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