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

View as plain text