github.com/Filosottile/go@v0.0.0-20170906193555-dbed9972d994/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  	q.As = ANOOP
   790  	q.Pos = p.Pos
   791  	q.Link = p.Link
   792  	p.Link = q
   793  }
   794  
   795  const (
   796  	E_HILO  = 1 << 0
   797  	E_FCR   = 1 << 1
   798  	E_MCR   = 1 << 2
   799  	E_MEM   = 1 << 3
   800  	E_MEMSP = 1 << 4 /* uses offset and size */
   801  	E_MEMSB = 1 << 5 /* uses offset and size */
   802  	ANYMEM  = E_MEM | E_MEMSP | E_MEMSB
   803  	//DELAY = LOAD|BRANCH|FCMP
   804  	DELAY = BRANCH /* only schedule branch */
   805  )
   806  
   807  type Dep struct {
   808  	ireg uint32
   809  	freg uint32
   810  	cc   uint32
   811  }
   812  
   813  type Sch struct {
   814  	p       obj.Prog
   815  	set     Dep
   816  	used    Dep
   817  	soffset int32
   818  	size    uint8
   819  	nop     uint8
   820  	comp    bool
   821  }
   822  
   823  func (c *ctxt0) sched(p0, pe *obj.Prog) {
   824  	var sch [NSCHED]Sch
   825  
   826  	/*
   827  	 * build side structure
   828  	 */
   829  	s := sch[:]
   830  	for p := p0; ; p = p.Link {
   831  		s[0].p = *p
   832  		c.markregused(&s[0])
   833  		if p == pe {
   834  			break
   835  		}
   836  		s = s[1:]
   837  	}
   838  	se := s
   839  
   840  	for i := cap(sch) - cap(se); i >= 0; i-- {
   841  		s = sch[i:]
   842  		if s[0].p.Mark&DELAY == 0 {
   843  			continue
   844  		}
   845  		if -cap(s) < -cap(se) {
   846  			if !conflict(&s[0], &s[1]) {
   847  				continue
   848  			}
   849  		}
   850  
   851  		var t []Sch
   852  		var j int
   853  		for j = cap(sch) - cap(s) - 1; j >= 0; j-- {
   854  			t = sch[j:]
   855  			if t[0].comp {
   856  				if s[0].p.Mark&BRANCH != 0 {
   857  					goto no2
   858  				}
   859  			}
   860  			if t[0].p.Mark&DELAY != 0 {
   861  				if -cap(s) >= -cap(se) || conflict(&t[0], &s[1]) {
   862  					goto no2
   863  				}
   864  			}
   865  			for u := t[1:]; -cap(u) <= -cap(s); u = u[1:] {
   866  				if c.depend(&u[0], &t[0]) {
   867  					goto no2
   868  				}
   869  			}
   870  			goto out2
   871  		no2:
   872  		}
   873  
   874  		if s[0].p.Mark&BRANCH != 0 {
   875  			s[0].nop = 1
   876  		}
   877  		continue
   878  
   879  	out2:
   880  		// t[0] is the instruction being moved to fill the delay
   881  		stmp := t[0]
   882  		copy(t[:i-j], t[1:i-j+1])
   883  		s[0] = stmp
   884  
   885  		if t[i-j-1].p.Mark&BRANCH != 0 {
   886  			// t[i-j] is being put into a branch delay slot
   887  			// combine its Spadj with the branch instruction
   888  			t[i-j-1].p.Spadj += t[i-j].p.Spadj
   889  			t[i-j].p.Spadj = 0
   890  		}
   891  
   892  		i--
   893  	}
   894  
   895  	/*
   896  	 * put it all back
   897  	 */
   898  	var p *obj.Prog
   899  	var q *obj.Prog
   900  	for s, p = sch[:], p0; -cap(s) <= -cap(se); s, p = s[1:], q {
   901  		q = p.Link
   902  		if q != s[0].p.Link {
   903  			*p = s[0].p
   904  			p.Link = q
   905  		}
   906  		for s[0].nop != 0 {
   907  			s[0].nop--
   908  			c.addnop(p)
   909  		}
   910  	}
   911  }
   912  
   913  func (c *ctxt0) markregused(s *Sch) {
   914  	p := &s.p
   915  	s.comp = c.compound(p)
   916  	s.nop = 0
   917  	if s.comp {
   918  		s.set.ireg |= 1 << (REGTMP - REG_R0)
   919  		s.used.ireg |= 1 << (REGTMP - REG_R0)
   920  	}
   921  
   922  	ar := 0  /* dest is really reference */
   923  	ad := 0  /* source/dest is really address */
   924  	ld := 0  /* opcode is load instruction */
   925  	sz := 20 /* size of load/store for overlap computation */
   926  
   927  	/*
   928  	 * flags based on opcode
   929  	 */
   930  	switch p.As {
   931  	case obj.ATEXT:
   932  		c.autosize = int32(p.To.Offset + 8)
   933  		ad = 1
   934  
   935  	case AJAL:
   936  		r := p.Reg
   937  		if r == 0 {
   938  			r = REGLINK
   939  		}
   940  		s.set.ireg |= 1 << uint(r-REG_R0)
   941  		ar = 1
   942  		ad = 1
   943  
   944  	case ABGEZAL,
   945  		ABLTZAL:
   946  		s.set.ireg |= 1 << (REGLINK - REG_R0)
   947  		fallthrough
   948  	case ABEQ,
   949  		ABGEZ,
   950  		ABGTZ,
   951  		ABLEZ,
   952  		ABLTZ,
   953  		ABNE:
   954  		ar = 1
   955  		ad = 1
   956  
   957  	case ABFPT,
   958  		ABFPF:
   959  		ad = 1
   960  		s.used.cc |= E_FCR
   961  
   962  	case ACMPEQD,
   963  		ACMPEQF,
   964  		ACMPGED,
   965  		ACMPGEF,
   966  		ACMPGTD,
   967  		ACMPGTF:
   968  		ar = 1
   969  		s.set.cc |= E_FCR
   970  		p.Mark |= FCMP
   971  
   972  	case AJMP:
   973  		ar = 1
   974  		ad = 1
   975  
   976  	case AMOVB,
   977  		AMOVBU:
   978  		sz = 1
   979  		ld = 1
   980  
   981  	case AMOVH,
   982  		AMOVHU:
   983  		sz = 2
   984  		ld = 1
   985  
   986  	case AMOVF,
   987  		AMOVW,
   988  		AMOVWL,
   989  		AMOVWR:
   990  		sz = 4
   991  		ld = 1
   992  
   993  	case AMOVD,
   994  		AMOVV,
   995  		AMOVVL,
   996  		AMOVVR:
   997  		sz = 8
   998  		ld = 1
   999  
  1000  	case ADIV,
  1001  		ADIVU,
  1002  		AMUL,
  1003  		AMULU,
  1004  		AREM,
  1005  		AREMU,
  1006  		ADIVV,
  1007  		ADIVVU,
  1008  		AMULV,
  1009  		AMULVU,
  1010  		AREMV,
  1011  		AREMVU:
  1012  		s.set.cc = E_HILO
  1013  		fallthrough
  1014  	case AADD,
  1015  		AADDU,
  1016  		AADDV,
  1017  		AADDVU,
  1018  		AAND,
  1019  		ANOR,
  1020  		AOR,
  1021  		ASGT,
  1022  		ASGTU,
  1023  		ASLL,
  1024  		ASRA,
  1025  		ASRL,
  1026  		ASLLV,
  1027  		ASRAV,
  1028  		ASRLV,
  1029  		ASUB,
  1030  		ASUBU,
  1031  		ASUBV,
  1032  		ASUBVU,
  1033  		AXOR,
  1034  
  1035  		AADDD,
  1036  		AADDF,
  1037  		AADDW,
  1038  		ASUBD,
  1039  		ASUBF,
  1040  		ASUBW,
  1041  		AMULF,
  1042  		AMULD,
  1043  		AMULW,
  1044  		ADIVF,
  1045  		ADIVD,
  1046  		ADIVW:
  1047  		if p.Reg == 0 {
  1048  			if p.To.Type == obj.TYPE_REG {
  1049  				p.Reg = p.To.Reg
  1050  			}
  1051  			//if(p->reg == NREG)
  1052  			//	print("botch %P\n", p);
  1053  		}
  1054  	}
  1055  
  1056  	/*
  1057  	 * flags based on 'to' field
  1058  	 */
  1059  	cls := int(p.To.Class)
  1060  	if cls == 0 {
  1061  		cls = c.aclass(&p.To) + 1
  1062  		p.To.Class = int8(cls)
  1063  	}
  1064  	cls--
  1065  	switch cls {
  1066  	default:
  1067  		fmt.Printf("unknown class %d %v\n", cls, p)
  1068  
  1069  	case C_ZCON,
  1070  		C_SCON,
  1071  		C_ADD0CON,
  1072  		C_AND0CON,
  1073  		C_ADDCON,
  1074  		C_ANDCON,
  1075  		C_UCON,
  1076  		C_LCON,
  1077  		C_NONE,
  1078  		C_SBRA,
  1079  		C_LBRA,
  1080  		C_ADDR,
  1081  		C_TEXTSIZE:
  1082  		break
  1083  
  1084  	case C_HI,
  1085  		C_LO:
  1086  		s.set.cc |= E_HILO
  1087  
  1088  	case C_FCREG:
  1089  		s.set.cc |= E_FCR
  1090  
  1091  	case C_MREG:
  1092  		s.set.cc |= E_MCR
  1093  
  1094  	case C_ZOREG,
  1095  		C_SOREG,
  1096  		C_LOREG:
  1097  		cls = int(p.To.Reg)
  1098  		s.used.ireg |= 1 << uint(cls-REG_R0)
  1099  		if ad != 0 {
  1100  			break
  1101  		}
  1102  		s.size = uint8(sz)
  1103  		s.soffset = c.regoff(&p.To)
  1104  
  1105  		m := uint32(ANYMEM)
  1106  		if cls == REGSB {
  1107  			m = E_MEMSB
  1108  		}
  1109  		if cls == REGSP {
  1110  			m = E_MEMSP
  1111  		}
  1112  
  1113  		if ar != 0 {
  1114  			s.used.cc |= m
  1115  		} else {
  1116  			s.set.cc |= m
  1117  		}
  1118  
  1119  	case C_SACON,
  1120  		C_LACON:
  1121  		s.used.ireg |= 1 << (REGSP - REG_R0)
  1122  
  1123  	case C_SECON,
  1124  		C_LECON:
  1125  		s.used.ireg |= 1 << (REGSB - REG_R0)
  1126  
  1127  	case C_REG:
  1128  		if ar != 0 {
  1129  			s.used.ireg |= 1 << uint(p.To.Reg-REG_R0)
  1130  		} else {
  1131  			s.set.ireg |= 1 << uint(p.To.Reg-REG_R0)
  1132  		}
  1133  
  1134  	case C_FREG:
  1135  		if ar != 0 {
  1136  			s.used.freg |= 1 << uint(p.To.Reg-REG_F0)
  1137  		} else {
  1138  			s.set.freg |= 1 << uint(p.To.Reg-REG_F0)
  1139  		}
  1140  		if ld != 0 && p.From.Type == obj.TYPE_REG {
  1141  			p.Mark |= LOAD
  1142  		}
  1143  
  1144  	case C_SAUTO,
  1145  		C_LAUTO:
  1146  		s.used.ireg |= 1 << (REGSP - REG_R0)
  1147  		if ad != 0 {
  1148  			break
  1149  		}
  1150  		s.size = uint8(sz)
  1151  		s.soffset = c.regoff(&p.To)
  1152  
  1153  		if ar != 0 {
  1154  			s.used.cc |= E_MEMSP
  1155  		} else {
  1156  			s.set.cc |= E_MEMSP
  1157  		}
  1158  
  1159  	case C_SEXT,
  1160  		C_LEXT:
  1161  		s.used.ireg |= 1 << (REGSB - REG_R0)
  1162  		if ad != 0 {
  1163  			break
  1164  		}
  1165  		s.size = uint8(sz)
  1166  		s.soffset = c.regoff(&p.To)
  1167  
  1168  		if ar != 0 {
  1169  			s.used.cc |= E_MEMSB
  1170  		} else {
  1171  			s.set.cc |= E_MEMSB
  1172  		}
  1173  	}
  1174  
  1175  	/*
  1176  	 * flags based on 'from' field
  1177  	 */
  1178  	cls = int(p.From.Class)
  1179  	if cls == 0 {
  1180  		cls = c.aclass(&p.From) + 1
  1181  		p.From.Class = int8(cls)
  1182  	}
  1183  	cls--
  1184  	switch cls {
  1185  	default:
  1186  		fmt.Printf("unknown class %d %v\n", cls, p)
  1187  
  1188  	case C_ZCON,
  1189  		C_SCON,
  1190  		C_ADD0CON,
  1191  		C_AND0CON,
  1192  		C_ADDCON,
  1193  		C_ANDCON,
  1194  		C_UCON,
  1195  		C_LCON,
  1196  		C_NONE,
  1197  		C_SBRA,
  1198  		C_LBRA,
  1199  		C_ADDR,
  1200  		C_TEXTSIZE:
  1201  		break
  1202  
  1203  	case C_HI,
  1204  		C_LO:
  1205  		s.used.cc |= E_HILO
  1206  
  1207  	case C_FCREG:
  1208  		s.used.cc |= E_FCR
  1209  
  1210  	case C_MREG:
  1211  		s.used.cc |= E_MCR
  1212  
  1213  	case C_ZOREG,
  1214  		C_SOREG,
  1215  		C_LOREG:
  1216  		cls = int(p.From.Reg)
  1217  		s.used.ireg |= 1 << uint(cls-REG_R0)
  1218  		if ld != 0 {
  1219  			p.Mark |= LOAD
  1220  		}
  1221  		s.size = uint8(sz)
  1222  		s.soffset = c.regoff(&p.From)
  1223  
  1224  		m := uint32(ANYMEM)
  1225  		if cls == REGSB {
  1226  			m = E_MEMSB
  1227  		}
  1228  		if cls == REGSP {
  1229  			m = E_MEMSP
  1230  		}
  1231  
  1232  		s.used.cc |= m
  1233  
  1234  	case C_SACON,
  1235  		C_LACON:
  1236  		cls = int(p.From.Reg)
  1237  		if cls == 0 {
  1238  			cls = REGSP
  1239  		}
  1240  		s.used.ireg |= 1 << uint(cls-REG_R0)
  1241  
  1242  	case C_SECON,
  1243  		C_LECON:
  1244  		s.used.ireg |= 1 << (REGSB - REG_R0)
  1245  
  1246  	case C_REG:
  1247  		s.used.ireg |= 1 << uint(p.From.Reg-REG_R0)
  1248  
  1249  	case C_FREG:
  1250  		s.used.freg |= 1 << uint(p.From.Reg-REG_F0)
  1251  		if ld != 0 && p.To.Type == obj.TYPE_REG {
  1252  			p.Mark |= LOAD
  1253  		}
  1254  
  1255  	case C_SAUTO,
  1256  		C_LAUTO:
  1257  		s.used.ireg |= 1 << (REGSP - REG_R0)
  1258  		if ld != 0 {
  1259  			p.Mark |= LOAD
  1260  		}
  1261  		if ad != 0 {
  1262  			break
  1263  		}
  1264  		s.size = uint8(sz)
  1265  		s.soffset = c.regoff(&p.From)
  1266  
  1267  		s.used.cc |= E_MEMSP
  1268  
  1269  	case C_SEXT:
  1270  	case C_LEXT:
  1271  		s.used.ireg |= 1 << (REGSB - 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_MEMSB
  1282  	}
  1283  
  1284  	cls = int(p.Reg)
  1285  	if cls != 0 {
  1286  		if REG_F0 <= cls && cls <= REG_F31 {
  1287  			s.used.freg |= 1 << uint(cls-REG_F0)
  1288  		} else {
  1289  			s.used.ireg |= 1 << uint(cls-REG_R0)
  1290  		}
  1291  	}
  1292  	s.set.ireg &^= (1 << (REGZERO - REG_R0)) /* R0 can't be set */
  1293  }
  1294  
  1295  /*
  1296   * test to see if two instructions can be
  1297   * interchanged without changing semantics
  1298   */
  1299  func (c *ctxt0) depend(sa, sb *Sch) bool {
  1300  	if sa.set.ireg&(sb.set.ireg|sb.used.ireg) != 0 {
  1301  		return true
  1302  	}
  1303  	if sb.set.ireg&sa.used.ireg != 0 {
  1304  		return true
  1305  	}
  1306  
  1307  	if sa.set.freg&(sb.set.freg|sb.used.freg) != 0 {
  1308  		return true
  1309  	}
  1310  	if sb.set.freg&sa.used.freg != 0 {
  1311  		return true
  1312  	}
  1313  
  1314  	/*
  1315  	 * special case.
  1316  	 * loads from same address cannot pass.
  1317  	 * this is for hardware fifo's and the like
  1318  	 */
  1319  	if sa.used.cc&sb.used.cc&E_MEM != 0 {
  1320  		if sa.p.Reg == sb.p.Reg {
  1321  			if c.regoff(&sa.p.From) == c.regoff(&sb.p.From) {
  1322  				return true
  1323  			}
  1324  		}
  1325  	}
  1326  
  1327  	x := (sa.set.cc & (sb.set.cc | sb.used.cc)) | (sb.set.cc & sa.used.cc)
  1328  	if x != 0 {
  1329  		/*
  1330  		 * allow SB and SP to pass each other.
  1331  		 * allow SB to pass SB iff doffsets are ok
  1332  		 * anything else conflicts
  1333  		 */
  1334  		if x != E_MEMSP && x != E_MEMSB {
  1335  			return true
  1336  		}
  1337  		x = sa.set.cc | sb.set.cc | sa.used.cc | sb.used.cc
  1338  		if x&E_MEM != 0 {
  1339  			return true
  1340  		}
  1341  		if offoverlap(sa, sb) {
  1342  			return true
  1343  		}
  1344  	}
  1345  
  1346  	return false
  1347  }
  1348  
  1349  func offoverlap(sa, sb *Sch) bool {
  1350  	if sa.soffset < sb.soffset {
  1351  		if sa.soffset+int32(sa.size) > sb.soffset {
  1352  			return true
  1353  		}
  1354  		return false
  1355  	}
  1356  	if sb.soffset+int32(sb.size) > sa.soffset {
  1357  		return true
  1358  	}
  1359  	return false
  1360  }
  1361  
  1362  /*
  1363   * test 2 adjacent instructions
  1364   * and find out if inserted instructions
  1365   * are desired to prevent stalls.
  1366   */
  1367  func conflict(sa, sb *Sch) bool {
  1368  	if sa.set.ireg&sb.used.ireg != 0 {
  1369  		return true
  1370  	}
  1371  	if sa.set.freg&sb.used.freg != 0 {
  1372  		return true
  1373  	}
  1374  	if sa.set.cc&sb.used.cc != 0 {
  1375  		return true
  1376  	}
  1377  	return false
  1378  }
  1379  
  1380  func (c *ctxt0) compound(p *obj.Prog) bool {
  1381  	o := c.oplook(p)
  1382  	if o.size != 4 {
  1383  		return true
  1384  	}
  1385  	if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSB {
  1386  		return true
  1387  	}
  1388  	return false
  1389  }
  1390  
  1391  var Linkmips64 = obj.LinkArch{
  1392  	Arch:       sys.ArchMIPS64,
  1393  	Init:       buildop,
  1394  	Preprocess: preprocess,
  1395  	Assemble:   span0,
  1396  	Progedit:   progedit,
  1397  }
  1398  
  1399  var Linkmips64le = obj.LinkArch{
  1400  	Arch:       sys.ArchMIPS64LE,
  1401  	Init:       buildop,
  1402  	Preprocess: preprocess,
  1403  	Assemble:   span0,
  1404  	Progedit:   progedit,
  1405  }
  1406  
  1407  var Linkmips = obj.LinkArch{
  1408  	Arch:       sys.ArchMIPS,
  1409  	Init:       buildop,
  1410  	Preprocess: preprocess,
  1411  	Assemble:   span0,
  1412  	Progedit:   progedit,
  1413  }
  1414  
  1415  var Linkmipsle = obj.LinkArch{
  1416  	Arch:       sys.ArchMIPSLE,
  1417  	Init:       buildop,
  1418  	Preprocess: preprocess,
  1419  	Assemble:   span0,
  1420  	Progedit:   progedit,
  1421  }