podman

Форк
0
1457 строк · 28.7 Кб
1
// cmd/9l/noop.c, cmd/9l/pass.c, cmd/9l/span.c from Vita Nuova.
2
//
3
//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
4
//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
5
//	Portions Copyright © 1997-1999 Vita Nuova Limited
6
//	Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
7
//	Portions Copyright © 2004,2006 Bruce Ellis
8
//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
9
//	Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
10
//	Portions Copyright © 2009 The Go Authors. All rights reserved.
11
//
12
// Permission is hereby granted, free of charge, to any person obtaining a copy
13
// of this software and associated documentation files (the "Software"), to deal
14
// in the Software without restriction, including without limitation the rights
15
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
// copies of the Software, and to permit persons to whom the Software is
17
// furnished to do so, subject to the following conditions:
18
//
19
// The above copyright notice and this permission notice shall be included in
20
// all copies or substantial portions of the Software.
21
//
22
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
25
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28
// THE SOFTWARE.
29

30
package mips
31

32
import (
33
	"github.com/twitchyliquid64/golang-asm/obj"
34
	"github.com/twitchyliquid64/golang-asm/objabi"
35
	"github.com/twitchyliquid64/golang-asm/sys"
36
	"encoding/binary"
37
	"fmt"
38
	"math"
39
)
40

41
func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
42
	c := ctxt0{ctxt: ctxt, newprog: newprog}
43

44
	p.From.Class = 0
45
	p.To.Class = 0
46

47
	// Rewrite JMP/JAL to symbol as TYPE_BRANCH.
48
	switch p.As {
49
	case AJMP,
50
		AJAL,
51
		ARET,
52
		obj.ADUFFZERO,
53
		obj.ADUFFCOPY:
54
		if p.To.Sym != nil {
55
			p.To.Type = obj.TYPE_BRANCH
56
		}
57
	}
58

59
	// Rewrite float constants to values stored in memory.
60
	switch p.As {
61
	case AMOVF:
62
		if p.From.Type == obj.TYPE_FCONST {
63
			f32 := float32(p.From.Val.(float64))
64
			if math.Float32bits(f32) == 0 {
65
				p.As = AMOVW
66
				p.From.Type = obj.TYPE_REG
67
				p.From.Reg = REGZERO
68
				break
69
			}
70
			p.From.Type = obj.TYPE_MEM
71
			p.From.Sym = ctxt.Float32Sym(f32)
72
			p.From.Name = obj.NAME_EXTERN
73
			p.From.Offset = 0
74
		}
75

76
	case AMOVD:
77
		if p.From.Type == obj.TYPE_FCONST {
78
			f64 := p.From.Val.(float64)
79
			if math.Float64bits(f64) == 0 && c.ctxt.Arch.Family == sys.MIPS64 {
80
				p.As = AMOVV
81
				p.From.Type = obj.TYPE_REG
82
				p.From.Reg = REGZERO
83
				break
84
			}
85
			p.From.Type = obj.TYPE_MEM
86
			p.From.Sym = ctxt.Float64Sym(f64)
87
			p.From.Name = obj.NAME_EXTERN
88
			p.From.Offset = 0
89
		}
90

91
		// Put >32-bit constants in memory and load them
92
	case AMOVV:
93
		if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == 0 && int64(int32(p.From.Offset)) != p.From.Offset {
94
			p.From.Type = obj.TYPE_MEM
95
			p.From.Sym = ctxt.Int64Sym(p.From.Offset)
96
			p.From.Name = obj.NAME_EXTERN
97
			p.From.Offset = 0
98
		}
99
	}
100

101
	// Rewrite SUB constants into ADD.
102
	switch p.As {
103
	case ASUB:
104
		if p.From.Type == obj.TYPE_CONST {
105
			p.From.Offset = -p.From.Offset
106
			p.As = AADD
107
		}
108

109
	case ASUBU:
110
		if p.From.Type == obj.TYPE_CONST {
111
			p.From.Offset = -p.From.Offset
112
			p.As = AADDU
113
		}
114

115
	case ASUBV:
116
		if p.From.Type == obj.TYPE_CONST {
117
			p.From.Offset = -p.From.Offset
118
			p.As = AADDV
119
		}
120

121
	case ASUBVU:
122
		if p.From.Type == obj.TYPE_CONST {
123
			p.From.Offset = -p.From.Offset
124
			p.As = AADDVU
125
		}
126
	}
127
}
128

129
func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
130
	// TODO(minux): add morestack short-cuts with small fixed frame-size.
131
	c := ctxt0{ctxt: ctxt, newprog: newprog, cursym: cursym}
132

133
	// a switch for enabling/disabling instruction scheduling
134
	nosched := true
135

136
	if c.cursym.Func.Text == nil || c.cursym.Func.Text.Link == nil {
137
		return
138
	}
139

140
	p := c.cursym.Func.Text
141
	textstksiz := p.To.Offset
142
	if textstksiz == -ctxt.FixedFrameSize() {
143
		// Historical way to mark NOFRAME.
144
		p.From.Sym.Set(obj.AttrNoFrame, true)
145
		textstksiz = 0
146
	}
147
	if textstksiz < 0 {
148
		c.ctxt.Diag("negative frame size %d - did you mean NOFRAME?", textstksiz)
149
	}
150
	if p.From.Sym.NoFrame() {
151
		if textstksiz != 0 {
152
			c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
153
		}
154
	}
155

156
	c.cursym.Func.Args = p.To.Val.(int32)
157
	c.cursym.Func.Locals = int32(textstksiz)
158

159
	/*
160
	 * find leaf subroutines
161
	 * expand RET
162
	 * expand BECOME pseudo
163
	 */
164

165
	for p := c.cursym.Func.Text; p != nil; p = p.Link {
166
		switch p.As {
167
		/* too hard, just leave alone */
168
		case obj.ATEXT:
169
			p.Mark |= LABEL | LEAF | SYNC
170
			if p.Link != nil {
171
				p.Link.Mark |= LABEL
172
			}
173

174
		/* too hard, just leave alone */
175
		case AMOVW,
176
			AMOVV:
177
			if p.To.Type == obj.TYPE_REG && p.To.Reg >= REG_SPECIAL {
178
				p.Mark |= LABEL | SYNC
179
				break
180
			}
181
			if p.From.Type == obj.TYPE_REG && p.From.Reg >= REG_SPECIAL {
182
				p.Mark |= LABEL | SYNC
183
			}
184

185
		/* too hard, just leave alone */
186
		case ASYSCALL,
187
			AWORD,
188
			ATLBWR,
189
			ATLBWI,
190
			ATLBP,
191
			ATLBR:
192
			p.Mark |= LABEL | SYNC
193

194
		case ANOR:
195
			if p.To.Type == obj.TYPE_REG {
196
				if p.To.Reg == REGZERO {
197
					p.Mark |= LABEL | SYNC
198
				}
199
			}
200

201
		case ABGEZAL,
202
			ABLTZAL,
203
			AJAL,
204
			obj.ADUFFZERO,
205
			obj.ADUFFCOPY:
206
			c.cursym.Func.Text.Mark &^= LEAF
207
			fallthrough
208

209
		case AJMP,
210
			ABEQ,
211
			ABGEZ,
212
			ABGTZ,
213
			ABLEZ,
214
			ABLTZ,
215
			ABNE,
216
			ABFPT, ABFPF:
217
			if p.As == ABFPT || p.As == ABFPF {
218
				// We don't treat ABFPT and ABFPF as branches here,
219
				// so that we will always fill nop (0x0) in their
220
				// delay slot during assembly.
221
				// This is to workaround a kernel FPU emulator bug
222
				// where it uses the user stack to simulate the
223
				// instruction in the delay slot if it's not 0x0,
224
				// and somehow that leads to SIGSEGV when the kernel
225
				// jump to the stack.
226
				p.Mark |= SYNC
227
			} else {
228
				p.Mark |= BRANCH
229
			}
230
			q1 := p.To.Target()
231
			if q1 != nil {
232
				for q1.As == obj.ANOP {
233
					q1 = q1.Link
234
					p.To.SetTarget(q1)
235
				}
236

237
				if q1.Mark&LEAF == 0 {
238
					q1.Mark |= LABEL
239
				}
240
			}
241
			//else {
242
			//	p.Mark |= LABEL
243
			//}
244
			q1 = p.Link
245
			if q1 != nil {
246
				q1.Mark |= LABEL
247
			}
248

249
		case ARET:
250
			if p.Link != nil {
251
				p.Link.Mark |= LABEL
252
			}
253
		}
254
	}
255

256
	var mov, add obj.As
257
	if c.ctxt.Arch.Family == sys.MIPS64 {
258
		add = AADDV
259
		mov = AMOVV
260
	} else {
261
		add = AADDU
262
		mov = AMOVW
263
	}
264

265
	var q *obj.Prog
266
	var q1 *obj.Prog
267
	autosize := int32(0)
268
	var p1 *obj.Prog
269
	var p2 *obj.Prog
270
	for p := c.cursym.Func.Text; p != nil; p = p.Link {
271
		o := p.As
272
		switch o {
273
		case obj.ATEXT:
274
			autosize = int32(textstksiz)
275

276
			if p.Mark&LEAF != 0 && autosize == 0 {
277
				// A leaf function with no locals has no frame.
278
				p.From.Sym.Set(obj.AttrNoFrame, true)
279
			}
280

281
			if !p.From.Sym.NoFrame() {
282
				// If there is a stack frame at all, it includes
283
				// space to save the LR.
284
				autosize += int32(c.ctxt.FixedFrameSize())
285
			}
286

287
			if autosize&4 != 0 && c.ctxt.Arch.Family == sys.MIPS64 {
288
				autosize += 4
289
			}
290

291
			if autosize == 0 && c.cursym.Func.Text.Mark&LEAF == 0 {
292
				if c.cursym.Func.Text.From.Sym.NoSplit() {
293
					if ctxt.Debugvlog {
294
						ctxt.Logf("save suppressed in: %s\n", c.cursym.Name)
295
					}
296

297
					c.cursym.Func.Text.Mark |= LEAF
298
				}
299
			}
300

301
			p.To.Offset = int64(autosize) - ctxt.FixedFrameSize()
302

303
			if c.cursym.Func.Text.Mark&LEAF != 0 {
304
				c.cursym.Set(obj.AttrLeaf, true)
305
				if p.From.Sym.NoFrame() {
306
					break
307
				}
308
			}
309

310
			if !p.From.Sym.NoSplit() {
311
				p = c.stacksplit(p, autosize) // emit split check
312
			}
313

314
			q = p
315

316
			if autosize != 0 {
317
				// Make sure to save link register for non-empty frame, even if
318
				// it is a leaf function, so that traceback works.
319
				// Store link register before decrement SP, so if a signal comes
320
				// during the execution of the function prologue, the traceback
321
				// code will not see a half-updated stack frame.
322
				// This sequence is not async preemptible, as if we open a frame
323
				// at the current SP, it will clobber the saved LR.
324
				q = c.ctxt.StartUnsafePoint(q, c.newprog)
325

326
				q = obj.Appendp(q, newprog)
327
				q.As = mov
328
				q.Pos = p.Pos
329
				q.From.Type = obj.TYPE_REG
330
				q.From.Reg = REGLINK
331
				q.To.Type = obj.TYPE_MEM
332
				q.To.Offset = int64(-autosize)
333
				q.To.Reg = REGSP
334

335
				q = obj.Appendp(q, newprog)
336
				q.As = add
337
				q.Pos = p.Pos
338
				q.From.Type = obj.TYPE_CONST
339
				q.From.Offset = int64(-autosize)
340
				q.To.Type = obj.TYPE_REG
341
				q.To.Reg = REGSP
342
				q.Spadj = +autosize
343

344
				q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
345
			}
346

347
			if c.cursym.Func.Text.From.Sym.Wrapper() && c.cursym.Func.Text.Mark&LEAF == 0 {
348
				// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
349
				//
350
				//	MOV	g_panic(g), R1
351
				//	BEQ	R1, end
352
				//	MOV	panic_argp(R1), R2
353
				//	ADD	$(autosize+FIXED_FRAME), R29, R3
354
				//	BNE	R2, R3, end
355
				//	ADD	$FIXED_FRAME, R29, R2
356
				//	MOV	R2, panic_argp(R1)
357
				// end:
358
				//	NOP
359
				//
360
				// The NOP is needed to give the jumps somewhere to land.
361
				// It is a liblink NOP, not an mips NOP: it encodes to 0 instruction bytes.
362
				//
363
				// We don't generate this for leafs because that means the wrapped
364
				// function was inlined into the wrapper.
365

366
				q = obj.Appendp(q, newprog)
367

368
				q.As = mov
369
				q.From.Type = obj.TYPE_MEM
370
				q.From.Reg = REGG
371
				q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
372
				q.To.Type = obj.TYPE_REG
373
				q.To.Reg = REG_R1
374

375
				q = obj.Appendp(q, newprog)
376
				q.As = ABEQ
377
				q.From.Type = obj.TYPE_REG
378
				q.From.Reg = REG_R1
379
				q.To.Type = obj.TYPE_BRANCH
380
				q.Mark |= BRANCH
381
				p1 = q
382

383
				q = obj.Appendp(q, newprog)
384
				q.As = mov
385
				q.From.Type = obj.TYPE_MEM
386
				q.From.Reg = REG_R1
387
				q.From.Offset = 0 // Panic.argp
388
				q.To.Type = obj.TYPE_REG
389
				q.To.Reg = REG_R2
390

391
				q = obj.Appendp(q, newprog)
392
				q.As = add
393
				q.From.Type = obj.TYPE_CONST
394
				q.From.Offset = int64(autosize) + ctxt.FixedFrameSize()
395
				q.Reg = REGSP
396
				q.To.Type = obj.TYPE_REG
397
				q.To.Reg = REG_R3
398

399
				q = obj.Appendp(q, newprog)
400
				q.As = ABNE
401
				q.From.Type = obj.TYPE_REG
402
				q.From.Reg = REG_R2
403
				q.Reg = REG_R3
404
				q.To.Type = obj.TYPE_BRANCH
405
				q.Mark |= BRANCH
406
				p2 = q
407

408
				q = obj.Appendp(q, newprog)
409
				q.As = add
410
				q.From.Type = obj.TYPE_CONST
411
				q.From.Offset = ctxt.FixedFrameSize()
412
				q.Reg = REGSP
413
				q.To.Type = obj.TYPE_REG
414
				q.To.Reg = REG_R2
415

416
				q = obj.Appendp(q, newprog)
417
				q.As = mov
418
				q.From.Type = obj.TYPE_REG
419
				q.From.Reg = REG_R2
420
				q.To.Type = obj.TYPE_MEM
421
				q.To.Reg = REG_R1
422
				q.To.Offset = 0 // Panic.argp
423

424
				q = obj.Appendp(q, newprog)
425

426
				q.As = obj.ANOP
427
				p1.To.SetTarget(q)
428
				p2.To.SetTarget(q)
429
			}
430

431
		case ARET:
432
			if p.From.Type == obj.TYPE_CONST {
433
				ctxt.Diag("using BECOME (%v) is not supported!", p)
434
				break
435
			}
436

437
			retSym := p.To.Sym
438
			p.To.Name = obj.NAME_NONE // clear fields as we may modify p to other instruction
439
			p.To.Sym = nil
440

441
			if c.cursym.Func.Text.Mark&LEAF != 0 {
442
				if autosize == 0 {
443
					p.As = AJMP
444
					p.From = obj.Addr{}
445
					if retSym != nil { // retjmp
446
						p.To.Type = obj.TYPE_BRANCH
447
						p.To.Name = obj.NAME_EXTERN
448
						p.To.Sym = retSym
449
					} else {
450
						p.To.Type = obj.TYPE_MEM
451
						p.To.Reg = REGLINK
452
						p.To.Offset = 0
453
					}
454
					p.Mark |= BRANCH
455
					break
456
				}
457

458
				p.As = add
459
				p.From.Type = obj.TYPE_CONST
460
				p.From.Offset = int64(autosize)
461
				p.To.Type = obj.TYPE_REG
462
				p.To.Reg = REGSP
463
				p.Spadj = -autosize
464

465
				q = c.newprog()
466
				q.As = AJMP
467
				q.Pos = p.Pos
468
				q.To.Type = obj.TYPE_MEM
469
				q.To.Offset = 0
470
				q.To.Reg = REGLINK
471
				q.Mark |= BRANCH
472
				q.Spadj = +autosize
473

474
				q.Link = p.Link
475
				p.Link = q
476
				break
477
			}
478

479
			p.As = mov
480
			p.From.Type = obj.TYPE_MEM
481
			p.From.Offset = 0
482
			p.From.Reg = REGSP
483
			p.To.Type = obj.TYPE_REG
484
			p.To.Reg = REGLINK
485

486
			if autosize != 0 {
487
				q = c.newprog()
488
				q.As = add
489
				q.Pos = p.Pos
490
				q.From.Type = obj.TYPE_CONST
491
				q.From.Offset = int64(autosize)
492
				q.To.Type = obj.TYPE_REG
493
				q.To.Reg = REGSP
494
				q.Spadj = -autosize
495

496
				q.Link = p.Link
497
				p.Link = q
498
			}
499

500
			q1 = c.newprog()
501
			q1.As = AJMP
502
			q1.Pos = p.Pos
503
			if retSym != nil { // retjmp
504
				q1.To.Type = obj.TYPE_BRANCH
505
				q1.To.Name = obj.NAME_EXTERN
506
				q1.To.Sym = retSym
507
			} else {
508
				q1.To.Type = obj.TYPE_MEM
509
				q1.To.Offset = 0
510
				q1.To.Reg = REGLINK
511
			}
512
			q1.Mark |= BRANCH
513
			q1.Spadj = +autosize
514

515
			q1.Link = q.Link
516
			q.Link = q1
517

518
		case AADD,
519
			AADDU,
520
			AADDV,
521
			AADDVU:
522
			if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
523
				p.Spadj = int32(-p.From.Offset)
524
			}
525

526
		case obj.AGETCALLERPC:
527
			if cursym.Leaf() {
528
				/* MOV LR, Rd */
529
				p.As = mov
530
				p.From.Type = obj.TYPE_REG
531
				p.From.Reg = REGLINK
532
			} else {
533
				/* MOV (RSP), Rd */
534
				p.As = mov
535
				p.From.Type = obj.TYPE_MEM
536
				p.From.Reg = REGSP
537
			}
538
		}
539
	}
540

541
	if c.ctxt.Arch.Family == sys.MIPS {
542
		// rewrite MOVD into two MOVF in 32-bit mode to avoid unaligned memory access
543
		for p = c.cursym.Func.Text; p != nil; p = p1 {
544
			p1 = p.Link
545

546
			if p.As != AMOVD {
547
				continue
548
			}
549
			if p.From.Type != obj.TYPE_MEM && p.To.Type != obj.TYPE_MEM {
550
				continue
551
			}
552

553
			p.As = AMOVF
554
			q = c.newprog()
555
			*q = *p
556
			q.Link = p.Link
557
			p.Link = q
558
			p1 = q.Link
559

560
			var addrOff int64
561
			if c.ctxt.Arch.ByteOrder == binary.BigEndian {
562
				addrOff = 4 // swap load/save order
563
			}
564
			if p.From.Type == obj.TYPE_MEM {
565
				reg := REG_F0 + (p.To.Reg-REG_F0)&^1
566
				p.To.Reg = reg
567
				q.To.Reg = reg + 1
568
				p.From.Offset += addrOff
569
				q.From.Offset += 4 - addrOff
570
			} else if p.To.Type == obj.TYPE_MEM {
571
				reg := REG_F0 + (p.From.Reg-REG_F0)&^1
572
				p.From.Reg = reg
573
				q.From.Reg = reg + 1
574
				p.To.Offset += addrOff
575
				q.To.Offset += 4 - addrOff
576
			}
577
		}
578
	}
579

580
	if nosched {
581
		// if we don't do instruction scheduling, simply add
582
		// NOP after each branch instruction.
583
		for p = c.cursym.Func.Text; p != nil; p = p.Link {
584
			if p.Mark&BRANCH != 0 {
585
				c.addnop(p)
586
			}
587
		}
588
		return
589
	}
590

591
	// instruction scheduling
592
	q = nil                 // p - 1
593
	q1 = c.cursym.Func.Text // top of block
594
	o := 0                  // count of instructions
595
	for p = c.cursym.Func.Text; p != nil; p = p1 {
596
		p1 = p.Link
597
		o++
598
		if p.Mark&NOSCHED != 0 {
599
			if q1 != p {
600
				c.sched(q1, q)
601
			}
602
			for ; p != nil; p = p.Link {
603
				if p.Mark&NOSCHED == 0 {
604
					break
605
				}
606
				q = p
607
			}
608
			p1 = p
609
			q1 = p
610
			o = 0
611
			continue
612
		}
613
		if p.Mark&(LABEL|SYNC) != 0 {
614
			if q1 != p {
615
				c.sched(q1, q)
616
			}
617
			q1 = p
618
			o = 1
619
		}
620
		if p.Mark&(BRANCH|SYNC) != 0 {
621
			c.sched(q1, p)
622
			q1 = p1
623
			o = 0
624
		}
625
		if o >= NSCHED {
626
			c.sched(q1, p)
627
			q1 = p1
628
			o = 0
629
		}
630
		q = p
631
	}
632
}
633

634
func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
635
	var mov, add, sub obj.As
636

637
	if c.ctxt.Arch.Family == sys.MIPS64 {
638
		add = AADDV
639
		mov = AMOVV
640
		sub = ASUBVU
641
	} else {
642
		add = AADDU
643
		mov = AMOVW
644
		sub = ASUBU
645
	}
646

647
	// MOV	g_stackguard(g), R1
648
	p = obj.Appendp(p, c.newprog)
649

650
	p.As = mov
651
	p.From.Type = obj.TYPE_MEM
652
	p.From.Reg = REGG
653
	p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
654
	if c.cursym.CFunc() {
655
		p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
656
	}
657
	p.To.Type = obj.TYPE_REG
658
	p.To.Reg = REG_R1
659

660
	// Mark the stack bound check and morestack call async nonpreemptible.
661
	// If we get preempted here, when resumed the preemption request is
662
	// cleared, but we'll still call morestack, which will double the stack
663
	// unnecessarily. See issue #35470.
664
	p = c.ctxt.StartUnsafePoint(p, c.newprog)
665

666
	var q *obj.Prog
667
	if framesize <= objabi.StackSmall {
668
		// small stack: SP < stackguard
669
		//	AGTU	SP, stackguard, R1
670
		p = obj.Appendp(p, c.newprog)
671

672
		p.As = ASGTU
673
		p.From.Type = obj.TYPE_REG
674
		p.From.Reg = REGSP
675
		p.Reg = REG_R1
676
		p.To.Type = obj.TYPE_REG
677
		p.To.Reg = REG_R1
678
	} else if framesize <= objabi.StackBig {
679
		// large stack: SP-framesize < stackguard-StackSmall
680
		//	ADD	$-(framesize-StackSmall), SP, R2
681
		//	SGTU	R2, stackguard, R1
682
		p = obj.Appendp(p, c.newprog)
683

684
		p.As = add
685
		p.From.Type = obj.TYPE_CONST
686
		p.From.Offset = -(int64(framesize) - objabi.StackSmall)
687
		p.Reg = REGSP
688
		p.To.Type = obj.TYPE_REG
689
		p.To.Reg = REG_R2
690

691
		p = obj.Appendp(p, c.newprog)
692
		p.As = ASGTU
693
		p.From.Type = obj.TYPE_REG
694
		p.From.Reg = REG_R2
695
		p.Reg = REG_R1
696
		p.To.Type = obj.TYPE_REG
697
		p.To.Reg = REG_R1
698
	} else {
699
		// Such a large stack we need to protect against wraparound.
700
		// If SP is close to zero:
701
		//	SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
702
		// The +StackGuard on both sides is required to keep the left side positive:
703
		// SP is allowed to be slightly below stackguard. See stack.h.
704
		//
705
		// Preemption sets stackguard to StackPreempt, a very large value.
706
		// That breaks the math above, so we have to check for that explicitly.
707
		//	// stackguard is R1
708
		//	MOV	$StackPreempt, R2
709
		//	BEQ	R1, R2, label-of-call-to-morestack
710
		//	ADD	$StackGuard, SP, R2
711
		//	SUB	R1, R2
712
		//	MOV	$(framesize+(StackGuard-StackSmall)), R1
713
		//	SGTU	R2, R1, R1
714
		p = obj.Appendp(p, c.newprog)
715

716
		p.As = mov
717
		p.From.Type = obj.TYPE_CONST
718
		p.From.Offset = objabi.StackPreempt
719
		p.To.Type = obj.TYPE_REG
720
		p.To.Reg = REG_R2
721

722
		p = obj.Appendp(p, c.newprog)
723
		q = p
724
		p.As = ABEQ
725
		p.From.Type = obj.TYPE_REG
726
		p.From.Reg = REG_R1
727
		p.Reg = REG_R2
728
		p.To.Type = obj.TYPE_BRANCH
729
		p.Mark |= BRANCH
730

731
		p = obj.Appendp(p, c.newprog)
732
		p.As = add
733
		p.From.Type = obj.TYPE_CONST
734
		p.From.Offset = int64(objabi.StackGuard)
735
		p.Reg = REGSP
736
		p.To.Type = obj.TYPE_REG
737
		p.To.Reg = REG_R2
738

739
		p = obj.Appendp(p, c.newprog)
740
		p.As = sub
741
		p.From.Type = obj.TYPE_REG
742
		p.From.Reg = REG_R1
743
		p.To.Type = obj.TYPE_REG
744
		p.To.Reg = REG_R2
745

746
		p = obj.Appendp(p, c.newprog)
747
		p.As = mov
748
		p.From.Type = obj.TYPE_CONST
749
		p.From.Offset = int64(framesize) + int64(objabi.StackGuard) - objabi.StackSmall
750
		p.To.Type = obj.TYPE_REG
751
		p.To.Reg = REG_R1
752

753
		p = obj.Appendp(p, c.newprog)
754
		p.As = ASGTU
755
		p.From.Type = obj.TYPE_REG
756
		p.From.Reg = REG_R2
757
		p.Reg = REG_R1
758
		p.To.Type = obj.TYPE_REG
759
		p.To.Reg = REG_R1
760
	}
761

762
	// q1: BNE	R1, done
763
	p = obj.Appendp(p, c.newprog)
764
	q1 := p
765

766
	p.As = ABNE
767
	p.From.Type = obj.TYPE_REG
768
	p.From.Reg = REG_R1
769
	p.To.Type = obj.TYPE_BRANCH
770
	p.Mark |= BRANCH
771

772
	// MOV	LINK, R3
773
	p = obj.Appendp(p, c.newprog)
774

775
	p.As = mov
776
	p.From.Type = obj.TYPE_REG
777
	p.From.Reg = REGLINK
778
	p.To.Type = obj.TYPE_REG
779
	p.To.Reg = REG_R3
780
	if q != nil {
781
		q.To.SetTarget(p)
782
		p.Mark |= LABEL
783
	}
784

785
	p = c.ctxt.EmitEntryStackMap(c.cursym, p, c.newprog)
786

787
	// JAL	runtime.morestack(SB)
788
	p = obj.Appendp(p, c.newprog)
789

790
	p.As = AJAL
791
	p.To.Type = obj.TYPE_BRANCH
792
	if c.cursym.CFunc() {
793
		p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
794
	} else if !c.cursym.Func.Text.From.Sym.NeedCtxt() {
795
		p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
796
	} else {
797
		p.To.Sym = c.ctxt.Lookup("runtime.morestack")
798
	}
799
	p.Mark |= BRANCH
800

801
	p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
802

803
	// JMP	start
804
	p = obj.Appendp(p, c.newprog)
805

806
	p.As = AJMP
807
	p.To.Type = obj.TYPE_BRANCH
808
	p.To.SetTarget(c.cursym.Func.Text.Link)
809
	p.Mark |= BRANCH
810

811
	// placeholder for q1's jump target
812
	p = obj.Appendp(p, c.newprog)
813

814
	p.As = obj.ANOP // zero-width place holder
815
	q1.To.SetTarget(p)
816

817
	return p
818
}
819

820
func (c *ctxt0) addnop(p *obj.Prog) {
821
	q := c.newprog()
822
	q.As = ANOOP
823
	q.Pos = p.Pos
824
	q.Link = p.Link
825
	p.Link = q
826
}
827

828
const (
829
	E_HILO  = 1 << 0
830
	E_FCR   = 1 << 1
831
	E_MCR   = 1 << 2
832
	E_MEM   = 1 << 3
833
	E_MEMSP = 1 << 4 /* uses offset and size */
834
	E_MEMSB = 1 << 5 /* uses offset and size */
835
	ANYMEM  = E_MEM | E_MEMSP | E_MEMSB
836
	//DELAY = LOAD|BRANCH|FCMP
837
	DELAY = BRANCH /* only schedule branch */
838
)
839

840
type Dep struct {
841
	ireg uint32
842
	freg uint32
843
	cc   uint32
844
}
845

846
type Sch struct {
847
	p       obj.Prog
848
	set     Dep
849
	used    Dep
850
	soffset int32
851
	size    uint8
852
	nop     uint8
853
	comp    bool
854
}
855

856
func (c *ctxt0) sched(p0, pe *obj.Prog) {
857
	var sch [NSCHED]Sch
858

859
	/*
860
	 * build side structure
861
	 */
862
	s := sch[:]
863
	for p := p0; ; p = p.Link {
864
		s[0].p = *p
865
		c.markregused(&s[0])
866
		if p == pe {
867
			break
868
		}
869
		s = s[1:]
870
	}
871
	se := s
872

873
	for i := cap(sch) - cap(se); i >= 0; i-- {
874
		s = sch[i:]
875
		if s[0].p.Mark&DELAY == 0 {
876
			continue
877
		}
878
		if -cap(s) < -cap(se) {
879
			if !conflict(&s[0], &s[1]) {
880
				continue
881
			}
882
		}
883

884
		var t []Sch
885
		var j int
886
		for j = cap(sch) - cap(s) - 1; j >= 0; j-- {
887
			t = sch[j:]
888
			if t[0].comp {
889
				if s[0].p.Mark&BRANCH != 0 {
890
					continue
891
				}
892
			}
893
			if t[0].p.Mark&DELAY != 0 {
894
				if -cap(s) >= -cap(se) || conflict(&t[0], &s[1]) {
895
					continue
896
				}
897
			}
898
			for u := t[1:]; -cap(u) <= -cap(s); u = u[1:] {
899
				if c.depend(&u[0], &t[0]) {
900
					continue
901
				}
902
			}
903
			goto out2
904
		}
905

906
		if s[0].p.Mark&BRANCH != 0 {
907
			s[0].nop = 1
908
		}
909
		continue
910

911
	out2:
912
		// t[0] is the instruction being moved to fill the delay
913
		stmp := t[0]
914
		copy(t[:i-j], t[1:i-j+1])
915
		s[0] = stmp
916

917
		if t[i-j-1].p.Mark&BRANCH != 0 {
918
			// t[i-j] is being put into a branch delay slot
919
			// combine its Spadj with the branch instruction
920
			t[i-j-1].p.Spadj += t[i-j].p.Spadj
921
			t[i-j].p.Spadj = 0
922
		}
923

924
		i--
925
	}
926

927
	/*
928
	 * put it all back
929
	 */
930
	var p *obj.Prog
931
	var q *obj.Prog
932
	for s, p = sch[:], p0; -cap(s) <= -cap(se); s, p = s[1:], q {
933
		q = p.Link
934
		if q != s[0].p.Link {
935
			*p = s[0].p
936
			p.Link = q
937
		}
938
		for s[0].nop != 0 {
939
			s[0].nop--
940
			c.addnop(p)
941
		}
942
	}
943
}
944

945
func (c *ctxt0) markregused(s *Sch) {
946
	p := &s.p
947
	s.comp = c.compound(p)
948
	s.nop = 0
949
	if s.comp {
950
		s.set.ireg |= 1 << (REGTMP - REG_R0)
951
		s.used.ireg |= 1 << (REGTMP - REG_R0)
952
	}
953

954
	ar := 0  /* dest is really reference */
955
	ad := 0  /* source/dest is really address */
956
	ld := 0  /* opcode is load instruction */
957
	sz := 20 /* size of load/store for overlap computation */
958

959
	/*
960
	 * flags based on opcode
961
	 */
962
	switch p.As {
963
	case obj.ATEXT:
964
		c.autosize = int32(p.To.Offset + 8)
965
		ad = 1
966

967
	case AJAL:
968
		r := p.Reg
969
		if r == 0 {
970
			r = REGLINK
971
		}
972
		s.set.ireg |= 1 << uint(r-REG_R0)
973
		ar = 1
974
		ad = 1
975

976
	case ABGEZAL,
977
		ABLTZAL:
978
		s.set.ireg |= 1 << (REGLINK - REG_R0)
979
		fallthrough
980
	case ABEQ,
981
		ABGEZ,
982
		ABGTZ,
983
		ABLEZ,
984
		ABLTZ,
985
		ABNE:
986
		ar = 1
987
		ad = 1
988

989
	case ABFPT,
990
		ABFPF:
991
		ad = 1
992
		s.used.cc |= E_FCR
993

994
	case ACMPEQD,
995
		ACMPEQF,
996
		ACMPGED,
997
		ACMPGEF,
998
		ACMPGTD,
999
		ACMPGTF:
1000
		ar = 1
1001
		s.set.cc |= E_FCR
1002
		p.Mark |= FCMP
1003

1004
	case AJMP:
1005
		ar = 1
1006
		ad = 1
1007

1008
	case AMOVB,
1009
		AMOVBU:
1010
		sz = 1
1011
		ld = 1
1012

1013
	case AMOVH,
1014
		AMOVHU:
1015
		sz = 2
1016
		ld = 1
1017

1018
	case AMOVF,
1019
		AMOVW,
1020
		AMOVWL,
1021
		AMOVWR:
1022
		sz = 4
1023
		ld = 1
1024

1025
	case AMOVD,
1026
		AMOVV,
1027
		AMOVVL,
1028
		AMOVVR:
1029
		sz = 8
1030
		ld = 1
1031

1032
	case ADIV,
1033
		ADIVU,
1034
		AMUL,
1035
		AMULU,
1036
		AREM,
1037
		AREMU,
1038
		ADIVV,
1039
		ADIVVU,
1040
		AMULV,
1041
		AMULVU,
1042
		AREMV,
1043
		AREMVU:
1044
		s.set.cc = E_HILO
1045
		fallthrough
1046
	case AADD,
1047
		AADDU,
1048
		AADDV,
1049
		AADDVU,
1050
		AAND,
1051
		ANOR,
1052
		AOR,
1053
		ASGT,
1054
		ASGTU,
1055
		ASLL,
1056
		ASRA,
1057
		ASRL,
1058
		ASLLV,
1059
		ASRAV,
1060
		ASRLV,
1061
		ASUB,
1062
		ASUBU,
1063
		ASUBV,
1064
		ASUBVU,
1065
		AXOR,
1066

1067
		AADDD,
1068
		AADDF,
1069
		AADDW,
1070
		ASUBD,
1071
		ASUBF,
1072
		ASUBW,
1073
		AMULF,
1074
		AMULD,
1075
		AMULW,
1076
		ADIVF,
1077
		ADIVD,
1078
		ADIVW:
1079
		if p.Reg == 0 {
1080
			if p.To.Type == obj.TYPE_REG {
1081
				p.Reg = p.To.Reg
1082
			}
1083
			//if(p->reg == NREG)
1084
			//	print("botch %P\n", p);
1085
		}
1086
	}
1087

1088
	/*
1089
	 * flags based on 'to' field
1090
	 */
1091
	cls := int(p.To.Class)
1092
	if cls == 0 {
1093
		cls = c.aclass(&p.To) + 1
1094
		p.To.Class = int8(cls)
1095
	}
1096
	cls--
1097
	switch cls {
1098
	default:
1099
		fmt.Printf("unknown class %d %v\n", cls, p)
1100

1101
	case C_ZCON,
1102
		C_SCON,
1103
		C_ADD0CON,
1104
		C_AND0CON,
1105
		C_ADDCON,
1106
		C_ANDCON,
1107
		C_UCON,
1108
		C_LCON,
1109
		C_NONE,
1110
		C_SBRA,
1111
		C_LBRA,
1112
		C_ADDR,
1113
		C_TEXTSIZE:
1114
		break
1115

1116
	case C_HI,
1117
		C_LO:
1118
		s.set.cc |= E_HILO
1119

1120
	case C_FCREG:
1121
		s.set.cc |= E_FCR
1122

1123
	case C_MREG:
1124
		s.set.cc |= E_MCR
1125

1126
	case C_ZOREG,
1127
		C_SOREG,
1128
		C_LOREG:
1129
		cls = int(p.To.Reg)
1130
		s.used.ireg |= 1 << uint(cls-REG_R0)
1131
		if ad != 0 {
1132
			break
1133
		}
1134
		s.size = uint8(sz)
1135
		s.soffset = c.regoff(&p.To)
1136

1137
		m := uint32(ANYMEM)
1138
		if cls == REGSB {
1139
			m = E_MEMSB
1140
		}
1141
		if cls == REGSP {
1142
			m = E_MEMSP
1143
		}
1144

1145
		if ar != 0 {
1146
			s.used.cc |= m
1147
		} else {
1148
			s.set.cc |= m
1149
		}
1150

1151
	case C_SACON,
1152
		C_LACON:
1153
		s.used.ireg |= 1 << (REGSP - REG_R0)
1154

1155
	case C_SECON,
1156
		C_LECON:
1157
		s.used.ireg |= 1 << (REGSB - REG_R0)
1158

1159
	case C_REG:
1160
		if ar != 0 {
1161
			s.used.ireg |= 1 << uint(p.To.Reg-REG_R0)
1162
		} else {
1163
			s.set.ireg |= 1 << uint(p.To.Reg-REG_R0)
1164
		}
1165

1166
	case C_FREG:
1167
		if ar != 0 {
1168
			s.used.freg |= 1 << uint(p.To.Reg-REG_F0)
1169
		} else {
1170
			s.set.freg |= 1 << uint(p.To.Reg-REG_F0)
1171
		}
1172
		if ld != 0 && p.From.Type == obj.TYPE_REG {
1173
			p.Mark |= LOAD
1174
		}
1175

1176
	case C_SAUTO,
1177
		C_LAUTO:
1178
		s.used.ireg |= 1 << (REGSP - REG_R0)
1179
		if ad != 0 {
1180
			break
1181
		}
1182
		s.size = uint8(sz)
1183
		s.soffset = c.regoff(&p.To)
1184

1185
		if ar != 0 {
1186
			s.used.cc |= E_MEMSP
1187
		} else {
1188
			s.set.cc |= E_MEMSP
1189
		}
1190

1191
	case C_SEXT,
1192
		C_LEXT:
1193
		s.used.ireg |= 1 << (REGSB - REG_R0)
1194
		if ad != 0 {
1195
			break
1196
		}
1197
		s.size = uint8(sz)
1198
		s.soffset = c.regoff(&p.To)
1199

1200
		if ar != 0 {
1201
			s.used.cc |= E_MEMSB
1202
		} else {
1203
			s.set.cc |= E_MEMSB
1204
		}
1205
	}
1206

1207
	/*
1208
	 * flags based on 'from' field
1209
	 */
1210
	cls = int(p.From.Class)
1211
	if cls == 0 {
1212
		cls = c.aclass(&p.From) + 1
1213
		p.From.Class = int8(cls)
1214
	}
1215
	cls--
1216
	switch cls {
1217
	default:
1218
		fmt.Printf("unknown class %d %v\n", cls, p)
1219

1220
	case C_ZCON,
1221
		C_SCON,
1222
		C_ADD0CON,
1223
		C_AND0CON,
1224
		C_ADDCON,
1225
		C_ANDCON,
1226
		C_UCON,
1227
		C_LCON,
1228
		C_NONE,
1229
		C_SBRA,
1230
		C_LBRA,
1231
		C_ADDR,
1232
		C_TEXTSIZE:
1233
		break
1234

1235
	case C_HI,
1236
		C_LO:
1237
		s.used.cc |= E_HILO
1238

1239
	case C_FCREG:
1240
		s.used.cc |= E_FCR
1241

1242
	case C_MREG:
1243
		s.used.cc |= E_MCR
1244

1245
	case C_ZOREG,
1246
		C_SOREG,
1247
		C_LOREG:
1248
		cls = int(p.From.Reg)
1249
		s.used.ireg |= 1 << uint(cls-REG_R0)
1250
		if ld != 0 {
1251
			p.Mark |= LOAD
1252
		}
1253
		s.size = uint8(sz)
1254
		s.soffset = c.regoff(&p.From)
1255

1256
		m := uint32(ANYMEM)
1257
		if cls == REGSB {
1258
			m = E_MEMSB
1259
		}
1260
		if cls == REGSP {
1261
			m = E_MEMSP
1262
		}
1263

1264
		s.used.cc |= m
1265

1266
	case C_SACON,
1267
		C_LACON:
1268
		cls = int(p.From.Reg)
1269
		if cls == 0 {
1270
			cls = REGSP
1271
		}
1272
		s.used.ireg |= 1 << uint(cls-REG_R0)
1273

1274
	case C_SECON,
1275
		C_LECON:
1276
		s.used.ireg |= 1 << (REGSB - REG_R0)
1277

1278
	case C_REG:
1279
		s.used.ireg |= 1 << uint(p.From.Reg-REG_R0)
1280

1281
	case C_FREG:
1282
		s.used.freg |= 1 << uint(p.From.Reg-REG_F0)
1283
		if ld != 0 && p.To.Type == obj.TYPE_REG {
1284
			p.Mark |= LOAD
1285
		}
1286

1287
	case C_SAUTO,
1288
		C_LAUTO:
1289
		s.used.ireg |= 1 << (REGSP - REG_R0)
1290
		if ld != 0 {
1291
			p.Mark |= LOAD
1292
		}
1293
		if ad != 0 {
1294
			break
1295
		}
1296
		s.size = uint8(sz)
1297
		s.soffset = c.regoff(&p.From)
1298

1299
		s.used.cc |= E_MEMSP
1300

1301
	case C_SEXT:
1302
	case C_LEXT:
1303
		s.used.ireg |= 1 << (REGSB - REG_R0)
1304
		if ld != 0 {
1305
			p.Mark |= LOAD
1306
		}
1307
		if ad != 0 {
1308
			break
1309
		}
1310
		s.size = uint8(sz)
1311
		s.soffset = c.regoff(&p.From)
1312

1313
		s.used.cc |= E_MEMSB
1314
	}
1315

1316
	cls = int(p.Reg)
1317
	if cls != 0 {
1318
		if REG_F0 <= cls && cls <= REG_F31 {
1319
			s.used.freg |= 1 << uint(cls-REG_F0)
1320
		} else {
1321
			s.used.ireg |= 1 << uint(cls-REG_R0)
1322
		}
1323
	}
1324
	s.set.ireg &^= (1 << (REGZERO - REG_R0)) /* R0 can't be set */
1325
}
1326

1327
/*
1328
 * test to see if two instructions can be
1329
 * interchanged without changing semantics
1330
 */
1331
func (c *ctxt0) depend(sa, sb *Sch) bool {
1332
	if sa.set.ireg&(sb.set.ireg|sb.used.ireg) != 0 {
1333
		return true
1334
	}
1335
	if sb.set.ireg&sa.used.ireg != 0 {
1336
		return true
1337
	}
1338

1339
	if sa.set.freg&(sb.set.freg|sb.used.freg) != 0 {
1340
		return true
1341
	}
1342
	if sb.set.freg&sa.used.freg != 0 {
1343
		return true
1344
	}
1345

1346
	/*
1347
	 * special case.
1348
	 * loads from same address cannot pass.
1349
	 * this is for hardware fifo's and the like
1350
	 */
1351
	if sa.used.cc&sb.used.cc&E_MEM != 0 {
1352
		if sa.p.Reg == sb.p.Reg {
1353
			if c.regoff(&sa.p.From) == c.regoff(&sb.p.From) {
1354
				return true
1355
			}
1356
		}
1357
	}
1358

1359
	x := (sa.set.cc & (sb.set.cc | sb.used.cc)) | (sb.set.cc & sa.used.cc)
1360
	if x != 0 {
1361
		/*
1362
		 * allow SB and SP to pass each other.
1363
		 * allow SB to pass SB iff doffsets are ok
1364
		 * anything else conflicts
1365
		 */
1366
		if x != E_MEMSP && x != E_MEMSB {
1367
			return true
1368
		}
1369
		x = sa.set.cc | sb.set.cc | sa.used.cc | sb.used.cc
1370
		if x&E_MEM != 0 {
1371
			return true
1372
		}
1373
		if offoverlap(sa, sb) {
1374
			return true
1375
		}
1376
	}
1377

1378
	return false
1379
}
1380

1381
func offoverlap(sa, sb *Sch) bool {
1382
	if sa.soffset < sb.soffset {
1383
		if sa.soffset+int32(sa.size) > sb.soffset {
1384
			return true
1385
		}
1386
		return false
1387
	}
1388
	if sb.soffset+int32(sb.size) > sa.soffset {
1389
		return true
1390
	}
1391
	return false
1392
}
1393

1394
/*
1395
 * test 2 adjacent instructions
1396
 * and find out if inserted instructions
1397
 * are desired to prevent stalls.
1398
 */
1399
func conflict(sa, sb *Sch) bool {
1400
	if sa.set.ireg&sb.used.ireg != 0 {
1401
		return true
1402
	}
1403
	if sa.set.freg&sb.used.freg != 0 {
1404
		return true
1405
	}
1406
	if sa.set.cc&sb.used.cc != 0 {
1407
		return true
1408
	}
1409
	return false
1410
}
1411

1412
func (c *ctxt0) compound(p *obj.Prog) bool {
1413
	o := c.oplook(p)
1414
	if o.size != 4 {
1415
		return true
1416
	}
1417
	if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSB {
1418
		return true
1419
	}
1420
	return false
1421
}
1422

1423
var Linkmips64 = obj.LinkArch{
1424
	Arch:           sys.ArchMIPS64,
1425
	Init:           buildop,
1426
	Preprocess:     preprocess,
1427
	Assemble:       span0,
1428
	Progedit:       progedit,
1429
	DWARFRegisters: MIPSDWARFRegisters,
1430
}
1431

1432
var Linkmips64le = obj.LinkArch{
1433
	Arch:           sys.ArchMIPS64LE,
1434
	Init:           buildop,
1435
	Preprocess:     preprocess,
1436
	Assemble:       span0,
1437
	Progedit:       progedit,
1438
	DWARFRegisters: MIPSDWARFRegisters,
1439
}
1440

1441
var Linkmips = obj.LinkArch{
1442
	Arch:           sys.ArchMIPS,
1443
	Init:           buildop,
1444
	Preprocess:     preprocess,
1445
	Assemble:       span0,
1446
	Progedit:       progedit,
1447
	DWARFRegisters: MIPSDWARFRegisters,
1448
}
1449

1450
var Linkmipsle = obj.LinkArch{
1451
	Arch:           sys.ArchMIPSLE,
1452
	Init:           buildop,
1453
	Preprocess:     preprocess,
1454
	Assemble:       span0,
1455
	Progedit:       progedit,
1456
	DWARFRegisters: MIPSDWARFRegisters,
1457
}
1458

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.