github.com/epfl-dcsl/gotee@v0.0.0-20200909122901-014b35f5e5e9/src/cmd/internal/obj/mips/obj0.go (about)

     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  	"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 addrOff int64
   535  			if c.ctxt.Arch.ByteOrder == binary.BigEndian {
   536  				addrOff = 4 // swap load/save order
   537  			}
   538  			if p.From.Type == obj.TYPE_MEM {
   539  				reg := REG_F0 + (p.To.Reg-REG_F0)&^1
   540  				p.To.Reg = reg
   541  				q.To.Reg = reg + 1
   542  				p.From.Offset += addrOff
   543  				q.From.Offset += 4 - addrOff
   544  			} else if p.To.Type == obj.TYPE_MEM {
   545  				reg := REG_F0 + (p.From.Reg-REG_F0)&^1
   546  				p.From.Reg = reg
   547  				q.From.Reg = reg + 1
   548  				p.To.Offset += addrOff
   549  				q.To.Offset += 4 - addrOff
   550  			}
   551  		}
   552  	}
   553  
   554  	if nosched {
   555  		// if we don't do instruction scheduling, simply add
   556  		// NOP after each branch instruction.
   557  		for p = c.cursym.Func.Text; p != nil; p = p.Link {
   558  			if p.Mark&BRANCH != 0 {
   559  				c.addnop(p)
   560  			}
   561  		}
   562  		return
   563  	}
   564  
   565  	// instruction scheduling
   566  	q = nil                 // p - 1
   567  	q1 = c.cursym.Func.Text // top of block
   568  	o := 0                  // count of instructions
   569  	for p = c.cursym.Func.Text; p != nil; p = p1 {
   570  		p1 = p.Link
   571  		o++
   572  		if p.Mark&NOSCHED != 0 {
   573  			if q1 != p {
   574  				c.sched(q1, q)
   575  			}
   576  			for ; p != nil; p = p.Link {
   577  				if p.Mark&NOSCHED == 0 {
   578  					break
   579  				}
   580  				q = p
   581  			}
   582  			p1 = p
   583  			q1 = p
   584  			o = 0
   585  			continue
   586  		}
   587  		if p.Mark&(LABEL|SYNC) != 0 {
   588  			if q1 != p {
   589  				c.sched(q1, q)
   590  			}
   591  			q1 = p
   592  			o = 1
   593  		}
   594  		if p.Mark&(BRANCH|SYNC) != 0 {
   595  			c.sched(q1, p)
   596  			q1 = p1
   597  			o = 0
   598  		}
   599  		if o >= NSCHED {
   600  			c.sched(q1, p)
   601  			q1 = p1
   602  			o = 0
   603  		}
   604  		q = p
   605  	}
   606  }
   607  
   608  func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
   609  	// Leaf function with no frame is effectively NOSPLIT.
   610  	if framesize == 0 {
   611  		return p
   612  	}
   613  
   614  	var mov, add, sub obj.As
   615  
   616  	if c.ctxt.Arch.Family == sys.MIPS64 {
   617  		add = AADDV
   618  		mov = AMOVV
   619  		sub = ASUBVU
   620  	} else {
   621  		add = AADDU
   622  		mov = AMOVW
   623  		sub = ASUBU
   624  	}
   625  
   626  	// MOV	g_stackguard(g), R1
   627  	p = obj.Appendp(p, c.newprog)
   628  
   629  	p.As = mov
   630  	p.From.Type = obj.TYPE_MEM
   631  	p.From.Reg = REGG
   632  	p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
   633  	if c.cursym.CFunc() {
   634  		p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
   635  	}
   636  	p.To.Type = obj.TYPE_REG
   637  	p.To.Reg = REG_R1
   638  
   639  	var q *obj.Prog
   640  	if framesize <= objabi.StackSmall {
   641  		// small stack: SP < stackguard
   642  		//	AGTU	SP, stackguard, R1
   643  		p = obj.Appendp(p, c.newprog)
   644  
   645  		p.As = ASGTU
   646  		p.From.Type = obj.TYPE_REG
   647  		p.From.Reg = REGSP
   648  		p.Reg = REG_R1
   649  		p.To.Type = obj.TYPE_REG
   650  		p.To.Reg = REG_R1
   651  	} else if framesize <= objabi.StackBig {
   652  		// large stack: SP-framesize < stackguard-StackSmall
   653  		//	ADD	$-(framesize-StackSmall), SP, R2
   654  		//	SGTU	R2, stackguard, R1
   655  		p = obj.Appendp(p, c.newprog)
   656  
   657  		p.As = add
   658  		p.From.Type = obj.TYPE_CONST
   659  		p.From.Offset = -(int64(framesize) - objabi.StackSmall)
   660  		p.Reg = REGSP
   661  		p.To.Type = obj.TYPE_REG
   662  		p.To.Reg = REG_R2
   663  
   664  		p = obj.Appendp(p, c.newprog)
   665  		p.As = ASGTU
   666  		p.From.Type = obj.TYPE_REG
   667  		p.From.Reg = REG_R2
   668  		p.Reg = REG_R1
   669  		p.To.Type = obj.TYPE_REG
   670  		p.To.Reg = REG_R1
   671  	} else {
   672  		// Such a large stack we need to protect against wraparound.
   673  		// If SP is close to zero:
   674  		//	SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
   675  		// The +StackGuard on both sides is required to keep the left side positive:
   676  		// SP is allowed to be slightly below stackguard. See stack.h.
   677  		//
   678  		// Preemption sets stackguard to StackPreempt, a very large value.
   679  		// That breaks the math above, so we have to check for that explicitly.
   680  		//	// stackguard is R1
   681  		//	MOV	$StackPreempt, R2
   682  		//	BEQ	R1, R2, label-of-call-to-morestack
   683  		//	ADD	$StackGuard, SP, R2
   684  		//	SUB	R1, R2
   685  		//	MOV	$(framesize+(StackGuard-StackSmall)), R1
   686  		//	SGTU	R2, R1, R1
   687  		p = obj.Appendp(p, c.newprog)
   688  
   689  		p.As = mov
   690  		p.From.Type = obj.TYPE_CONST
   691  		p.From.Offset = objabi.StackPreempt
   692  		p.To.Type = obj.TYPE_REG
   693  		p.To.Reg = REG_R2
   694  
   695  		p = obj.Appendp(p, c.newprog)
   696  		q = p
   697  		p.As = ABEQ
   698  		p.From.Type = obj.TYPE_REG
   699  		p.From.Reg = REG_R1
   700  		p.Reg = REG_R2
   701  		p.To.Type = obj.TYPE_BRANCH
   702  		p.Mark |= BRANCH
   703  
   704  		p = obj.Appendp(p, c.newprog)
   705  		p.As = add
   706  		p.From.Type = obj.TYPE_CONST
   707  		p.From.Offset = objabi.StackGuard
   708  		p.Reg = REGSP
   709  		p.To.Type = obj.TYPE_REG
   710  		p.To.Reg = REG_R2
   711  
   712  		p = obj.Appendp(p, c.newprog)
   713  		p.As = sub
   714  		p.From.Type = obj.TYPE_REG
   715  		p.From.Reg = REG_R1
   716  		p.To.Type = obj.TYPE_REG
   717  		p.To.Reg = REG_R2
   718  
   719  		p = obj.Appendp(p, c.newprog)
   720  		p.As = mov
   721  		p.From.Type = obj.TYPE_CONST
   722  		p.From.Offset = int64(framesize) + objabi.StackGuard - objabi.StackSmall
   723  		p.To.Type = obj.TYPE_REG
   724  		p.To.Reg = REG_R1
   725  
   726  		p = obj.Appendp(p, c.newprog)
   727  		p.As = ASGTU
   728  		p.From.Type = obj.TYPE_REG
   729  		p.From.Reg = REG_R2
   730  		p.Reg = REG_R1
   731  		p.To.Type = obj.TYPE_REG
   732  		p.To.Reg = REG_R1
   733  	}
   734  
   735  	// q1: BNE	R1, done
   736  	p = obj.Appendp(p, c.newprog)
   737  	q1 := p
   738  
   739  	p.As = ABNE
   740  	p.From.Type = obj.TYPE_REG
   741  	p.From.Reg = REG_R1
   742  	p.To.Type = obj.TYPE_BRANCH
   743  	p.Mark |= BRANCH
   744  
   745  	// MOV	LINK, R3
   746  	p = obj.Appendp(p, c.newprog)
   747  
   748  	p.As = mov
   749  	p.From.Type = obj.TYPE_REG
   750  	p.From.Reg = REGLINK
   751  	p.To.Type = obj.TYPE_REG
   752  	p.To.Reg = REG_R3
   753  	if q != nil {
   754  		q.Pcond = p
   755  		p.Mark |= LABEL
   756  	}
   757  
   758  	// JAL	runtime.morestack(SB)
   759  	p = obj.Appendp(p, c.newprog)
   760  
   761  	p.As = AJAL
   762  	p.To.Type = obj.TYPE_BRANCH
   763  	if c.cursym.CFunc() {
   764  		p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
   765  	} else if !c.cursym.Func.Text.From.Sym.NeedCtxt() {
   766  		p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
   767  	} else {
   768  		p.To.Sym = c.ctxt.Lookup("runtime.morestack")
   769  	}
   770  	p.Mark |= BRANCH
   771  
   772  	// JMP	start
   773  	p = obj.Appendp(p, c.newprog)
   774  
   775  	p.As = AJMP
   776  	p.To.Type = obj.TYPE_BRANCH
   777  	p.Pcond = c.cursym.Func.Text.Link
   778  	p.Mark |= BRANCH
   779  
   780  	// placeholder for q1's jump target
   781  	p = obj.Appendp(p, c.newprog)
   782  
   783  	p.As = obj.ANOP // zero-width place holder
   784  	q1.Pcond = p
   785  
   786  	return p
   787  }
   788  
   789  func (c *ctxt0) addnop(p *obj.Prog) {
   790  	q := c.newprog()
   791  	q.As = ANOOP
   792  	q.Pos = p.Pos
   793  	q.Link = p.Link
   794  	p.Link = q
   795  }
   796  
   797  const (
   798  	E_HILO  = 1 << 0
   799  	E_FCR   = 1 << 1
   800  	E_MCR   = 1 << 2
   801  	E_MEM   = 1 << 3
   802  	E_MEMSP = 1 << 4 /* uses offset and size */
   803  	E_MEMSB = 1 << 5 /* uses offset and size */
   804  	ANYMEM  = E_MEM | E_MEMSP | E_MEMSB
   805  	//DELAY = LOAD|BRANCH|FCMP
   806  	DELAY = BRANCH /* only schedule branch */
   807  )
   808  
   809  type Dep struct {
   810  	ireg uint32
   811  	freg uint32
   812  	cc   uint32
   813  }
   814  
   815  type Sch struct {
   816  	p       obj.Prog
   817  	set     Dep
   818  	used    Dep
   819  	soffset int32
   820  	size    uint8
   821  	nop     uint8
   822  	comp    bool
   823  }
   824  
   825  func (c *ctxt0) sched(p0, pe *obj.Prog) {
   826  	var sch [NSCHED]Sch
   827  
   828  	/*
   829  	 * build side structure
   830  	 */
   831  	s := sch[:]
   832  	for p := p0; ; p = p.Link {
   833  		s[0].p = *p
   834  		c.markregused(&s[0])
   835  		if p == pe {
   836  			break
   837  		}
   838  		s = s[1:]
   839  	}
   840  	se := s
   841  
   842  	for i := cap(sch) - cap(se); i >= 0; i-- {
   843  		s = sch[i:]
   844  		if s[0].p.Mark&DELAY == 0 {
   845  			continue
   846  		}
   847  		if -cap(s) < -cap(se) {
   848  			if !conflict(&s[0], &s[1]) {
   849  				continue
   850  			}
   851  		}
   852  
   853  		var t []Sch
   854  		var j int
   855  		for j = cap(sch) - cap(s) - 1; j >= 0; j-- {
   856  			t = sch[j:]
   857  			if t[0].comp {
   858  				if s[0].p.Mark&BRANCH != 0 {
   859  					goto no2
   860  				}
   861  			}
   862  			if t[0].p.Mark&DELAY != 0 {
   863  				if -cap(s) >= -cap(se) || conflict(&t[0], &s[1]) {
   864  					goto no2
   865  				}
   866  			}
   867  			for u := t[1:]; -cap(u) <= -cap(s); u = u[1:] {
   868  				if c.depend(&u[0], &t[0]) {
   869  					goto no2
   870  				}
   871  			}
   872  			goto out2
   873  		no2:
   874  		}
   875  
   876  		if s[0].p.Mark&BRANCH != 0 {
   877  			s[0].nop = 1
   878  		}
   879  		continue
   880  
   881  	out2:
   882  		// t[0] is the instruction being moved to fill the delay
   883  		stmp := t[0]
   884  		copy(t[:i-j], t[1:i-j+1])
   885  		s[0] = stmp
   886  
   887  		if t[i-j-1].p.Mark&BRANCH != 0 {
   888  			// t[i-j] is being put into a branch delay slot
   889  			// combine its Spadj with the branch instruction
   890  			t[i-j-1].p.Spadj += t[i-j].p.Spadj
   891  			t[i-j].p.Spadj = 0
   892  		}
   893  
   894  		i--
   895  	}
   896  
   897  	/*
   898  	 * put it all back
   899  	 */
   900  	var p *obj.Prog
   901  	var q *obj.Prog
   902  	for s, p = sch[:], p0; -cap(s) <= -cap(se); s, p = s[1:], q {
   903  		q = p.Link
   904  		if q != s[0].p.Link {
   905  			*p = s[0].p
   906  			p.Link = q
   907  		}
   908  		for s[0].nop != 0 {
   909  			s[0].nop--
   910  			c.addnop(p)
   911  		}
   912  	}
   913  }
   914  
   915  func (c *ctxt0) markregused(s *Sch) {
   916  	p := &s.p
   917  	s.comp = c.compound(p)
   918  	s.nop = 0
   919  	if s.comp {
   920  		s.set.ireg |= 1 << (REGTMP - REG_R0)
   921  		s.used.ireg |= 1 << (REGTMP - REG_R0)
   922  	}
   923  
   924  	ar := 0  /* dest is really reference */
   925  	ad := 0  /* source/dest is really address */
   926  	ld := 0  /* opcode is load instruction */
   927  	sz := 20 /* size of load/store for overlap computation */
   928  
   929  	/*
   930  	 * flags based on opcode
   931  	 */
   932  	switch p.As {
   933  	case obj.ATEXT:
   934  		c.autosize = int32(p.To.Offset + 8)
   935  		ad = 1
   936  
   937  	case AJAL:
   938  		r := p.Reg
   939  		if r == 0 {
   940  			r = REGLINK
   941  		}
   942  		s.set.ireg |= 1 << uint(r-REG_R0)
   943  		ar = 1
   944  		ad = 1
   945  
   946  	case ABGEZAL,
   947  		ABLTZAL:
   948  		s.set.ireg |= 1 << (REGLINK - REG_R0)
   949  		fallthrough
   950  	case ABEQ,
   951  		ABGEZ,
   952  		ABGTZ,
   953  		ABLEZ,
   954  		ABLTZ,
   955  		ABNE:
   956  		ar = 1
   957  		ad = 1
   958  
   959  	case ABFPT,
   960  		ABFPF:
   961  		ad = 1
   962  		s.used.cc |= E_FCR
   963  
   964  	case ACMPEQD,
   965  		ACMPEQF,
   966  		ACMPGED,
   967  		ACMPGEF,
   968  		ACMPGTD,
   969  		ACMPGTF:
   970  		ar = 1
   971  		s.set.cc |= E_FCR
   972  		p.Mark |= FCMP
   973  
   974  	case AJMP:
   975  		ar = 1
   976  		ad = 1
   977  
   978  	case AMOVB,
   979  		AMOVBU:
   980  		sz = 1
   981  		ld = 1
   982  
   983  	case AMOVH,
   984  		AMOVHU:
   985  		sz = 2
   986  		ld = 1
   987  
   988  	case AMOVF,
   989  		AMOVW,
   990  		AMOVWL,
   991  		AMOVWR:
   992  		sz = 4
   993  		ld = 1
   994  
   995  	case AMOVD,
   996  		AMOVV,
   997  		AMOVVL,
   998  		AMOVVR:
   999  		sz = 8
  1000  		ld = 1
  1001  
  1002  	case ADIV,
  1003  		ADIVU,
  1004  		AMUL,
  1005  		AMULU,
  1006  		AREM,
  1007  		AREMU,
  1008  		ADIVV,
  1009  		ADIVVU,
  1010  		AMULV,
  1011  		AMULVU,
  1012  		AREMV,
  1013  		AREMVU:
  1014  		s.set.cc = E_HILO
  1015  		fallthrough
  1016  	case AADD,
  1017  		AADDU,
  1018  		AADDV,
  1019  		AADDVU,
  1020  		AAND,
  1021  		ANOR,
  1022  		AOR,
  1023  		ASGT,
  1024  		ASGTU,
  1025  		ASLL,
  1026  		ASRA,
  1027  		ASRL,
  1028  		ASLLV,
  1029  		ASRAV,
  1030  		ASRLV,
  1031  		ASUB,
  1032  		ASUBU,
  1033  		ASUBV,
  1034  		ASUBVU,
  1035  		AXOR,
  1036  
  1037  		AADDD,
  1038  		AADDF,
  1039  		AADDW,
  1040  		ASUBD,
  1041  		ASUBF,
  1042  		ASUBW,
  1043  		AMULF,
  1044  		AMULD,
  1045  		AMULW,
  1046  		ADIVF,
  1047  		ADIVD,
  1048  		ADIVW:
  1049  		if p.Reg == 0 {
  1050  			if p.To.Type == obj.TYPE_REG {
  1051  				p.Reg = p.To.Reg
  1052  			}
  1053  			//if(p->reg == NREG)
  1054  			//	print("botch %P\n", p);
  1055  		}
  1056  	}
  1057  
  1058  	/*
  1059  	 * flags based on 'to' field
  1060  	 */
  1061  	cls := int(p.To.Class)
  1062  	if cls == 0 {
  1063  		cls = c.aclass(&p.To) + 1
  1064  		p.To.Class = int8(cls)
  1065  	}
  1066  	cls--
  1067  	switch cls {
  1068  	default:
  1069  		fmt.Printf("unknown class %d %v\n", cls, p)
  1070  
  1071  	case C_ZCON,
  1072  		C_SCON,
  1073  		C_ADD0CON,
  1074  		C_AND0CON,
  1075  		C_ADDCON,
  1076  		C_ANDCON,
  1077  		C_UCON,
  1078  		C_LCON,
  1079  		C_NONE,
  1080  		C_SBRA,
  1081  		C_LBRA,
  1082  		C_ADDR,
  1083  		C_TEXTSIZE:
  1084  		break
  1085  
  1086  	case C_HI,
  1087  		C_LO:
  1088  		s.set.cc |= E_HILO
  1089  
  1090  	case C_FCREG:
  1091  		s.set.cc |= E_FCR
  1092  
  1093  	case C_MREG:
  1094  		s.set.cc |= E_MCR
  1095  
  1096  	case C_ZOREG,
  1097  		C_SOREG,
  1098  		C_LOREG:
  1099  		cls = int(p.To.Reg)
  1100  		s.used.ireg |= 1 << uint(cls-REG_R0)
  1101  		if ad != 0 {
  1102  			break
  1103  		}
  1104  		s.size = uint8(sz)
  1105  		s.soffset = c.regoff(&p.To)
  1106  
  1107  		m := uint32(ANYMEM)
  1108  		if cls == REGSB {
  1109  			m = E_MEMSB
  1110  		}
  1111  		if cls == REGSP {
  1112  			m = E_MEMSP
  1113  		}
  1114  
  1115  		if ar != 0 {
  1116  			s.used.cc |= m
  1117  		} else {
  1118  			s.set.cc |= m
  1119  		}
  1120  
  1121  	case C_SACON,
  1122  		C_LACON:
  1123  		s.used.ireg |= 1 << (REGSP - REG_R0)
  1124  
  1125  	case C_SECON,
  1126  		C_LECON:
  1127  		s.used.ireg |= 1 << (REGSB - REG_R0)
  1128  
  1129  	case C_REG:
  1130  		if ar != 0 {
  1131  			s.used.ireg |= 1 << uint(p.To.Reg-REG_R0)
  1132  		} else {
  1133  			s.set.ireg |= 1 << uint(p.To.Reg-REG_R0)
  1134  		}
  1135  
  1136  	case C_FREG:
  1137  		if ar != 0 {
  1138  			s.used.freg |= 1 << uint(p.To.Reg-REG_F0)
  1139  		} else {
  1140  			s.set.freg |= 1 << uint(p.To.Reg-REG_F0)
  1141  		}
  1142  		if ld != 0 && p.From.Type == obj.TYPE_REG {
  1143  			p.Mark |= LOAD
  1144  		}
  1145  
  1146  	case C_SAUTO,
  1147  		C_LAUTO:
  1148  		s.used.ireg |= 1 << (REGSP - REG_R0)
  1149  		if ad != 0 {
  1150  			break
  1151  		}
  1152  		s.size = uint8(sz)
  1153  		s.soffset = c.regoff(&p.To)
  1154  
  1155  		if ar != 0 {
  1156  			s.used.cc |= E_MEMSP
  1157  		} else {
  1158  			s.set.cc |= E_MEMSP
  1159  		}
  1160  
  1161  	case C_SEXT,
  1162  		C_LEXT:
  1163  		s.used.ireg |= 1 << (REGSB - REG_R0)
  1164  		if ad != 0 {
  1165  			break
  1166  		}
  1167  		s.size = uint8(sz)
  1168  		s.soffset = c.regoff(&p.To)
  1169  
  1170  		if ar != 0 {
  1171  			s.used.cc |= E_MEMSB
  1172  		} else {
  1173  			s.set.cc |= E_MEMSB
  1174  		}
  1175  	}
  1176  
  1177  	/*
  1178  	 * flags based on 'from' field
  1179  	 */
  1180  	cls = int(p.From.Class)
  1181  	if cls == 0 {
  1182  		cls = c.aclass(&p.From) + 1
  1183  		p.From.Class = int8(cls)
  1184  	}
  1185  	cls--
  1186  	switch cls {
  1187  	default:
  1188  		fmt.Printf("unknown class %d %v\n", cls, p)
  1189  
  1190  	case C_ZCON,
  1191  		C_SCON,
  1192  		C_ADD0CON,
  1193  		C_AND0CON,
  1194  		C_ADDCON,
  1195  		C_ANDCON,
  1196  		C_UCON,
  1197  		C_LCON,
  1198  		C_NONE,
  1199  		C_SBRA,
  1200  		C_LBRA,
  1201  		C_ADDR,
  1202  		C_TEXTSIZE:
  1203  		break
  1204  
  1205  	case C_HI,
  1206  		C_LO:
  1207  		s.used.cc |= E_HILO
  1208  
  1209  	case C_FCREG:
  1210  		s.used.cc |= E_FCR
  1211  
  1212  	case C_MREG:
  1213  		s.used.cc |= E_MCR
  1214  
  1215  	case C_ZOREG,
  1216  		C_SOREG,
  1217  		C_LOREG:
  1218  		cls = int(p.From.Reg)
  1219  		s.used.ireg |= 1 << uint(cls-REG_R0)
  1220  		if ld != 0 {
  1221  			p.Mark |= LOAD
  1222  		}
  1223  		s.size = uint8(sz)
  1224  		s.soffset = c.regoff(&p.From)
  1225  
  1226  		m := uint32(ANYMEM)
  1227  		if cls == REGSB {
  1228  			m = E_MEMSB
  1229  		}
  1230  		if cls == REGSP {
  1231  			m = E_MEMSP
  1232  		}
  1233  
  1234  		s.used.cc |= m
  1235  
  1236  	case C_SACON,
  1237  		C_LACON:
  1238  		cls = int(p.From.Reg)
  1239  		if cls == 0 {
  1240  			cls = REGSP
  1241  		}
  1242  		s.used.ireg |= 1 << uint(cls-REG_R0)
  1243  
  1244  	case C_SECON,
  1245  		C_LECON:
  1246  		s.used.ireg |= 1 << (REGSB - REG_R0)
  1247  
  1248  	case C_REG:
  1249  		s.used.ireg |= 1 << uint(p.From.Reg-REG_R0)
  1250  
  1251  	case C_FREG:
  1252  		s.used.freg |= 1 << uint(p.From.Reg-REG_F0)
  1253  		if ld != 0 && p.To.Type == obj.TYPE_REG {
  1254  			p.Mark |= LOAD
  1255  		}
  1256  
  1257  	case C_SAUTO,
  1258  		C_LAUTO:
  1259  		s.used.ireg |= 1 << (REGSP - REG_R0)
  1260  		if ld != 0 {
  1261  			p.Mark |= LOAD
  1262  		}
  1263  		if ad != 0 {
  1264  			break
  1265  		}
  1266  		s.size = uint8(sz)
  1267  		s.soffset = c.regoff(&p.From)
  1268  
  1269  		s.used.cc |= E_MEMSP
  1270  
  1271  	case C_SEXT:
  1272  	case C_LEXT:
  1273  		s.used.ireg |= 1 << (REGSB - REG_R0)
  1274  		if ld != 0 {
  1275  			p.Mark |= LOAD
  1276  		}
  1277  		if ad != 0 {
  1278  			break
  1279  		}
  1280  		s.size = uint8(sz)
  1281  		s.soffset = c.regoff(&p.From)
  1282  
  1283  		s.used.cc |= E_MEMSB
  1284  	}
  1285  
  1286  	cls = int(p.Reg)
  1287  	if cls != 0 {
  1288  		if REG_F0 <= cls && cls <= REG_F31 {
  1289  			s.used.freg |= 1 << uint(cls-REG_F0)
  1290  		} else {
  1291  			s.used.ireg |= 1 << uint(cls-REG_R0)
  1292  		}
  1293  	}
  1294  	s.set.ireg &^= (1 << (REGZERO - REG_R0)) /* R0 can't be set */
  1295  }
  1296  
  1297  /*
  1298   * test to see if two instructions can be
  1299   * interchanged without changing semantics
  1300   */
  1301  func (c *ctxt0) depend(sa, sb *Sch) bool {
  1302  	if sa.set.ireg&(sb.set.ireg|sb.used.ireg) != 0 {
  1303  		return true
  1304  	}
  1305  	if sb.set.ireg&sa.used.ireg != 0 {
  1306  		return true
  1307  	}
  1308  
  1309  	if sa.set.freg&(sb.set.freg|sb.used.freg) != 0 {
  1310  		return true
  1311  	}
  1312  	if sb.set.freg&sa.used.freg != 0 {
  1313  		return true
  1314  	}
  1315  
  1316  	/*
  1317  	 * special case.
  1318  	 * loads from same address cannot pass.
  1319  	 * this is for hardware fifo's and the like
  1320  	 */
  1321  	if sa.used.cc&sb.used.cc&E_MEM != 0 {
  1322  		if sa.p.Reg == sb.p.Reg {
  1323  			if c.regoff(&sa.p.From) == c.regoff(&sb.p.From) {
  1324  				return true
  1325  			}
  1326  		}
  1327  	}
  1328  
  1329  	x := (sa.set.cc & (sb.set.cc | sb.used.cc)) | (sb.set.cc & sa.used.cc)
  1330  	if x != 0 {
  1331  		/*
  1332  		 * allow SB and SP to pass each other.
  1333  		 * allow SB to pass SB iff doffsets are ok
  1334  		 * anything else conflicts
  1335  		 */
  1336  		if x != E_MEMSP && x != E_MEMSB {
  1337  			return true
  1338  		}
  1339  		x = sa.set.cc | sb.set.cc | sa.used.cc | sb.used.cc
  1340  		if x&E_MEM != 0 {
  1341  			return true
  1342  		}
  1343  		if offoverlap(sa, sb) {
  1344  			return true
  1345  		}
  1346  	}
  1347  
  1348  	return false
  1349  }
  1350  
  1351  func offoverlap(sa, sb *Sch) bool {
  1352  	if sa.soffset < sb.soffset {
  1353  		if sa.soffset+int32(sa.size) > sb.soffset {
  1354  			return true
  1355  		}
  1356  		return false
  1357  	}
  1358  	if sb.soffset+int32(sb.size) > sa.soffset {
  1359  		return true
  1360  	}
  1361  	return false
  1362  }
  1363  
  1364  /*
  1365   * test 2 adjacent instructions
  1366   * and find out if inserted instructions
  1367   * are desired to prevent stalls.
  1368   */
  1369  func conflict(sa, sb *Sch) bool {
  1370  	if sa.set.ireg&sb.used.ireg != 0 {
  1371  		return true
  1372  	}
  1373  	if sa.set.freg&sb.used.freg != 0 {
  1374  		return true
  1375  	}
  1376  	if sa.set.cc&sb.used.cc != 0 {
  1377  		return true
  1378  	}
  1379  	return false
  1380  }
  1381  
  1382  func (c *ctxt0) compound(p *obj.Prog) bool {
  1383  	o := c.oplook(p)
  1384  	if o.size != 4 {
  1385  		return true
  1386  	}
  1387  	if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSB {
  1388  		return true
  1389  	}
  1390  	return false
  1391  }
  1392  
  1393  var Linkmips64 = obj.LinkArch{
  1394  	Arch:       sys.ArchMIPS64,
  1395  	Init:       buildop,
  1396  	Preprocess: preprocess,
  1397  	Assemble:   span0,
  1398  	Progedit:   progedit,
  1399  }
  1400  
  1401  var Linkmips64le = obj.LinkArch{
  1402  	Arch:       sys.ArchMIPS64LE,
  1403  	Init:       buildop,
  1404  	Preprocess: preprocess,
  1405  	Assemble:   span0,
  1406  	Progedit:   progedit,
  1407  }
  1408  
  1409  var Linkmips = obj.LinkArch{
  1410  	Arch:       sys.ArchMIPS,
  1411  	Init:       buildop,
  1412  	Preprocess: preprocess,
  1413  	Assemble:   span0,
  1414  	Progedit:   progedit,
  1415  }
  1416  
  1417  var Linkmipsle = obj.LinkArch{
  1418  	Arch:       sys.ArchMIPSLE,
  1419  	Init:       buildop,
  1420  	Preprocess: preprocess,
  1421  	Assemble:   span0,
  1422  	Progedit:   progedit,
  1423  }