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