gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

obj0.go (29399B)


      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 }