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

View as plain text