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

     1  // cmd/9l/noop.c, cmd/9l/pass.c, cmd/9l/span.c from Vita Nuova.
     2  //
     3  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     4  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     5  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     6  //	Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
     7  //	Portions Copyright © 2004,2006 Bruce Ellis
     8  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
     9  //	Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
    10  //	Portions Copyright © 2009 The Go Authors. All rights reserved.
    11  //
    12  // Permission is hereby granted, free of charge, to any person obtaining a copy
    13  // of this software and associated documentation files (the "Software"), to deal
    14  // in the Software without restriction, including without limitation the rights
    15  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    16  // copies of the Software, and to permit persons to whom the Software is
    17  // furnished to do so, subject to the following conditions:
    18  //
    19  // The above copyright notice and this permission notice shall be included in
    20  // all copies or substantial portions of the Software.
    21  //
    22  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    23  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    24  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    25  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    26  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    27  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    28  // THE SOFTWARE.
    29  
    30  package mips
    31  
    32  import (
    33  	"cmd/internal/obj"
    34  	"cmd/internal/sys"
    35  	"encoding/binary"
    36  	"fmt"
    37  	"internal/abi"
    38  	"log"
    39  	"math"
    40  )
    41  
    42  func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
    43  	c := ctxt0{ctxt: ctxt}
    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.Arch.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  	for p := c.cursym.Func().Text; p != nil; p = p.Link {
   271  		o := p.As
   272  		switch o {
   273  		case obj.ATEXT:
   274  			autosize = int32(textstksiz)
   275  
   276  			if p.Mark&LEAF != 0 && autosize == 0 {
   277  				// A leaf function with no locals has no frame.
   278  				p.From.Sym.Set(obj.AttrNoFrame, true)
   279  			}
   280  
   281  			if !p.From.Sym.NoFrame() {
   282  				// If there is a stack frame at all, it includes
   283  				// space to save the LR.
   284  				autosize += int32(c.ctxt.Arch.FixedFrameSize)
   285  			}
   286  
   287  			if autosize&4 != 0 && c.ctxt.Arch.Family == sys.MIPS64 {
   288  				autosize += 4
   289  			}
   290  
   291  			if autosize == 0 && c.cursym.Func().Text.Mark&LEAF == 0 {
   292  				if c.cursym.Func().Text.From.Sym.NoSplit() {
   293  					if ctxt.Debugvlog {
   294  						ctxt.Logf("save suppressed in: %s\n", c.cursym.Name)
   295  					}
   296  
   297  					c.cursym.Func().Text.Mark |= LEAF
   298  				}
   299  			}
   300  
   301  			p.To.Offset = int64(autosize) - ctxt.Arch.FixedFrameSize
   302  
   303  			if c.cursym.Func().Text.Mark&LEAF != 0 {
   304  				c.cursym.Set(obj.AttrLeaf, true)
   305  				if p.From.Sym.NoFrame() {
   306  					break
   307  				}
   308  			}
   309  
   310  			if !p.From.Sym.NoSplit() {
   311  				p = c.stacksplit(p, autosize) // emit split check
   312  			}
   313  
   314  			q = p
   315  
   316  			if autosize != 0 {
   317  				// Make sure to save link register for non-empty frame, even if
   318  				// it is a leaf function, so that traceback works.
   319  				// Store link register before decrement SP, so if a signal comes
   320  				// during the execution of the function prologue, the traceback
   321  				// code will not see a half-updated stack frame.
   322  				// This sequence is not async preemptible, as if we open a frame
   323  				// at the current SP, it will clobber the saved LR.
   324  				q = c.ctxt.StartUnsafePoint(q, c.newprog)
   325  
   326  				q = obj.Appendp(q, newprog)
   327  				q.As = mov
   328  				q.Pos = p.Pos
   329  				q.From.Type = obj.TYPE_REG
   330  				q.From.Reg = REGLINK
   331  				q.To.Type = obj.TYPE_MEM
   332  				q.To.Offset = int64(-autosize)
   333  				q.To.Reg = REGSP
   334  
   335  				q = obj.Appendp(q, newprog)
   336  				q.As = add
   337  				q.Pos = p.Pos
   338  				q.From.Type = obj.TYPE_CONST
   339  				q.From.Offset = int64(-autosize)
   340  				q.To.Type = obj.TYPE_REG
   341  				q.To.Reg = REGSP
   342  				q.Spadj = +autosize
   343  
   344  				q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
   345  
   346  				// On Linux, in a cgo binary we may get a SIGSETXID signal early on
   347  				// before the signal stack is set, as glibc doesn't allow us to block
   348  				// SIGSETXID. So a signal may land on the current stack and clobber
   349  				// the content below the SP. We store the LR again after the SP is
   350  				// decremented.
   351  				q = obj.Appendp(q, newprog)
   352  				q.As = mov
   353  				q.Pos = p.Pos
   354  				q.From.Type = obj.TYPE_REG
   355  				q.From.Reg = REGLINK
   356  				q.To.Type = obj.TYPE_MEM
   357  				q.To.Offset = 0
   358  				q.To.Reg = REGSP
   359  			}
   360  
   361  		case ARET:
   362  			if p.From.Type == obj.TYPE_CONST {
   363  				ctxt.Diag("using BECOME (%v) is not supported!", p)
   364  				break
   365  			}
   366  
   367  			retSym, retReg := p.To.Sym, p.To.Reg
   368  			if retReg == obj.REG_NONE {
   369  				retReg = REGLINK
   370  			}
   371  			p.To.Name = obj.NAME_NONE // clear fields as we may modify p to other instruction
   372  			p.To.Sym = nil
   373  			p.To.Reg = obj.REG_NONE
   374  
   375  			if c.cursym.Func().Text.Mark&LEAF != 0 {
   376  				if autosize == 0 {
   377  					p.As = AJMP
   378  					p.From = obj.Addr{}
   379  					if retSym != nil { // retjmp
   380  						p.To.Type = obj.TYPE_BRANCH
   381  						p.To.Name = obj.NAME_EXTERN
   382  						p.To.Sym = retSym
   383  					} else {
   384  						p.To.Type = obj.TYPE_MEM
   385  						p.To.Reg = retReg
   386  						p.To.Offset = 0
   387  					}
   388  					p.Mark |= BRANCH
   389  					break
   390  				}
   391  
   392  				p.As = add
   393  				p.From.Type = obj.TYPE_CONST
   394  				p.From.Offset = int64(autosize)
   395  				p.To.Type = obj.TYPE_REG
   396  				p.To.Reg = REGSP
   397  				p.Spadj = -autosize
   398  
   399  				q = c.newprog()
   400  				q.As = AJMP
   401  				q.Pos = p.Pos
   402  				if retSym != nil { // retjmp
   403  					q.To.Type = obj.TYPE_BRANCH
   404  					q.To.Name = obj.NAME_EXTERN
   405  					q.To.Sym = retSym
   406  				} else {
   407  					q.To.Type = obj.TYPE_MEM
   408  					q.To.Reg = retReg
   409  					q.To.Offset = 0
   410  				}
   411  				q.Mark |= BRANCH
   412  				q.Spadj = +autosize
   413  
   414  				q.Link = p.Link
   415  				p.Link = q
   416  				break
   417  			}
   418  
   419  			p.As = mov
   420  			p.From.Type = obj.TYPE_MEM
   421  			p.From.Offset = 0
   422  			p.From.Reg = REGSP
   423  			p.To.Type = obj.TYPE_REG
   424  			p.To.Reg = REGLINK
   425  
   426  			if autosize != 0 {
   427  				q = c.newprog()
   428  				q.As = add
   429  				q.Pos = p.Pos
   430  				q.From.Type = obj.TYPE_CONST
   431  				q.From.Offset = int64(autosize)
   432  				q.To.Type = obj.TYPE_REG
   433  				q.To.Reg = REGSP
   434  				q.Spadj = -autosize
   435  
   436  				q.Link = p.Link
   437  				p.Link = q
   438  			}
   439  
   440  			q1 = c.newprog()
   441  			q1.As = AJMP
   442  			q1.Pos = p.Pos
   443  			if retSym != nil { // retjmp
   444  				q1.To.Type = obj.TYPE_BRANCH
   445  				q1.To.Name = obj.NAME_EXTERN
   446  				q1.To.Sym = retSym
   447  			} else {
   448  				q1.To.Type = obj.TYPE_MEM
   449  				q1.To.Offset = 0
   450  				q1.To.Reg = retReg
   451  			}
   452  			q1.Mark |= BRANCH
   453  			q1.Spadj = +autosize
   454  
   455  			q1.Link = q.Link
   456  			q.Link = q1
   457  
   458  		case AADD,
   459  			AADDU,
   460  			AADDV,
   461  			AADDVU:
   462  			if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
   463  				p.Spadj = int32(-p.From.Offset)
   464  			}
   465  
   466  		case obj.AGETCALLERPC:
   467  			if cursym.Leaf() {
   468  				/* MOV LR, Rd */
   469  				p.As = mov
   470  				p.From.Type = obj.TYPE_REG
   471  				p.From.Reg = REGLINK
   472  			} else {
   473  				/* MOV (RSP), Rd */
   474  				p.As = mov
   475  				p.From.Type = obj.TYPE_MEM
   476  				p.From.Reg = REGSP
   477  			}
   478  		}
   479  
   480  		if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
   481  			f := c.cursym.Func()
   482  			if f.FuncFlag&abi.FuncFlagSPWrite == 0 {
   483  				c.cursym.Func().FuncFlag |= abi.FuncFlagSPWrite
   484  				if ctxt.Debugvlog || !ctxt.IsAsm {
   485  					ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
   486  					if !ctxt.IsAsm {
   487  						ctxt.Diag("invalid auto-SPWRITE in non-assembly")
   488  						ctxt.DiagFlush()
   489  						log.Fatalf("bad SPWRITE")
   490  					}
   491  				}
   492  			}
   493  		}
   494  	}
   495  
   496  	if c.ctxt.Arch.Family == sys.MIPS {
   497  		// rewrite MOVD into two MOVF in 32-bit mode to avoid unaligned memory access
   498  		for p = c.cursym.Func().Text; p != nil; p = p1 {
   499  			p1 = p.Link
   500  
   501  			if p.As != AMOVD {
   502  				continue
   503  			}
   504  			if p.From.Type != obj.TYPE_MEM && p.To.Type != obj.TYPE_MEM {
   505  				continue
   506  			}
   507  
   508  			p.As = AMOVF
   509  			q = c.newprog()
   510  			*q = *p
   511  			q.Link = p.Link
   512  			p.Link = q
   513  			p1 = q.Link
   514  
   515  			var addrOff int64
   516  			if c.ctxt.Arch.ByteOrder == binary.BigEndian {
   517  				addrOff = 4 // swap load/save order
   518  			}
   519  			if p.From.Type == obj.TYPE_MEM {
   520  				reg := REG_F0 + (p.To.Reg-REG_F0)&^1
   521  				p.To.Reg = reg
   522  				q.To.Reg = reg + 1
   523  				p.From.Offset += addrOff
   524  				q.From.Offset += 4 - addrOff
   525  			} else if p.To.Type == obj.TYPE_MEM {
   526  				reg := REG_F0 + (p.From.Reg-REG_F0)&^1
   527  				p.From.Reg = reg
   528  				q.From.Reg = reg + 1
   529  				p.To.Offset += addrOff
   530  				q.To.Offset += 4 - addrOff
   531  			}
   532  		}
   533  	}
   534  
   535  	if nosched {
   536  		// if we don't do instruction scheduling, simply add
   537  		// NOP after each branch instruction.
   538  		for p = c.cursym.Func().Text; p != nil; p = p.Link {
   539  			if p.Mark&BRANCH != 0 {
   540  				c.addnop(p)
   541  			}
   542  		}
   543  		return
   544  	}
   545  
   546  	// instruction scheduling
   547  	q = nil                   // p - 1
   548  	q1 = c.cursym.Func().Text // top of block
   549  	o := 0                    // count of instructions
   550  	for p = c.cursym.Func().Text; p != nil; p = p1 {
   551  		p1 = p.Link
   552  		o++
   553  		if p.Mark&NOSCHED != 0 {
   554  			if q1 != p {
   555  				c.sched(q1, q)
   556  			}
   557  			for ; p != nil; p = p.Link {
   558  				if p.Mark&NOSCHED == 0 {
   559  					break
   560  				}
   561  				q = p
   562  			}
   563  			p1 = p
   564  			q1 = p
   565  			o = 0
   566  			continue
   567  		}
   568  		if p.Mark&(LABEL|SYNC) != 0 {
   569  			if q1 != p {
   570  				c.sched(q1, q)
   571  			}
   572  			q1 = p
   573  			o = 1
   574  		}
   575  		if p.Mark&(BRANCH|SYNC) != 0 {
   576  			c.sched(q1, p)
   577  			q1 = p1
   578  			o = 0
   579  		}
   580  		if o >= NSCHED {
   581  			c.sched(q1, p)
   582  			q1 = p1
   583  			o = 0
   584  		}
   585  		q = p
   586  	}
   587  }
   588  
   589  func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
   590  	var mov, add obj.As
   591  
   592  	if c.ctxt.Arch.Family == sys.MIPS64 {
   593  		add = AADDV
   594  		mov = AMOVV
   595  	} else {
   596  		add = AADDU
   597  		mov = AMOVW
   598  	}
   599  
   600  	if c.ctxt.Flag_maymorestack != "" {
   601  		// Save LR and REGCTXT.
   602  		frameSize := 2 * c.ctxt.Arch.PtrSize
   603  
   604  		p = c.ctxt.StartUnsafePoint(p, c.newprog)
   605  
   606  		// MOV	REGLINK, -8/-16(SP)
   607  		p = obj.Appendp(p, c.newprog)
   608  		p.As = mov
   609  		p.From.Type = obj.TYPE_REG
   610  		p.From.Reg = REGLINK
   611  		p.To.Type = obj.TYPE_MEM
   612  		p.To.Offset = int64(-frameSize)
   613  		p.To.Reg = REGSP
   614  
   615  		// MOV	REGCTXT, -4/-8(SP)
   616  		p = obj.Appendp(p, c.newprog)
   617  		p.As = mov
   618  		p.From.Type = obj.TYPE_REG
   619  		p.From.Reg = REGCTXT
   620  		p.To.Type = obj.TYPE_MEM
   621  		p.To.Offset = -int64(c.ctxt.Arch.PtrSize)
   622  		p.To.Reg = REGSP
   623  
   624  		// ADD	$-8/$-16, SP
   625  		p = obj.Appendp(p, c.newprog)
   626  		p.As = add
   627  		p.From.Type = obj.TYPE_CONST
   628  		p.From.Offset = int64(-frameSize)
   629  		p.To.Type = obj.TYPE_REG
   630  		p.To.Reg = REGSP
   631  		p.Spadj = int32(frameSize)
   632  
   633  		// JAL	maymorestack
   634  		p = obj.Appendp(p, c.newprog)
   635  		p.As = AJAL
   636  		p.To.Type = obj.TYPE_BRANCH
   637  		// See ../x86/obj6.go
   638  		p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
   639  		p.Mark |= BRANCH
   640  
   641  		// Restore LR and REGCTXT.
   642  
   643  		// MOV	0(SP), REGLINK
   644  		p = obj.Appendp(p, c.newprog)
   645  		p.As = mov
   646  		p.From.Type = obj.TYPE_MEM
   647  		p.From.Offset = 0
   648  		p.From.Reg = REGSP
   649  		p.To.Type = obj.TYPE_REG
   650  		p.To.Reg = REGLINK
   651  
   652  		// MOV	4/8(SP), REGCTXT
   653  		p = obj.Appendp(p, c.newprog)
   654  		p.As = mov
   655  		p.From.Type = obj.TYPE_MEM
   656  		p.From.Offset = int64(c.ctxt.Arch.PtrSize)
   657  		p.From.Reg = REGSP
   658  		p.To.Type = obj.TYPE_REG
   659  		p.To.Reg = REGCTXT
   660  
   661  		// ADD	$8/$16, SP
   662  		p = obj.Appendp(p, c.newprog)
   663  		p.As = add
   664  		p.From.Type = obj.TYPE_CONST
   665  		p.From.Offset = int64(frameSize)
   666  		p.To.Type = obj.TYPE_REG
   667  		p.To.Reg = REGSP
   668  		p.Spadj = int32(-frameSize)
   669  
   670  		p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
   671  	}
   672  
   673  	// Jump back to here after morestack returns.
   674  	startPred := p
   675  
   676  	// MOV	g_stackguard(g), R1
   677  	p = obj.Appendp(p, c.newprog)
   678  
   679  	p.As = mov
   680  	p.From.Type = obj.TYPE_MEM
   681  	p.From.Reg = REGG
   682  	p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
   683  	if c.cursym.CFunc() {
   684  		p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
   685  	}
   686  	p.To.Type = obj.TYPE_REG
   687  	p.To.Reg = REG_R1
   688  
   689  	// Mark the stack bound check and morestack call async nonpreemptible.
   690  	// If we get preempted here, when resumed the preemption request is
   691  	// cleared, but we'll still call morestack, which will double the stack
   692  	// unnecessarily. See issue #35470.
   693  	p = c.ctxt.StartUnsafePoint(p, c.newprog)
   694  
   695  	var q *obj.Prog
   696  	if framesize <= abi.StackSmall {
   697  		// small stack: SP < stackguard
   698  		//	AGTU	SP, stackguard, R1
   699  		p = obj.Appendp(p, c.newprog)
   700  
   701  		p.As = ASGTU
   702  		p.From.Type = obj.TYPE_REG
   703  		p.From.Reg = REGSP
   704  		p.Reg = REG_R1
   705  		p.To.Type = obj.TYPE_REG
   706  		p.To.Reg = REG_R1
   707  	} else {
   708  		// large stack: SP-framesize < stackguard-StackSmall
   709  		offset := int64(framesize) - abi.StackSmall
   710  		if framesize > abi.StackBig {
   711  			// Such a large stack we need to protect against underflow.
   712  			// The runtime guarantees SP > objabi.StackBig, but
   713  			// framesize is large enough that SP-framesize may
   714  			// underflow, causing a direct comparison with the
   715  			// stack guard to incorrectly succeed. We explicitly
   716  			// guard against underflow.
   717  			//
   718  			//	SGTU	$(framesize-StackSmall), SP, R2
   719  			//	BNE	R2, label-of-call-to-morestack
   720  
   721  			p = obj.Appendp(p, c.newprog)
   722  			p.As = ASGTU
   723  			p.From.Type = obj.TYPE_CONST
   724  			p.From.Offset = offset
   725  			p.Reg = REGSP
   726  			p.To.Type = obj.TYPE_REG
   727  			p.To.Reg = REG_R2
   728  
   729  			p = obj.Appendp(p, c.newprog)
   730  			q = p
   731  			p.As = ABNE
   732  			p.From.Type = obj.TYPE_REG
   733  			p.From.Reg = REG_R2
   734  			p.To.Type = obj.TYPE_BRANCH
   735  			p.Mark |= BRANCH
   736  		}
   737  
   738  		// Check against the stack guard. We've ensured this won't underflow.
   739  		//	ADD	$-(framesize-StackSmall), SP, R2
   740  		//	SGTU	R2, stackguard, R1
   741  		p = obj.Appendp(p, c.newprog)
   742  
   743  		p.As = add
   744  		p.From.Type = obj.TYPE_CONST
   745  		p.From.Offset = -offset
   746  		p.Reg = REGSP
   747  		p.To.Type = obj.TYPE_REG
   748  		p.To.Reg = REG_R2
   749  
   750  		p = obj.Appendp(p, c.newprog)
   751  		p.As = ASGTU
   752  		p.From.Type = obj.TYPE_REG
   753  		p.From.Reg = REG_R2
   754  		p.Reg = REG_R1
   755  		p.To.Type = obj.TYPE_REG
   756  		p.To.Reg = REG_R1
   757  	}
   758  
   759  	// q1: BNE	R1, done
   760  	p = obj.Appendp(p, c.newprog)
   761  	q1 := p
   762  
   763  	p.As = ABNE
   764  	p.From.Type = obj.TYPE_REG
   765  	p.From.Reg = REG_R1
   766  	p.To.Type = obj.TYPE_BRANCH
   767  	p.Mark |= BRANCH
   768  
   769  	// MOV	LINK, R3
   770  	p = obj.Appendp(p, c.newprog)
   771  
   772  	p.As = mov
   773  	p.From.Type = obj.TYPE_REG
   774  	p.From.Reg = REGLINK
   775  	p.To.Type = obj.TYPE_REG
   776  	p.To.Reg = REG_R3
   777  	if q != nil {
   778  		q.To.SetTarget(p)
   779  		p.Mark |= LABEL
   780  	}
   781  
   782  	p = c.ctxt.EmitEntryStackMap(c.cursym, p, c.newprog)
   783  
   784  	// JAL	runtime.morestack(SB)
   785  	p = obj.Appendp(p, c.newprog)
   786  
   787  	p.As = AJAL
   788  	p.To.Type = obj.TYPE_BRANCH
   789  	if c.cursym.CFunc() {
   790  		p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
   791  	} else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
   792  		p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
   793  	} else {
   794  		p.To.Sym = c.ctxt.Lookup("runtime.morestack")
   795  	}
   796  	p.Mark |= BRANCH
   797  
   798  	p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
   799  
   800  	// JMP	start
   801  	p = obj.Appendp(p, c.newprog)
   802  
   803  	p.As = AJMP
   804  	p.To.Type = obj.TYPE_BRANCH
   805  	p.To.SetTarget(startPred.Link)
   806  	startPred.Link.Mark |= LABEL
   807  	p.Mark |= BRANCH
   808  
   809  	// placeholder for q1's jump target
   810  	p = obj.Appendp(p, c.newprog)
   811  
   812  	p.As = obj.ANOP // zero-width place holder
   813  	q1.To.SetTarget(p)
   814  
   815  	return p
   816  }
   817  
   818  func (c *ctxt0) addnop(p *obj.Prog) {
   819  	q := c.newprog()
   820  	q.As = ANOOP
   821  	q.Pos = p.Pos
   822  	q.Link = p.Link
   823  	p.Link = q
   824  }
   825  
   826  const (
   827  	E_HILO  = 1 << 0
   828  	E_FCR   = 1 << 1
   829  	E_MCR   = 1 << 2
   830  	E_MEM   = 1 << 3
   831  	E_MEMSP = 1 << 4 /* uses offset and size */
   832  	E_MEMSB = 1 << 5 /* uses offset and size */
   833  	ANYMEM  = E_MEM | E_MEMSP | E_MEMSB
   834  	//DELAY = LOAD|BRANCH|FCMP
   835  	DELAY = BRANCH /* only schedule branch */
   836  )
   837  
   838  type Dep struct {
   839  	ireg uint32
   840  	freg uint32
   841  	cc   uint32
   842  }
   843  
   844  type Sch struct {
   845  	p       obj.Prog
   846  	set     Dep
   847  	used    Dep
   848  	soffset int32
   849  	size    uint8
   850  	nop     uint8
   851  	comp    bool
   852  }
   853  
   854  func (c *ctxt0) sched(p0, pe *obj.Prog) {
   855  	var sch [NSCHED]Sch
   856  
   857  	/*
   858  	 * build side structure
   859  	 */
   860  	s := sch[:]
   861  	for p := p0; ; p = p.Link {
   862  		s[0].p = *p
   863  		c.markregused(&s[0])
   864  		if p == pe {
   865  			break
   866  		}
   867  		s = s[1:]
   868  	}
   869  	se := s
   870  
   871  	for i := cap(sch) - cap(se); i >= 0; i-- {
   872  		s = sch[i:]
   873  		if s[0].p.Mark&DELAY == 0 {
   874  			continue
   875  		}
   876  		if -cap(s) < -cap(se) {
   877  			if !conflict(&s[0], &s[1]) {
   878  				continue
   879  			}
   880  		}
   881  
   882  		var t []Sch
   883  		var j int
   884  		for j = cap(sch) - cap(s) - 1; j >= 0; j-- {
   885  			t = sch[j:]
   886  			if t[0].comp {
   887  				if s[0].p.Mark&BRANCH != 0 {
   888  					continue
   889  				}
   890  			}
   891  			if t[0].p.Mark&DELAY != 0 {
   892  				if -cap(s) >= -cap(se) || conflict(&t[0], &s[1]) {
   893  					continue
   894  				}
   895  			}
   896  			for u := t[1:]; -cap(u) <= -cap(s); u = u[1:] {
   897  				if c.depend(&u[0], &t[0]) {
   898  					continue
   899  				}
   900  			}
   901  			goto out2
   902  		}
   903  
   904  		if s[0].p.Mark&BRANCH != 0 {
   905  			s[0].nop = 1
   906  		}
   907  		continue
   908  
   909  	out2:
   910  		// t[0] is the instruction being moved to fill the delay
   911  		stmp := t[0]
   912  		copy(t[:i-j], t[1:i-j+1])
   913  		s[0] = stmp
   914  
   915  		if t[i-j-1].p.Mark&BRANCH != 0 {
   916  			// t[i-j] is being put into a branch delay slot
   917  			// combine its Spadj with the branch instruction
   918  			t[i-j-1].p.Spadj += t[i-j].p.Spadj
   919  			t[i-j].p.Spadj = 0
   920  		}
   921  
   922  		i--
   923  	}
   924  
   925  	/*
   926  	 * put it all back
   927  	 */
   928  	var p *obj.Prog
   929  	var q *obj.Prog
   930  	for s, p = sch[:], p0; -cap(s) <= -cap(se); s, p = s[1:], q {
   931  		q = p.Link
   932  		if q != s[0].p.Link {
   933  			*p = s[0].p
   934  			p.Link = q
   935  		}
   936  		for s[0].nop != 0 {
   937  			s[0].nop--
   938  			c.addnop(p)
   939  		}
   940  	}
   941  }
   942  
   943  func (c *ctxt0) markregused(s *Sch) {
   944  	p := &s.p
   945  	s.comp = c.compound(p)
   946  	s.nop = 0
   947  	if s.comp {
   948  		s.set.ireg |= 1 << (REGTMP - REG_R0)
   949  		s.used.ireg |= 1 << (REGTMP - REG_R0)
   950  	}
   951  
   952  	ar := 0  /* dest is really reference */
   953  	ad := 0  /* source/dest is really address */
   954  	ld := 0  /* opcode is load instruction */
   955  	sz := 20 /* size of load/store for overlap computation */
   956  
   957  	/*
   958  	 * flags based on opcode
   959  	 */
   960  	switch p.As {
   961  	case obj.ATEXT:
   962  		c.autosize = int32(p.To.Offset + 8)
   963  		ad = 1
   964  
   965  	case AJAL:
   966  		r := p.Reg
   967  		if r == 0 {
   968  			r = REGLINK
   969  		}
   970  		s.set.ireg |= 1 << uint(r-REG_R0)
   971  		ar = 1
   972  		ad = 1
   973  
   974  	case ABGEZAL,
   975  		ABLTZAL:
   976  		s.set.ireg |= 1 << (REGLINK - REG_R0)
   977  		fallthrough
   978  	case ABEQ,
   979  		ABGEZ,
   980  		ABGTZ,
   981  		ABLEZ,
   982  		ABLTZ,
   983  		ABNE:
   984  		ar = 1
   985  		ad = 1
   986  
   987  	case ABFPT,
   988  		ABFPF:
   989  		ad = 1
   990  		s.used.cc |= E_FCR
   991  
   992  	case ACMPEQD,
   993  		ACMPEQF,
   994  		ACMPGED,
   995  		ACMPGEF,
   996  		ACMPGTD,
   997  		ACMPGTF:
   998  		ar = 1
   999  		s.set.cc |= E_FCR
  1000  		p.Mark |= FCMP
  1001  
  1002  	case AJMP:
  1003  		ar = 1
  1004  		ad = 1
  1005  
  1006  	case AMOVB,
  1007  		AMOVBU:
  1008  		sz = 1
  1009  		ld = 1
  1010  
  1011  	case AMOVH,
  1012  		AMOVHU:
  1013  		sz = 2
  1014  		ld = 1
  1015  
  1016  	case AMOVF,
  1017  		AMOVW,
  1018  		AMOVWL,
  1019  		AMOVWR:
  1020  		sz = 4
  1021  		ld = 1
  1022  
  1023  	case AMOVD,
  1024  		AMOVV,
  1025  		AMOVVL,
  1026  		AMOVVR:
  1027  		sz = 8
  1028  		ld = 1
  1029  
  1030  	case ADIV,
  1031  		ADIVU,
  1032  		AMUL,
  1033  		AMULU,
  1034  		AREM,
  1035  		AREMU,
  1036  		ADIVV,
  1037  		ADIVVU,
  1038  		AMULV,
  1039  		AMULVU,
  1040  		AREMV,
  1041  		AREMVU:
  1042  		s.set.cc = E_HILO
  1043  		fallthrough
  1044  	case AADD,
  1045  		AADDU,
  1046  		AADDV,
  1047  		AADDVU,
  1048  		AAND,
  1049  		ANOR,
  1050  		AOR,
  1051  		ASGT,
  1052  		ASGTU,
  1053  		ASLL,
  1054  		ASRA,
  1055  		ASRL,
  1056  		ASLLV,
  1057  		ASRAV,
  1058  		ASRLV,
  1059  		ASUB,
  1060  		ASUBU,
  1061  		ASUBV,
  1062  		ASUBVU,
  1063  		AXOR,
  1064  
  1065  		AADDD,
  1066  		AADDF,
  1067  		AADDW,
  1068  		ASUBD,
  1069  		ASUBF,
  1070  		ASUBW,
  1071  		AMULF,
  1072  		AMULD,
  1073  		AMULW,
  1074  		ADIVF,
  1075  		ADIVD,
  1076  		ADIVW:
  1077  		if p.Reg == 0 {
  1078  			if p.To.Type == obj.TYPE_REG {
  1079  				p.Reg = p.To.Reg
  1080  			}
  1081  			//if(p->reg == NREG)
  1082  			//	print("botch %P\n", p);
  1083  		}
  1084  	}
  1085  
  1086  	/*
  1087  	 * flags based on 'to' field
  1088  	 */
  1089  	cls := int(p.To.Class)
  1090  	if cls == 0 {
  1091  		cls = c.aclass(&p.To) + 1
  1092  		p.To.Class = int8(cls)
  1093  	}
  1094  	cls--
  1095  	switch cls {
  1096  	default:
  1097  		fmt.Printf("unknown class %d %v\n", cls, p)
  1098  
  1099  	case C_ZCON,
  1100  		C_SCON,
  1101  		C_ADD0CON,
  1102  		C_AND0CON,
  1103  		C_ADDCON,
  1104  		C_ANDCON,
  1105  		C_UCON,
  1106  		C_LCON,
  1107  		C_NONE,
  1108  		C_SBRA,
  1109  		C_LBRA,
  1110  		C_ADDR,
  1111  		C_TEXTSIZE:
  1112  		break
  1113  
  1114  	case C_HI,
  1115  		C_LO:
  1116  		s.set.cc |= E_HILO
  1117  
  1118  	case C_FCREG:
  1119  		s.set.cc |= E_FCR
  1120  
  1121  	case C_MREG:
  1122  		s.set.cc |= E_MCR
  1123  
  1124  	case C_ZOREG,
  1125  		C_SOREG,
  1126  		C_LOREG:
  1127  		cls = int(p.To.Reg)
  1128  		s.used.ireg |= 1 << uint(cls-REG_R0)
  1129  		if ad != 0 {
  1130  			break
  1131  		}
  1132  		s.size = uint8(sz)
  1133  		s.soffset = c.regoff(&p.To)
  1134  
  1135  		m := uint32(ANYMEM)
  1136  		if cls == REGSB {
  1137  			m = E_MEMSB
  1138  		}
  1139  		if cls == REGSP {
  1140  			m = E_MEMSP
  1141  		}
  1142  
  1143  		if ar != 0 {
  1144  			s.used.cc |= m
  1145  		} else {
  1146  			s.set.cc |= m
  1147  		}
  1148  
  1149  	case C_SACON,
  1150  		C_LACON:
  1151  		s.used.ireg |= 1 << (REGSP - REG_R0)
  1152  
  1153  	case C_SECON,
  1154  		C_LECON:
  1155  		s.used.ireg |= 1 << (REGSB - REG_R0)
  1156  
  1157  	case C_REG:
  1158  		if ar != 0 {
  1159  			s.used.ireg |= 1 << uint(p.To.Reg-REG_R0)
  1160  		} else {
  1161  			s.set.ireg |= 1 << uint(p.To.Reg-REG_R0)
  1162  		}
  1163  
  1164  	case C_FREG:
  1165  		if ar != 0 {
  1166  			s.used.freg |= 1 << uint(p.To.Reg-REG_F0)
  1167  		} else {
  1168  			s.set.freg |= 1 << uint(p.To.Reg-REG_F0)
  1169  		}
  1170  		if ld != 0 && p.From.Type == obj.TYPE_REG {
  1171  			p.Mark |= LOAD
  1172  		}
  1173  
  1174  	case C_SAUTO,
  1175  		C_LAUTO:
  1176  		s.used.ireg |= 1 << (REGSP - REG_R0)
  1177  		if ad != 0 {
  1178  			break
  1179  		}
  1180  		s.size = uint8(sz)
  1181  		s.soffset = c.regoff(&p.To)
  1182  
  1183  		if ar != 0 {
  1184  			s.used.cc |= E_MEMSP
  1185  		} else {
  1186  			s.set.cc |= E_MEMSP
  1187  		}
  1188  
  1189  	case C_SEXT,
  1190  		C_LEXT:
  1191  		s.used.ireg |= 1 << (REGSB - REG_R0)
  1192  		if ad != 0 {
  1193  			break
  1194  		}
  1195  		s.size = uint8(sz)
  1196  		s.soffset = c.regoff(&p.To)
  1197  
  1198  		if ar != 0 {
  1199  			s.used.cc |= E_MEMSB
  1200  		} else {
  1201  			s.set.cc |= E_MEMSB
  1202  		}
  1203  	}
  1204  
  1205  	/*
  1206  	 * flags based on 'from' field
  1207  	 */
  1208  	cls = int(p.From.Class)
  1209  	if cls == 0 {
  1210  		cls = c.aclass(&p.From) + 1
  1211  		p.From.Class = int8(cls)
  1212  	}
  1213  	cls--
  1214  	switch cls {
  1215  	default:
  1216  		fmt.Printf("unknown class %d %v\n", cls, p)
  1217  
  1218  	case C_ZCON,
  1219  		C_SCON,
  1220  		C_ADD0CON,
  1221  		C_AND0CON,
  1222  		C_ADDCON,
  1223  		C_ANDCON,
  1224  		C_UCON,
  1225  		C_LCON,
  1226  		C_NONE,
  1227  		C_SBRA,
  1228  		C_LBRA,
  1229  		C_ADDR,
  1230  		C_TEXTSIZE:
  1231  		break
  1232  
  1233  	case C_HI,
  1234  		C_LO:
  1235  		s.used.cc |= E_HILO
  1236  
  1237  	case C_FCREG:
  1238  		s.used.cc |= E_FCR
  1239  
  1240  	case C_MREG:
  1241  		s.used.cc |= E_MCR
  1242  
  1243  	case C_ZOREG,
  1244  		C_SOREG,
  1245  		C_LOREG:
  1246  		cls = int(p.From.Reg)
  1247  		s.used.ireg |= 1 << uint(cls-REG_R0)
  1248  		if ld != 0 {
  1249  			p.Mark |= LOAD
  1250  		}
  1251  		s.size = uint8(sz)
  1252  		s.soffset = c.regoff(&p.From)
  1253  
  1254  		m := uint32(ANYMEM)
  1255  		if cls == REGSB {
  1256  			m = E_MEMSB
  1257  		}
  1258  		if cls == REGSP {
  1259  			m = E_MEMSP
  1260  		}
  1261  
  1262  		s.used.cc |= m
  1263  
  1264  	case C_SACON,
  1265  		C_LACON:
  1266  		cls = int(p.From.Reg)
  1267  		if cls == 0 {
  1268  			cls = REGSP
  1269  		}
  1270  		s.used.ireg |= 1 << uint(cls-REG_R0)
  1271  
  1272  	case C_SECON,
  1273  		C_LECON:
  1274  		s.used.ireg |= 1 << (REGSB - REG_R0)
  1275  
  1276  	case C_REG:
  1277  		s.used.ireg |= 1 << uint(p.From.Reg-REG_R0)
  1278  
  1279  	case C_FREG:
  1280  		s.used.freg |= 1 << uint(p.From.Reg-REG_F0)
  1281  		if ld != 0 && p.To.Type == obj.TYPE_REG {
  1282  			p.Mark |= LOAD
  1283  		}
  1284  
  1285  	case C_SAUTO,
  1286  		C_LAUTO:
  1287  		s.used.ireg |= 1 << (REGSP - REG_R0)
  1288  		if ld != 0 {
  1289  			p.Mark |= LOAD
  1290  		}
  1291  		if ad != 0 {
  1292  			break
  1293  		}
  1294  		s.size = uint8(sz)
  1295  		s.soffset = c.regoff(&p.From)
  1296  
  1297  		s.used.cc |= E_MEMSP
  1298  
  1299  	case C_SEXT:
  1300  	case C_LEXT:
  1301  		s.used.ireg |= 1 << (REGSB - REG_R0)
  1302  		if ld != 0 {
  1303  			p.Mark |= LOAD
  1304  		}
  1305  		if ad != 0 {
  1306  			break
  1307  		}
  1308  		s.size = uint8(sz)
  1309  		s.soffset = c.regoff(&p.From)
  1310  
  1311  		s.used.cc |= E_MEMSB
  1312  	}
  1313  
  1314  	cls = int(p.Reg)
  1315  	if cls != 0 {
  1316  		if REG_F0 <= cls && cls <= REG_F31 {
  1317  			s.used.freg |= 1 << uint(cls-REG_F0)
  1318  		} else {
  1319  			s.used.ireg |= 1 << uint(cls-REG_R0)
  1320  		}
  1321  	}
  1322  	s.set.ireg &^= (1 << (REGZERO - REG_R0)) /* R0 can't be set */
  1323  }
  1324  
  1325  /*
  1326   * test to see if two instructions can be
  1327   * interchanged without changing semantics
  1328   */
  1329  func (c *ctxt0) depend(sa, sb *Sch) bool {
  1330  	if sa.set.ireg&(sb.set.ireg|sb.used.ireg) != 0 {
  1331  		return true
  1332  	}
  1333  	if sb.set.ireg&sa.used.ireg != 0 {
  1334  		return true
  1335  	}
  1336  
  1337  	if sa.set.freg&(sb.set.freg|sb.used.freg) != 0 {
  1338  		return true
  1339  	}
  1340  	if sb.set.freg&sa.used.freg != 0 {
  1341  		return true
  1342  	}
  1343  
  1344  	/*
  1345  	 * special case.
  1346  	 * loads from same address cannot pass.
  1347  	 * this is for hardware fifo's and the like
  1348  	 */
  1349  	if sa.used.cc&sb.used.cc&E_MEM != 0 {
  1350  		if sa.p.Reg == sb.p.Reg {
  1351  			if c.regoff(&sa.p.From) == c.regoff(&sb.p.From) {
  1352  				return true
  1353  			}
  1354  		}
  1355  	}
  1356  
  1357  	x := (sa.set.cc & (sb.set.cc | sb.used.cc)) | (sb.set.cc & sa.used.cc)
  1358  	if x != 0 {
  1359  		/*
  1360  		 * allow SB and SP to pass each other.
  1361  		 * allow SB to pass SB iff doffsets are ok
  1362  		 * anything else conflicts
  1363  		 */
  1364  		if x != E_MEMSP && x != E_MEMSB {
  1365  			return true
  1366  		}
  1367  		x = sa.set.cc | sb.set.cc | sa.used.cc | sb.used.cc
  1368  		if x&E_MEM != 0 {
  1369  			return true
  1370  		}
  1371  		if offoverlap(sa, sb) {
  1372  			return true
  1373  		}
  1374  	}
  1375  
  1376  	return false
  1377  }
  1378  
  1379  func offoverlap(sa, sb *Sch) bool {
  1380  	if sa.soffset < sb.soffset {
  1381  		if sa.soffset+int32(sa.size) > sb.soffset {
  1382  			return true
  1383  		}
  1384  		return false
  1385  	}
  1386  	if sb.soffset+int32(sb.size) > sa.soffset {
  1387  		return true
  1388  	}
  1389  	return false
  1390  }
  1391  
  1392  /*
  1393   * test 2 adjacent instructions
  1394   * and find out if inserted instructions
  1395   * are desired to prevent stalls.
  1396   */
  1397  func conflict(sa, sb *Sch) bool {
  1398  	if sa.set.ireg&sb.used.ireg != 0 {
  1399  		return true
  1400  	}
  1401  	if sa.set.freg&sb.used.freg != 0 {
  1402  		return true
  1403  	}
  1404  	if sa.set.cc&sb.used.cc != 0 {
  1405  		return true
  1406  	}
  1407  	return false
  1408  }
  1409  
  1410  func (c *ctxt0) compound(p *obj.Prog) bool {
  1411  	o := c.oplook(p)
  1412  	if o.size != 4 {
  1413  		return true
  1414  	}
  1415  	if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSB {
  1416  		return true
  1417  	}
  1418  	return false
  1419  }
  1420  
  1421  var Linkmips64 = obj.LinkArch{
  1422  	Arch:           sys.ArchMIPS64,
  1423  	Init:           buildop,
  1424  	Preprocess:     preprocess,
  1425  	Assemble:       span0,
  1426  	Progedit:       progedit,
  1427  	DWARFRegisters: MIPSDWARFRegisters,
  1428  }
  1429  
  1430  var Linkmips64le = obj.LinkArch{
  1431  	Arch:           sys.ArchMIPS64LE,
  1432  	Init:           buildop,
  1433  	Preprocess:     preprocess,
  1434  	Assemble:       span0,
  1435  	Progedit:       progedit,
  1436  	DWARFRegisters: MIPSDWARFRegisters,
  1437  }
  1438  
  1439  var Linkmips = obj.LinkArch{
  1440  	Arch:           sys.ArchMIPS,
  1441  	Init:           buildop,
  1442  	Preprocess:     preprocess,
  1443  	Assemble:       span0,
  1444  	Progedit:       progedit,
  1445  	DWARFRegisters: MIPSDWARFRegisters,
  1446  }
  1447  
  1448  var Linkmipsle = obj.LinkArch{
  1449  	Arch:           sys.ArchMIPSLE,
  1450  	Init:           buildop,
  1451  	Preprocess:     preprocess,
  1452  	Assemble:       span0,
  1453  	Progedit:       progedit,
  1454  	DWARFRegisters: MIPSDWARFRegisters,
  1455  }
  1456  

View as plain text