Home | History | Annotate | Download | only in mips
      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 (a] 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 (a] 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 	"cmd/internal/obj"
     34 	"cmd/internal/objabi"
     35 	"cmd/internal/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 
    143 	c.cursym.Func.Args = p.To.Val.(int32)
    144 	c.cursym.Func.Locals = int32(textstksiz)
    145 
    146 	/*
    147 	 * find leaf subroutines
    148 	 * strip NOPs
    149 	 * expand RET
    150 	 * expand BECOME pseudo
    151 	 */
    152 
    153 	var q *obj.Prog
    154 	var q1 *obj.Prog
    155 	for p := c.cursym.Func.Text; p != nil; p = p.Link {
    156 		switch p.As {
    157 		/* too hard, just leave alone */
    158 		case obj.ATEXT:
    159 			q = p
    160 
    161 			p.Mark |= LABEL | LEAF | SYNC
    162 			if p.Link != nil {
    163 				p.Link.Mark |= LABEL
    164 			}
    165 
    166 		/* too hard, just leave alone */
    167 		case AMOVW,
    168 			AMOVV:
    169 			q = p
    170 			if p.To.Type == obj.TYPE_REG && p.To.Reg >= REG_SPECIAL {
    171 				p.Mark |= LABEL | SYNC
    172 				break
    173 			}
    174 			if p.From.Type == obj.TYPE_REG && p.From.Reg >= REG_SPECIAL {
    175 				p.Mark |= LABEL | SYNC
    176 			}
    177 
    178 		/* too hard, just leave alone */
    179 		case ASYSCALL,
    180 			AWORD,
    181 			ATLBWR,
    182 			ATLBWI,
    183 			ATLBP,
    184 			ATLBR:
    185 			q = p
    186 			p.Mark |= LABEL | SYNC
    187 
    188 		case ANOR:
    189 			q = p
    190 			if p.To.Type == obj.TYPE_REG {
    191 				if p.To.Reg == REGZERO {
    192 					p.Mark |= LABEL | SYNC
    193 				}
    194 			}
    195 
    196 		case ABGEZAL,
    197 			ABLTZAL,
    198 			AJAL,
    199 			obj.ADUFFZERO,
    200 			obj.ADUFFCOPY:
    201 			c.cursym.Func.Text.Mark &^= LEAF
    202 			fallthrough
    203 
    204 		case AJMP,
    205 			ABEQ,
    206 			ABGEZ,
    207 			ABGTZ,
    208 			ABLEZ,
    209 			ABLTZ,
    210 			ABNE,
    211 			ABFPT, ABFPF:
    212 			if p.As == ABFPT || p.As == ABFPF {
    213 				// We don't treat ABFPT and ABFPF as branches here,
    214 				// so that we will always fill nop (0x0) in their
    215 				// delay slot during assembly.
    216 				// This is to workaround a kernel FPU emulator bug
    217 				// where it uses the user stack to simulate the
    218 				// instruction in the delay slot if it's not 0x0,
    219 				// and somehow that leads to SIGSEGV when the kernel
    220 				// jump to the stack.
    221 				p.Mark |= SYNC
    222 			} else {
    223 				p.Mark |= BRANCH
    224 			}
    225 			q = p
    226 			q1 = p.Pcond
    227 			if q1 != nil {
    228 				for q1.As == obj.ANOP {
    229 					q1 = q1.Link
    230 					p.Pcond = q1
    231 				}
    232 
    233 				if q1.Mark&LEAF == 0 {
    234 					q1.Mark |= LABEL
    235 				}
    236 			}
    237 			//else {
    238 			//	p.Mark |= LABEL
    239 			//}
    240 			q1 = p.Link
    241 			if q1 != nil {
    242 				q1.Mark |= LABEL
    243 			}
    244 			continue
    245 
    246 		case ARET:
    247 			q = p
    248 			if p.Link != nil {
    249 				p.Link.Mark |= LABEL
    250 			}
    251 			continue
    252 
    253 		case obj.ANOP:
    254 			q1 = p.Link
    255 			q.Link = q1 /* q is non-nop */
    256 			q1.Mark |= p.Mark
    257 			continue
    258 
    259 		default:
    260 			q = p
    261 			continue
    262 		}
    263 	}
    264 
    265 	var mov, add obj.As
    266 	if c.ctxt.Arch.Family == sys.MIPS64 {
    267 		add = AADDV
    268 		mov = AMOVV
    269 	} else {
    270 		add = AADDU
    271 		mov = AMOVW
    272 	}
    273 
    274 	autosize := int32(0)
    275 	var p1 *obj.Prog
    276 	var p2 *obj.Prog
    277 	for p := c.cursym.Func.Text; p != nil; p = p.Link {
    278 		o := p.As
    279 		switch o {
    280 		case obj.ATEXT:
    281 			autosize = int32(textstksiz + ctxt.FixedFrameSize())
    282 			if (p.Mark&LEAF != 0) && autosize <= int32(ctxt.FixedFrameSize()) {
    283 				autosize = 0
    284 			} else if autosize&4 != 0 && c.ctxt.Arch.Family == sys.MIPS64 {
    285 				autosize += 4
    286 			}
    287 
    288 			p.To.Offset = int64(autosize) - ctxt.FixedFrameSize()
    289 
    290 			if !p.From.Sym.NoSplit() {
    291 				p = c.stacksplit(p, autosize) // emit split check
    292 			}
    293 
    294 			q = p
    295 
    296 			if autosize != 0 {
    297 				// Make sure to save link register for non-empty frame, even if
    298 				// it is a leaf function, so that traceback works.
    299 				// Store link register before decrement SP, so if a signal comes
    300 				// during the execution of the function prologue, the traceback
    301 				// code will not see a half-updated stack frame.
    302 				q = obj.Appendp(q, newprog)
    303 				q.As = mov
    304 				q.Pos = p.Pos
    305 				q.From.Type = obj.TYPE_REG
    306 				q.From.Reg = REGLINK
    307 				q.To.Type = obj.TYPE_MEM
    308 				q.To.Offset = int64(-autosize)
    309 				q.To.Reg = REGSP
    310 
    311 				q = obj.Appendp(q, newprog)
    312 				q.As = add
    313 				q.Pos = p.Pos
    314 				q.From.Type = obj.TYPE_CONST
    315 				q.From.Offset = int64(-autosize)
    316 				q.To.Type = obj.TYPE_REG
    317 				q.To.Reg = REGSP
    318 				q.Spadj = +autosize
    319 			} else if c.cursym.Func.Text.Mark&LEAF == 0 {
    320 				if c.cursym.Func.Text.From.Sym.NoSplit() {
    321 					if ctxt.Debugvlog {
    322 						ctxt.Logf("save suppressed in: %s\n", c.cursym.Name)
    323 					}
    324 
    325 					c.cursym.Func.Text.Mark |= LEAF
    326 				}
    327 			}
    328 
    329 			if c.cursym.Func.Text.Mark&LEAF != 0 {
    330 				c.cursym.Set(obj.AttrLeaf, true)
    331 				break
    332 			}
    333 
    334 			if c.cursym.Func.Text.From.Sym.Wrapper() {
    335 				// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
    336 				//
    337 				//	MOV	g_panic(g), R1
    338 				//	BEQ	R1, end
    339 				//	MOV	panic_argp(R1), R2
    340 				//	ADD	$(autosize+FIXED_FRAME), R29, R3
    341 				//	BNE	R2, R3, end
    342 				//	ADD	$FIXED_FRAME, R29, R2
    343 				//	MOV	R2, panic_argp(R1)
    344 				// end:
    345 				//	NOP
    346 				//
    347 				// The NOP is needed to give the jumps somewhere to land.
    348 				// It is a liblink NOP, not an mips NOP: it encodes to 0 instruction bytes.
    349 
    350 				q = obj.Appendp(q, newprog)
    351 
    352 				q.As = mov
    353 				q.From.Type = obj.TYPE_MEM
    354 				q.From.Reg = REGG
    355 				q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
    356 				q.To.Type = obj.TYPE_REG
    357 				q.To.Reg = REG_R1
    358 
    359 				q = obj.Appendp(q, newprog)
    360 				q.As = ABEQ
    361 				q.From.Type = obj.TYPE_REG
    362 				q.From.Reg = REG_R1
    363 				q.To.Type = obj.TYPE_BRANCH
    364 				q.Mark |= BRANCH
    365 				p1 = q
    366 
    367 				q = obj.Appendp(q, newprog)
    368 				q.As = mov
    369 				q.From.Type = obj.TYPE_MEM
    370 				q.From.Reg = REG_R1
    371 				q.From.Offset = 0 // Panic.argp
    372 				q.To.Type = obj.TYPE_REG
    373 				q.To.Reg = REG_R2
    374 
    375 				q = obj.Appendp(q, newprog)
    376 				q.As = add
    377 				q.From.Type = obj.TYPE_CONST
    378 				q.From.Offset = int64(autosize) + ctxt.FixedFrameSize()
    379 				q.Reg = REGSP
    380 				q.To.Type = obj.TYPE_REG
    381 				q.To.Reg = REG_R3
    382 
    383 				q = obj.Appendp(q, newprog)
    384 				q.As = ABNE
    385 				q.From.Type = obj.TYPE_REG
    386 				q.From.Reg = REG_R2
    387 				q.Reg = REG_R3
    388 				q.To.Type = obj.TYPE_BRANCH
    389 				q.Mark |= BRANCH
    390 				p2 = q
    391 
    392 				q = obj.Appendp(q, newprog)
    393 				q.As = add
    394 				q.From.Type = obj.TYPE_CONST
    395 				q.From.Offset = ctxt.FixedFrameSize()
    396 				q.Reg = REGSP
    397 				q.To.Type = obj.TYPE_REG
    398 				q.To.Reg = REG_R2
    399 
    400 				q = obj.Appendp(q, newprog)
    401 				q.As = mov
    402 				q.From.Type = obj.TYPE_REG
    403 				q.From.Reg = REG_R2
    404 				q.To.Type = obj.TYPE_MEM
    405 				q.To.Reg = REG_R1
    406 				q.To.Offset = 0 // Panic.argp
    407 
    408 				q = obj.Appendp(q, newprog)
    409 
    410 				q.As = obj.ANOP
    411 				p1.Pcond = q
    412 				p2.Pcond = q
    413 			}
    414 
    415 		case ARET:
    416 			if p.From.Type == obj.TYPE_CONST {
    417 				ctxt.Diag("using BECOME (%v) is not supported!", p)
    418 				break
    419 			}
    420 
    421 			retSym := p.To.Sym
    422 			p.To.Name = obj.NAME_NONE // clear fields as we may modify p to other instruction
    423 			p.To.Sym = nil
    424 
    425 			if c.cursym.Func.Text.Mark&LEAF != 0 {
    426 				if autosize == 0 {
    427 					p.As = AJMP
    428 					p.From = obj.Addr{}
    429 					if retSym != nil { // retjmp
    430 						p.To.Type = obj.TYPE_BRANCH
    431 						p.To.Name = obj.NAME_EXTERN
    432 						p.To.Sym = retSym
    433 					} else {
    434 						p.To.Type = obj.TYPE_MEM
    435 						p.To.Reg = REGLINK
    436 						p.To.Offset = 0
    437 					}
    438 					p.Mark |= BRANCH
    439 					break
    440 				}
    441 
    442 				p.As = add
    443 				p.From.Type = obj.TYPE_CONST
    444 				p.From.Offset = int64(autosize)
    445 				p.To.Type = obj.TYPE_REG
    446 				p.To.Reg = REGSP
    447 				p.Spadj = -autosize
    448 
    449 				q = c.newprog()
    450 				q.As = AJMP
    451 				q.Pos = p.Pos
    452 				q.To.Type = obj.TYPE_MEM
    453 				q.To.Offset = 0
    454 				q.To.Reg = REGLINK
    455 				q.Mark |= BRANCH
    456 				q.Spadj = +autosize
    457 
    458 				q.Link = p.Link
    459 				p.Link = q
    460 				break
    461 			}
    462 
    463 			p.As = mov
    464 			p.From.Type = obj.TYPE_MEM
    465 			p.From.Offset = 0
    466 			p.From.Reg = REGSP
    467 			p.To.Type = obj.TYPE_REG
    468 			p.To.Reg = REG_R4
    469 			if retSym != nil { // retjmp from non-leaf, need to restore LINK register
    470 				p.To.Reg = REGLINK
    471 			}
    472 
    473 			if autosize != 0 {
    474 				q = c.newprog()
    475 				q.As = add
    476 				q.Pos = p.Pos
    477 				q.From.Type = obj.TYPE_CONST
    478 				q.From.Offset = int64(autosize)
    479 				q.To.Type = obj.TYPE_REG
    480 				q.To.Reg = REGSP
    481 				q.Spadj = -autosize
    482 
    483 				q.Link = p.Link
    484 				p.Link = q
    485 			}
    486 
    487 			q1 = c.newprog()
    488 			q1.As = AJMP
    489 			q1.Pos = p.Pos
    490 			if retSym != nil { // retjmp
    491 				q1.To.Type = obj.TYPE_BRANCH
    492 				q1.To.Name = obj.NAME_EXTERN
    493 				q1.To.Sym = retSym
    494 			} else {
    495 				q1.To.Type = obj.TYPE_MEM
    496 				q1.To.Offset = 0
    497 				q1.To.Reg = REG_R4
    498 			}
    499 			q1.Mark |= BRANCH
    500 			q1.Spadj = +autosize
    501 
    502 			q1.Link = q.Link
    503 			q.Link = q1
    504 
    505 		case AADD,
    506 			AADDU,
    507 			AADDV,
    508 			AADDVU:
    509 			if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
    510 				p.Spadj = int32(-p.From.Offset)
    511 			}
    512 		}
    513 	}
    514 
    515 	if c.ctxt.Arch.Family == sys.MIPS {
    516 		// rewrite MOVD into two MOVF in 32-bit mode to avoid unaligned memory access
    517 		for p = c.cursym.Func.Text; p != nil; p = p1 {
    518 			p1 = p.Link
    519 
    520 			if p.As != AMOVD {
    521 				continue
    522 			}
    523 			if p.From.Type != obj.TYPE_MEM && p.To.Type != obj.TYPE_MEM {
    524 				continue
    525 			}
    526 
    527 			p.As = AMOVF
    528 			q = c.newprog()
    529 			*q = *p
    530 			q.Link = p.Link
    531 			p.Link = q
    532 			p1 = q.Link
    533 
    534 			var regOff int16
    535 			if c.ctxt.Arch.ByteOrder == binary.BigEndian {
    536 				regOff = 1 // load odd register first
    537 			}
    538 			if p.From.Type == obj.TYPE_MEM {
    539 				reg := REG_F0 + (p.To.Reg-REG_F0)&^1
    540 				p.To.Reg = reg + regOff
    541 				q.To.Reg = reg + 1 - regOff
    542 				q.From.Offset += 4
    543 			} else if p.To.Type == obj.TYPE_MEM {
    544 				reg := REG_F0 + (p.From.Reg-REG_F0)&^1
    545 				p.From.Reg = reg + regOff
    546 				q.From.Reg = reg + 1 - regOff
    547 				q.To.Offset += 4
    548 			}
    549 		}
    550 	}
    551 
    552 	if nosched {
    553 		// if we don't do instruction scheduling, simply add
    554 		// NOP after each branch instruction.
    555 		for p = c.cursym.Func.Text; p != nil; p = p.Link {
    556 			if p.Mark&BRANCH != 0 {
    557 				c.addnop(p)
    558 			}
    559 		}
    560 		return
    561 	}
    562 
    563 	// instruction scheduling
    564 	q = nil                 // p - 1
    565 	q1 = c.cursym.Func.Text // top of block
    566 	o := 0                  // count of instructions
    567 	for p = c.cursym.Func.Text; p != nil; p = p1 {
    568 		p1 = p.Link
    569 		o++
    570 		if p.Mark&NOSCHED != 0 {
    571 			if q1 != p {
    572 				c.sched(q1, q)
    573 			}
    574 			for ; p != nil; p = p.Link {
    575 				if p.Mark&NOSCHED == 0 {
    576 					break
    577 				}
    578 				q = p
    579 			}
    580 			p1 = p
    581 			q1 = p
    582 			o = 0
    583 			continue
    584 		}
    585 		if p.Mark&(LABEL|SYNC) != 0 {
    586 			if q1 != p {
    587 				c.sched(q1, q)
    588 			}
    589 			q1 = p
    590 			o = 1
    591 		}
    592 		if p.Mark&(BRANCH|SYNC) != 0 {
    593 			c.sched(q1, p)
    594 			q1 = p1
    595 			o = 0
    596 		}
    597 		if o >= NSCHED {
    598 			c.sched(q1, p)
    599 			q1 = p1
    600 			o = 0
    601 		}
    602 		q = p
    603 	}
    604 }
    605 
    606 func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
    607 	// Leaf function with no frame is effectively NOSPLIT.
    608 	if framesize == 0 {
    609 		return p
    610 	}
    611 
    612 	var mov, add, sub obj.As
    613 
    614 	if c.ctxt.Arch.Family == sys.MIPS64 {
    615 		add = AADDV
    616 		mov = AMOVV
    617 		sub = ASUBVU
    618 	} else {
    619 		add = AADDU
    620 		mov = AMOVW
    621 		sub = ASUBU
    622 	}
    623 
    624 	// MOV	g_stackguard(g), R1
    625 	p = obj.Appendp(p, c.newprog)
    626 
    627 	p.As = mov
    628 	p.From.Type = obj.TYPE_MEM
    629 	p.From.Reg = REGG
    630 	p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
    631 	if c.cursym.CFunc() {
    632 		p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
    633 	}
    634 	p.To.Type = obj.TYPE_REG
    635 	p.To.Reg = REG_R1
    636 
    637 	var q *obj.Prog
    638 	if framesize <= objabi.StackSmall {
    639 		// small stack: SP < stackguard
    640 		//	AGTU	SP, stackguard, R1
    641 		p = obj.Appendp(p, c.newprog)
    642 
    643 		p.As = ASGTU
    644 		p.From.Type = obj.TYPE_REG
    645 		p.From.Reg = REGSP
    646 		p.Reg = REG_R1
    647 		p.To.Type = obj.TYPE_REG
    648 		p.To.Reg = REG_R1
    649 	} else if framesize <= objabi.StackBig {
    650 		// large stack: SP-framesize < stackguard-StackSmall
    651 		//	ADD	$-(framesize-StackSmall), SP, R2
    652 		//	SGTU	R2, stackguard, R1
    653 		p = obj.Appendp(p, c.newprog)
    654 
    655 		p.As = add
    656 		p.From.Type = obj.TYPE_CONST
    657 		p.From.Offset = -(int64(framesize) - objabi.StackSmall)
    658 		p.Reg = REGSP
    659 		p.To.Type = obj.TYPE_REG
    660 		p.To.Reg = REG_R2
    661 
    662 		p = obj.Appendp(p, c.newprog)
    663 		p.As = ASGTU
    664 		p.From.Type = obj.TYPE_REG
    665 		p.From.Reg = REG_R2
    666 		p.Reg = REG_R1
    667 		p.To.Type = obj.TYPE_REG
    668 		p.To.Reg = REG_R1
    669 	} else {
    670 		// Such a large stack we need to protect against wraparound.
    671 		// If SP is close to zero:
    672 		//	SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
    673 		// The +StackGuard on both sides is required to keep the left side positive:
    674 		// SP is allowed to be slightly below stackguard. See stack.h.
    675 		//
    676 		// Preemption sets stackguard to StackPreempt, a very large value.
    677 		// That breaks the math above, so we have to check for that explicitly.
    678 		//	// stackguard is R1
    679 		//	MOV	$StackPreempt, R2
    680 		//	BEQ	R1, R2, label-of-call-to-morestack
    681 		//	ADD	$StackGuard, SP, R2
    682 		//	SUB	R1, R2
    683 		//	MOV	$(framesize+(StackGuard-StackSmall)), R1
    684 		//	SGTU	R2, R1, R1
    685 		p = obj.Appendp(p, c.newprog)
    686 
    687 		p.As = mov
    688 		p.From.Type = obj.TYPE_CONST
    689 		p.From.Offset = objabi.StackPreempt
    690 		p.To.Type = obj.TYPE_REG
    691 		p.To.Reg = REG_R2
    692 
    693 		p = obj.Appendp(p, c.newprog)
    694 		q = p
    695 		p.As = ABEQ
    696 		p.From.Type = obj.TYPE_REG
    697 		p.From.Reg = REG_R1
    698 		p.Reg = REG_R2
    699 		p.To.Type = obj.TYPE_BRANCH
    700 		p.Mark |= BRANCH
    701 
    702 		p = obj.Appendp(p, c.newprog)
    703 		p.As = add
    704 		p.From.Type = obj.TYPE_CONST
    705 		p.From.Offset = objabi.StackGuard
    706 		p.Reg = REGSP
    707 		p.To.Type = obj.TYPE_REG
    708 		p.To.Reg = REG_R2
    709 
    710 		p = obj.Appendp(p, c.newprog)
    711 		p.As = sub
    712 		p.From.Type = obj.TYPE_REG
    713 		p.From.Reg = REG_R1
    714 		p.To.Type = obj.TYPE_REG
    715 		p.To.Reg = REG_R2
    716 
    717 		p = obj.Appendp(p, c.newprog)
    718 		p.As = mov
    719 		p.From.Type = obj.TYPE_CONST
    720 		p.From.Offset = int64(framesize) + objabi.StackGuard - objabi.StackSmall
    721 		p.To.Type = obj.TYPE_REG
    722 		p.To.Reg = REG_R1
    723 
    724 		p = obj.Appendp(p, c.newprog)
    725 		p.As = ASGTU
    726 		p.From.Type = obj.TYPE_REG
    727 		p.From.Reg = REG_R2
    728 		p.Reg = REG_R1
    729 		p.To.Type = obj.TYPE_REG
    730 		p.To.Reg = REG_R1
    731 	}
    732 
    733 	// q1: BNE	R1, done
    734 	p = obj.Appendp(p, c.newprog)
    735 	q1 := p
    736 
    737 	p.As = ABNE
    738 	p.From.Type = obj.TYPE_REG
    739 	p.From.Reg = REG_R1
    740 	p.To.Type = obj.TYPE_BRANCH
    741 	p.Mark |= BRANCH
    742 
    743 	// MOV	LINK, R3
    744 	p = obj.Appendp(p, c.newprog)
    745 
    746 	p.As = mov
    747 	p.From.Type = obj.TYPE_REG
    748 	p.From.Reg = REGLINK
    749 	p.To.Type = obj.TYPE_REG
    750 	p.To.Reg = REG_R3
    751 	if q != nil {
    752 		q.Pcond = p
    753 		p.Mark |= LABEL
    754 	}
    755 
    756 	// JAL	runtime.morestack(SB)
    757 	p = obj.Appendp(p, c.newprog)
    758 
    759 	p.As = AJAL
    760 	p.To.Type = obj.TYPE_BRANCH
    761 	if c.cursym.CFunc() {
    762 		p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
    763 	} else if !c.cursym.Func.Text.From.Sym.NeedCtxt() {
    764 		p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
    765 	} else {
    766 		p.To.Sym = c.ctxt.Lookup("runtime.morestack")
    767 	}
    768 	p.Mark |= BRANCH
    769 
    770 	// JMP	start
    771 	p = obj.Appendp(p, c.newprog)
    772 
    773 	p.As = AJMP
    774 	p.To.Type = obj.TYPE_BRANCH
    775 	p.Pcond = c.cursym.Func.Text.Link
    776 	p.Mark |= BRANCH
    777 
    778 	// placeholder for q1's jump target
    779 	p = obj.Appendp(p, c.newprog)
    780 
    781 	p.As = obj.ANOP // zero-width place holder
    782 	q1.Pcond = p
    783 
    784 	return p
    785 }
    786 
    787 func (c *ctxt0) addnop(p *obj.Prog) {
    788 	q := c.newprog()
    789 	q.As = ANOOP
    790 	q.Pos = p.Pos
    791 	q.Link = p.Link
    792 	p.Link = q
    793 }
    794 
    795 const (
    796 	E_HILO  = 1 << 0
    797 	E_FCR   = 1 << 1
    798 	E_MCR   = 1 << 2
    799 	E_MEM   = 1 << 3
    800 	E_MEMSP = 1 << 4 /* uses offset and size */
    801 	E_MEMSB = 1 << 5 /* uses offset and size */
    802 	ANYMEM  = E_MEM | E_MEMSP | E_MEMSB
    803 	//DELAY = LOAD|BRANCH|FCMP
    804 	DELAY = BRANCH /* only schedule branch */
    805 )
    806 
    807 type Dep struct {
    808 	ireg uint32
    809 	freg uint32
    810 	cc   uint32
    811 }
    812 
    813 type Sch struct {
    814 	p       obj.Prog
    815 	set     Dep
    816 	used    Dep
    817 	soffset int32
    818 	size    uint8
    819 	nop     uint8
    820 	comp    bool
    821 }
    822 
    823 func (c *ctxt0) sched(p0, pe *obj.Prog) {
    824 	var sch [NSCHED]Sch
    825 
    826 	/*
    827 	 * build side structure
    828 	 */
    829 	s := sch[:]
    830 	for p := p0; ; p = p.Link {
    831 		s[0].p = *p
    832 		c.markregused(&s[0])
    833 		if p == pe {
    834 			break
    835 		}
    836 		s = s[1:]
    837 	}
    838 	se := s
    839 
    840 	for i := cap(sch) - cap(se); i >= 0; i-- {
    841 		s = sch[i:]
    842 		if s[0].p.Mark&DELAY == 0 {
    843 			continue
    844 		}
    845 		if -cap(s) < -cap(se) {
    846 			if !conflict(&s[0], &s[1]) {
    847 				continue
    848 			}
    849 		}
    850 
    851 		var t []Sch
    852 		var j int
    853 		for j = cap(sch) - cap(s) - 1; j >= 0; j-- {
    854 			t = sch[j:]
    855 			if t[0].comp {
    856 				if s[0].p.Mark&BRANCH != 0 {
    857 					goto no2
    858 				}
    859 			}
    860 			if t[0].p.Mark&DELAY != 0 {
    861 				if -cap(s) >= -cap(se) || conflict(&t[0], &s[1]) {
    862 					goto no2
    863 				}
    864 			}
    865 			for u := t[1:]; -cap(u) <= -cap(s); u = u[1:] {
    866 				if c.depend(&u[0], &t[0]) {
    867 					goto no2
    868 				}
    869 			}
    870 			goto out2
    871 		no2:
    872 		}
    873 
    874 		if s[0].p.Mark&BRANCH != 0 {
    875 			s[0].nop = 1
    876 		}
    877 		continue
    878 
    879 	out2:
    880 		// t[0] is the instruction being moved to fill the delay
    881 		stmp := t[0]
    882 		copy(t[:i-j], t[1:i-j+1])
    883 		s[0] = stmp
    884 
    885 		if t[i-j-1].p.Mark&BRANCH != 0 {
    886 			// t[i-j] is being put into a branch delay slot
    887 			// combine its Spadj with the branch instruction
    888 			t[i-j-1].p.Spadj += t[i-j].p.Spadj
    889 			t[i-j].p.Spadj = 0
    890 		}
    891 
    892 		i--
    893 	}
    894 
    895 	/*
    896 	 * put it all back
    897 	 */
    898 	var p *obj.Prog
    899 	var q *obj.Prog
    900 	for s, p = sch[:], p0; -cap(s) <= -cap(se); s, p = s[1:], q {
    901 		q = p.Link
    902 		if q != s[0].p.Link {
    903 			*p = s[0].p
    904 			p.Link = q
    905 		}
    906 		for s[0].nop != 0 {
    907 			s[0].nop--
    908 			c.addnop(p)
    909 		}
    910 	}
    911 }
    912 
    913 func (c *ctxt0) markregused(s *Sch) {
    914 	p := &s.p
    915 	s.comp = c.compound(p)
    916 	s.nop = 0
    917 	if s.comp {
    918 		s.set.ireg |= 1 << (REGTMP - REG_R0)
    919 		s.used.ireg |= 1 << (REGTMP - REG_R0)
    920 	}
    921 
    922 	ar := 0  /* dest is really reference */
    923 	ad := 0  /* source/dest is really address */
    924 	ld := 0  /* opcode is load instruction */
    925 	sz := 20 /* size of load/store for overlap computation */
    926 
    927 	/*
    928 	 * flags based on opcode
    929 	 */
    930 	switch p.As {
    931 	case obj.ATEXT:
    932 		c.autosize = int32(p.To.Offset + 8)
    933 		ad = 1
    934 
    935 	case AJAL:
    936 		r := p.Reg
    937 		if r == 0 {
    938 			r = REGLINK
    939 		}
    940 		s.set.ireg |= 1 << uint(r-REG_R0)
    941 		ar = 1
    942 		ad = 1
    943 
    944 	case ABGEZAL,
    945 		ABLTZAL:
    946 		s.set.ireg |= 1 << (REGLINK - REG_R0)
    947 		fallthrough
    948 	case ABEQ,
    949 		ABGEZ,
    950 		ABGTZ,
    951 		ABLEZ,
    952 		ABLTZ,
    953 		ABNE:
    954 		ar = 1
    955 		ad = 1
    956 
    957 	case ABFPT,
    958 		ABFPF:
    959 		ad = 1
    960 		s.used.cc |= E_FCR
    961 
    962 	case ACMPEQD,
    963 		ACMPEQF,
    964 		ACMPGED,
    965 		ACMPGEF,
    966 		ACMPGTD,
    967 		ACMPGTF:
    968 		ar = 1
    969 		s.set.cc |= E_FCR
    970 		p.Mark |= FCMP
    971 
    972 	case AJMP:
    973 		ar = 1
    974 		ad = 1
    975 
    976 	case AMOVB,
    977 		AMOVBU:
    978 		sz = 1
    979 		ld = 1
    980 
    981 	case AMOVH,
    982 		AMOVHU:
    983 		sz = 2
    984 		ld = 1
    985 
    986 	case AMOVF,
    987 		AMOVW,
    988 		AMOVWL,
    989 		AMOVWR:
    990 		sz = 4
    991 		ld = 1
    992 
    993 	case AMOVD,
    994 		AMOVV,
    995 		AMOVVL,
    996 		AMOVVR:
    997 		sz = 8
    998 		ld = 1
    999 
   1000 	case ADIV,
   1001 		ADIVU,
   1002 		AMUL,
   1003 		AMULU,
   1004 		AREM,
   1005 		AREMU,
   1006 		ADIVV,
   1007 		ADIVVU,
   1008 		AMULV,
   1009 		AMULVU,
   1010 		AREMV,
   1011 		AREMVU:
   1012 		s.set.cc = E_HILO
   1013 		fallthrough
   1014 	case AADD,
   1015 		AADDU,
   1016 		AADDV,
   1017 		AADDVU,
   1018 		AAND,
   1019 		ANOR,
   1020 		AOR,
   1021 		ASGT,
   1022 		ASGTU,
   1023 		ASLL,
   1024 		ASRA,
   1025 		ASRL,
   1026 		ASLLV,
   1027 		ASRAV,
   1028 		ASRLV,
   1029 		ASUB,
   1030 		ASUBU,
   1031 		ASUBV,
   1032 		ASUBVU,
   1033 		AXOR,
   1034 
   1035 		AADDD,
   1036 		AADDF,
   1037 		AADDW,
   1038 		ASUBD,
   1039 		ASUBF,
   1040 		ASUBW,
   1041 		AMULF,
   1042 		AMULD,
   1043 		AMULW,
   1044 		ADIVF,
   1045 		ADIVD,
   1046 		ADIVW:
   1047 		if p.Reg == 0 {
   1048 			if p.To.Type == obj.TYPE_REG {
   1049 				p.Reg = p.To.Reg
   1050 			}
   1051 			//if(p->reg == NREG)
   1052 			//	print("botch %P\n", p);
   1053 		}
   1054 	}
   1055 
   1056 	/*
   1057 	 * flags based on 'to' field
   1058 	 */
   1059 	cls := int(p.To.Class)
   1060 	if cls == 0 {
   1061 		cls = c.aclass(&p.To) + 1
   1062 		p.To.Class = int8(cls)
   1063 	}
   1064 	cls--
   1065 	switch cls {
   1066 	default:
   1067 		fmt.Printf("unknown class %d %v\n", cls, p)
   1068 
   1069 	case C_ZCON,
   1070 		C_SCON,
   1071 		C_ADD0CON,
   1072 		C_AND0CON,
   1073 		C_ADDCON,
   1074 		C_ANDCON,
   1075 		C_UCON,
   1076 		C_LCON,
   1077 		C_NONE,
   1078 		C_SBRA,
   1079 		C_LBRA,
   1080 		C_ADDR,
   1081 		C_TEXTSIZE:
   1082 		break
   1083 
   1084 	case C_HI,
   1085 		C_LO:
   1086 		s.set.cc |= E_HILO
   1087 
   1088 	case C_FCREG:
   1089 		s.set.cc |= E_FCR
   1090 
   1091 	case C_MREG:
   1092 		s.set.cc |= E_MCR
   1093 
   1094 	case C_ZOREG,
   1095 		C_SOREG,
   1096 		C_LOREG:
   1097 		cls = int(p.To.Reg)
   1098 		s.used.ireg |= 1 << uint(cls-REG_R0)
   1099 		if ad != 0 {
   1100 			break
   1101 		}
   1102 		s.size = uint8(sz)
   1103 		s.soffset = c.regoff(&p.To)
   1104 
   1105 		m := uint32(ANYMEM)
   1106 		if cls == REGSB {
   1107 			m = E_MEMSB
   1108 		}
   1109 		if cls == REGSP {
   1110 			m = E_MEMSP
   1111 		}
   1112 
   1113 		if ar != 0 {
   1114 			s.used.cc |= m
   1115 		} else {
   1116 			s.set.cc |= m
   1117 		}
   1118 
   1119 	case C_SACON,
   1120 		C_LACON:
   1121 		s.used.ireg |= 1 << (REGSP - REG_R0)
   1122 
   1123 	case C_SECON,
   1124 		C_LECON:
   1125 		s.used.ireg |= 1 << (REGSB - REG_R0)
   1126 
   1127 	case C_REG:
   1128 		if ar != 0 {
   1129 			s.used.ireg |= 1 << uint(p.To.Reg-REG_R0)
   1130 		} else {
   1131 			s.set.ireg |= 1 << uint(p.To.Reg-REG_R0)
   1132 		}
   1133 
   1134 	case C_FREG:
   1135 		if ar != 0 {
   1136 			s.used.freg |= 1 << uint(p.To.Reg-REG_F0)
   1137 		} else {
   1138 			s.set.freg |= 1 << uint(p.To.Reg-REG_F0)
   1139 		}
   1140 		if ld != 0 && p.From.Type == obj.TYPE_REG {
   1141 			p.Mark |= LOAD
   1142 		}
   1143 
   1144 	case C_SAUTO,
   1145 		C_LAUTO:
   1146 		s.used.ireg |= 1 << (REGSP - REG_R0)
   1147 		if ad != 0 {
   1148 			break
   1149 		}
   1150 		s.size = uint8(sz)
   1151 		s.soffset = c.regoff(&p.To)
   1152 
   1153 		if ar != 0 {
   1154 			s.used.cc |= E_MEMSP
   1155 		} else {
   1156 			s.set.cc |= E_MEMSP
   1157 		}
   1158 
   1159 	case C_SEXT,
   1160 		C_LEXT:
   1161 		s.used.ireg |= 1 << (REGSB - REG_R0)
   1162 		if ad != 0 {
   1163 			break
   1164 		}
   1165 		s.size = uint8(sz)
   1166 		s.soffset = c.regoff(&p.To)
   1167 
   1168 		if ar != 0 {
   1169 			s.used.cc |= E_MEMSB
   1170 		} else {
   1171 			s.set.cc |= E_MEMSB
   1172 		}
   1173 	}
   1174 
   1175 	/*
   1176 	 * flags based on 'from' field
   1177 	 */
   1178 	cls = int(p.From.Class)
   1179 	if cls == 0 {
   1180 		cls = c.aclass(&p.From) + 1
   1181 		p.From.Class = int8(cls)
   1182 	}
   1183 	cls--
   1184 	switch cls {
   1185 	default:
   1186 		fmt.Printf("unknown class %d %v\n", cls, p)
   1187 
   1188 	case C_ZCON,
   1189 		C_SCON,
   1190 		C_ADD0CON,
   1191 		C_AND0CON,
   1192 		C_ADDCON,
   1193 		C_ANDCON,
   1194 		C_UCON,
   1195 		C_LCON,
   1196 		C_NONE,
   1197 		C_SBRA,
   1198 		C_LBRA,
   1199 		C_ADDR,
   1200 		C_TEXTSIZE:
   1201 		break
   1202 
   1203 	case C_HI,
   1204 		C_LO:
   1205 		s.used.cc |= E_HILO
   1206 
   1207 	case C_FCREG:
   1208 		s.used.cc |= E_FCR
   1209 
   1210 	case C_MREG:
   1211 		s.used.cc |= E_MCR
   1212 
   1213 	case C_ZOREG,
   1214 		C_SOREG,
   1215 		C_LOREG:
   1216 		cls = int(p.From.Reg)
   1217 		s.used.ireg |= 1 << uint(cls-REG_R0)
   1218 		if ld != 0 {
   1219 			p.Mark |= LOAD
   1220 		}
   1221 		s.size = uint8(sz)
   1222 		s.soffset = c.regoff(&p.From)
   1223 
   1224 		m := uint32(ANYMEM)
   1225 		if cls == REGSB {
   1226 			m = E_MEMSB
   1227 		}
   1228 		if cls == REGSP {
   1229 			m = E_MEMSP
   1230 		}
   1231 
   1232 		s.used.cc |= m
   1233 
   1234 	case C_SACON,
   1235 		C_LACON:
   1236 		cls = int(p.From.Reg)
   1237 		if cls == 0 {
   1238 			cls = REGSP
   1239 		}
   1240 		s.used.ireg |= 1 << uint(cls-REG_R0)
   1241 
   1242 	case C_SECON,
   1243 		C_LECON:
   1244 		s.used.ireg |= 1 << (REGSB - REG_R0)
   1245 
   1246 	case C_REG:
   1247 		s.used.ireg |= 1 << uint(p.From.Reg-REG_R0)
   1248 
   1249 	case C_FREG:
   1250 		s.used.freg |= 1 << uint(p.From.Reg-REG_F0)
   1251 		if ld != 0 && p.To.Type == obj.TYPE_REG {
   1252 			p.Mark |= LOAD
   1253 		}
   1254 
   1255 	case C_SAUTO,
   1256 		C_LAUTO:
   1257 		s.used.ireg |= 1 << (REGSP - REG_R0)
   1258 		if ld != 0 {
   1259 			p.Mark |= LOAD
   1260 		}
   1261 		if ad != 0 {
   1262 			break
   1263 		}
   1264 		s.size = uint8(sz)
   1265 		s.soffset = c.regoff(&p.From)
   1266 
   1267 		s.used.cc |= E_MEMSP
   1268 
   1269 	case C_SEXT:
   1270 	case C_LEXT:
   1271 		s.used.ireg |= 1 << (REGSB - REG_R0)
   1272 		if ld != 0 {
   1273 			p.Mark |= LOAD
   1274 		}
   1275 		if ad != 0 {
   1276 			break
   1277 		}
   1278 		s.size = uint8(sz)
   1279 		s.soffset = c.regoff(&p.From)
   1280 
   1281 		s.used.cc |= E_MEMSB
   1282 	}
   1283 
   1284 	cls = int(p.Reg)
   1285 	if cls != 0 {
   1286 		if REG_F0 <= cls && cls <= REG_F31 {
   1287 			s.used.freg |= 1 << uint(cls-REG_F0)
   1288 		} else {
   1289 			s.used.ireg |= 1 << uint(cls-REG_R0)
   1290 		}
   1291 	}
   1292 	s.set.ireg &^= (1 << (REGZERO - REG_R0)) /* R0 can't be set */
   1293 }
   1294 
   1295 /*
   1296  * test to see if two instructions can be
   1297  * interchanged without changing semantics
   1298  */
   1299 func (c *ctxt0) depend(sa, sb *Sch) bool {
   1300 	if sa.set.ireg&(sb.set.ireg|sb.used.ireg) != 0 {
   1301 		return true
   1302 	}
   1303 	if sb.set.ireg&sa.used.ireg != 0 {
   1304 		return true
   1305 	}
   1306 
   1307 	if sa.set.freg&(sb.set.freg|sb.used.freg) != 0 {
   1308 		return true
   1309 	}
   1310 	if sb.set.freg&sa.used.freg != 0 {
   1311 		return true
   1312 	}
   1313 
   1314 	/*
   1315 	 * special case.
   1316 	 * loads from same address cannot pass.
   1317 	 * this is for hardware fifo's and the like
   1318 	 */
   1319 	if sa.used.cc&sb.used.cc&E_MEM != 0 {
   1320 		if sa.p.Reg == sb.p.Reg {
   1321 			if c.regoff(&sa.p.From) == c.regoff(&sb.p.From) {
   1322 				return true
   1323 			}
   1324 		}
   1325 	}
   1326 
   1327 	x := (sa.set.cc & (sb.set.cc | sb.used.cc)) | (sb.set.cc & sa.used.cc)
   1328 	if x != 0 {
   1329 		/*
   1330 		 * allow SB and SP to pass each other.
   1331 		 * allow SB to pass SB iff doffsets are ok
   1332 		 * anything else conflicts
   1333 		 */
   1334 		if x != E_MEMSP && x != E_MEMSB {
   1335 			return true
   1336 		}
   1337 		x = sa.set.cc | sb.set.cc | sa.used.cc | sb.used.cc
   1338 		if x&E_MEM != 0 {
   1339 			return true
   1340 		}
   1341 		if offoverlap(sa, sb) {
   1342 			return true
   1343 		}
   1344 	}
   1345 
   1346 	return false
   1347 }
   1348 
   1349 func offoverlap(sa, sb *Sch) bool {
   1350 	if sa.soffset < sb.soffset {
   1351 		if sa.soffset+int32(sa.size) > sb.soffset {
   1352 			return true
   1353 		}
   1354 		return false
   1355 	}
   1356 	if sb.soffset+int32(sb.size) > sa.soffset {
   1357 		return true
   1358 	}
   1359 	return false
   1360 }
   1361 
   1362 /*
   1363  * test 2 adjacent instructions
   1364  * and find out if inserted instructions
   1365  * are desired to prevent stalls.
   1366  */
   1367 func conflict(sa, sb *Sch) bool {
   1368 	if sa.set.ireg&sb.used.ireg != 0 {
   1369 		return true
   1370 	}
   1371 	if sa.set.freg&sb.used.freg != 0 {
   1372 		return true
   1373 	}
   1374 	if sa.set.cc&sb.used.cc != 0 {
   1375 		return true
   1376 	}
   1377 	return false
   1378 }
   1379 
   1380 func (c *ctxt0) compound(p *obj.Prog) bool {
   1381 	o := c.oplook(p)
   1382 	if o.size != 4 {
   1383 		return true
   1384 	}
   1385 	if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSB {
   1386 		return true
   1387 	}
   1388 	return false
   1389 }
   1390 
   1391 var Linkmips64 = obj.LinkArch{
   1392 	Arch:       sys.ArchMIPS64,
   1393 	Init:       buildop,
   1394 	Preprocess: preprocess,
   1395 	Assemble:   span0,
   1396 	Progedit:   progedit,
   1397 }
   1398 
   1399 var Linkmips64le = obj.LinkArch{
   1400 	Arch:       sys.ArchMIPS64LE,
   1401 	Init:       buildop,
   1402 	Preprocess: preprocess,
   1403 	Assemble:   span0,
   1404 	Progedit:   progedit,
   1405 }
   1406 
   1407 var Linkmips = obj.LinkArch{
   1408 	Arch:       sys.ArchMIPS,
   1409 	Init:       buildop,
   1410 	Preprocess: preprocess,
   1411 	Assemble:   span0,
   1412 	Progedit:   progedit,
   1413 }
   1414 
   1415 var Linkmipsle = obj.LinkArch{
   1416 	Arch:       sys.ArchMIPSLE,
   1417 	Init:       buildop,
   1418 	Preprocess: preprocess,
   1419 	Assemble:   span0,
   1420 	Progedit:   progedit,
   1421 }
   1422