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