...

Source file src/github.com/twitchyliquid64/golang-asm/obj/mips/obj0.go

Documentation: github.com/twitchyliquid64/golang-asm/obj/mips

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

View as plain text