github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/src/cmd/internal/obj/mips/obj0.go (about)

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