Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/internal/obj/mips/obj0.go

Documentation: cmd/internal/obj/mips

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

View as plain text