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

     1  // Copyright 2016 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package mips
     6  
     7  import (
     8  	"math"
     9  
    10  	"cmd/compile/internal/gc"
    11  	"cmd/compile/internal/ssa"
    12  	"cmd/internal/obj"
    13  	"cmd/internal/obj/mips"
    14  )
    15  
    16  // isFPreg returns whether r is an FP register
    17  func isFPreg(r int16) bool {
    18  	return mips.REG_F0 <= r && r <= mips.REG_F31
    19  }
    20  
    21  // isHILO returns whether r is HI or LO register
    22  func isHILO(r int16) bool {
    23  	return r == mips.REG_HI || r == mips.REG_LO
    24  }
    25  
    26  // loadByType returns the load instruction of the given type.
    27  func loadByType(t ssa.Type, r int16) obj.As {
    28  	if isFPreg(r) {
    29  		if t.Size() == 4 { // float32 or int32
    30  			return mips.AMOVF
    31  		} else { // float64 or int64
    32  			return mips.AMOVD
    33  		}
    34  	} else {
    35  		switch t.Size() {
    36  		case 1:
    37  			if t.IsSigned() {
    38  				return mips.AMOVB
    39  			} else {
    40  				return mips.AMOVBU
    41  			}
    42  		case 2:
    43  			if t.IsSigned() {
    44  				return mips.AMOVH
    45  			} else {
    46  				return mips.AMOVHU
    47  			}
    48  		case 4:
    49  			return mips.AMOVW
    50  		}
    51  	}
    52  	panic("bad load type")
    53  }
    54  
    55  // storeByType returns the store instruction of the given type.
    56  func storeByType(t ssa.Type, r int16) obj.As {
    57  	if isFPreg(r) {
    58  		if t.Size() == 4 { // float32 or int32
    59  			return mips.AMOVF
    60  		} else { // float64 or int64
    61  			return mips.AMOVD
    62  		}
    63  	} else {
    64  		switch t.Size() {
    65  		case 1:
    66  			return mips.AMOVB
    67  		case 2:
    68  			return mips.AMOVH
    69  		case 4:
    70  			return mips.AMOVW
    71  		}
    72  	}
    73  	panic("bad store type")
    74  }
    75  
    76  func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
    77  	s.SetLineno(v.Line)
    78  	switch v.Op {
    79  	case ssa.OpInitMem:
    80  		// memory arg needs no code
    81  	case ssa.OpArg:
    82  		// input args need no code
    83  	case ssa.OpSP, ssa.OpSB, ssa.OpGetG:
    84  		// nothing to do
    85  	case ssa.OpSelect0, ssa.OpSelect1:
    86  		// nothing to do
    87  	case ssa.OpCopy, ssa.OpMIPSMOVWconvert, ssa.OpMIPSMOVWreg:
    88  		t := v.Type
    89  		if t.IsMemory() {
    90  			return
    91  		}
    92  		x := v.Args[0].Reg()
    93  		y := v.Reg()
    94  		if x == y {
    95  			return
    96  		}
    97  		as := mips.AMOVW
    98  		if isFPreg(x) && isFPreg(y) {
    99  			as = mips.AMOVF
   100  			if t.Size() == 8 {
   101  				as = mips.AMOVD
   102  			}
   103  		}
   104  
   105  		p := gc.Prog(as)
   106  		p.From.Type = obj.TYPE_REG
   107  		p.From.Reg = x
   108  		p.To.Type = obj.TYPE_REG
   109  		p.To.Reg = y
   110  		if isHILO(x) && isHILO(y) || isHILO(x) && isFPreg(y) || isFPreg(x) && isHILO(y) {
   111  			// cannot move between special registers, use TMP as intermediate
   112  			p.To.Reg = mips.REGTMP
   113  			p = gc.Prog(mips.AMOVW)
   114  			p.From.Type = obj.TYPE_REG
   115  			p.From.Reg = mips.REGTMP
   116  			p.To.Type = obj.TYPE_REG
   117  			p.To.Reg = y
   118  		}
   119  	case ssa.OpMIPSMOVWnop:
   120  		if v.Reg() != v.Args[0].Reg() {
   121  			v.Fatalf("input[0] and output not in same register %s", v.LongString())
   122  		}
   123  		// nothing to do
   124  	case ssa.OpLoadReg:
   125  		if v.Type.IsFlags() {
   126  			v.Fatalf("load flags not implemented: %v", v.LongString())
   127  			return
   128  		}
   129  		r := v.Reg()
   130  		p := gc.Prog(loadByType(v.Type, r))
   131  		gc.AddrAuto(&p.From, v.Args[0])
   132  		p.To.Type = obj.TYPE_REG
   133  		p.To.Reg = r
   134  		if isHILO(r) {
   135  			// cannot directly load, load to TMP and move
   136  			p.To.Reg = mips.REGTMP
   137  			p = gc.Prog(mips.AMOVW)
   138  			p.From.Type = obj.TYPE_REG
   139  			p.From.Reg = mips.REGTMP
   140  			p.To.Type = obj.TYPE_REG
   141  			p.To.Reg = r
   142  		}
   143  	case ssa.OpStoreReg:
   144  		if v.Type.IsFlags() {
   145  			v.Fatalf("store flags not implemented: %v", v.LongString())
   146  			return
   147  		}
   148  		r := v.Args[0].Reg()
   149  		if isHILO(r) {
   150  			// cannot directly store, move to TMP and store
   151  			p := gc.Prog(mips.AMOVW)
   152  			p.From.Type = obj.TYPE_REG
   153  			p.From.Reg = r
   154  			p.To.Type = obj.TYPE_REG
   155  			p.To.Reg = mips.REGTMP
   156  			r = mips.REGTMP
   157  		}
   158  		p := gc.Prog(storeByType(v.Type, r))
   159  		p.From.Type = obj.TYPE_REG
   160  		p.From.Reg = r
   161  		gc.AddrAuto(&p.To, v)
   162  	case ssa.OpMIPSADD,
   163  		ssa.OpMIPSSUB,
   164  		ssa.OpMIPSAND,
   165  		ssa.OpMIPSOR,
   166  		ssa.OpMIPSXOR,
   167  		ssa.OpMIPSNOR,
   168  		ssa.OpMIPSSLL,
   169  		ssa.OpMIPSSRL,
   170  		ssa.OpMIPSSRA,
   171  		ssa.OpMIPSADDF,
   172  		ssa.OpMIPSADDD,
   173  		ssa.OpMIPSSUBF,
   174  		ssa.OpMIPSSUBD,
   175  		ssa.OpMIPSMULF,
   176  		ssa.OpMIPSMULD,
   177  		ssa.OpMIPSDIVF,
   178  		ssa.OpMIPSDIVD,
   179  		ssa.OpMIPSMUL:
   180  		p := gc.Prog(v.Op.Asm())
   181  		p.From.Type = obj.TYPE_REG
   182  		p.From.Reg = v.Args[1].Reg()
   183  		p.Reg = v.Args[0].Reg()
   184  		p.To.Type = obj.TYPE_REG
   185  		p.To.Reg = v.Reg()
   186  	case ssa.OpMIPSSGT,
   187  		ssa.OpMIPSSGTU:
   188  		p := gc.Prog(v.Op.Asm())
   189  		p.From.Type = obj.TYPE_REG
   190  		p.From.Reg = v.Args[0].Reg()
   191  		p.Reg = v.Args[1].Reg()
   192  		p.To.Type = obj.TYPE_REG
   193  		p.To.Reg = v.Reg()
   194  	case ssa.OpMIPSSGTzero,
   195  		ssa.OpMIPSSGTUzero:
   196  		p := gc.Prog(v.Op.Asm())
   197  		p.From.Type = obj.TYPE_REG
   198  		p.From.Reg = v.Args[0].Reg()
   199  		p.Reg = mips.REGZERO
   200  		p.To.Type = obj.TYPE_REG
   201  		p.To.Reg = v.Reg()
   202  	case ssa.OpMIPSADDconst,
   203  		ssa.OpMIPSSUBconst,
   204  		ssa.OpMIPSANDconst,
   205  		ssa.OpMIPSORconst,
   206  		ssa.OpMIPSXORconst,
   207  		ssa.OpMIPSNORconst,
   208  		ssa.OpMIPSSLLconst,
   209  		ssa.OpMIPSSRLconst,
   210  		ssa.OpMIPSSRAconst,
   211  		ssa.OpMIPSSGTconst,
   212  		ssa.OpMIPSSGTUconst:
   213  		p := gc.Prog(v.Op.Asm())
   214  		p.From.Type = obj.TYPE_CONST
   215  		p.From.Offset = v.AuxInt
   216  		p.Reg = v.Args[0].Reg()
   217  		p.To.Type = obj.TYPE_REG
   218  		p.To.Reg = v.Reg()
   219  	case ssa.OpMIPSMULT,
   220  		ssa.OpMIPSMULTU,
   221  		ssa.OpMIPSDIV,
   222  		ssa.OpMIPSDIVU:
   223  		// result in hi,lo
   224  		p := gc.Prog(v.Op.Asm())
   225  		p.From.Type = obj.TYPE_REG
   226  		p.From.Reg = v.Args[1].Reg()
   227  		p.Reg = v.Args[0].Reg()
   228  	case ssa.OpMIPSMOVWconst:
   229  		r := v.Reg()
   230  		p := gc.Prog(v.Op.Asm())
   231  		p.From.Type = obj.TYPE_CONST
   232  		p.From.Offset = v.AuxInt
   233  		p.To.Type = obj.TYPE_REG
   234  		p.To.Reg = r
   235  		if isFPreg(r) || isHILO(r) {
   236  			// cannot move into FP or special registers, use TMP as intermediate
   237  			p.To.Reg = mips.REGTMP
   238  			p = gc.Prog(mips.AMOVW)
   239  			p.From.Type = obj.TYPE_REG
   240  			p.From.Reg = mips.REGTMP
   241  			p.To.Type = obj.TYPE_REG
   242  			p.To.Reg = r
   243  		}
   244  	case ssa.OpMIPSMOVFconst,
   245  		ssa.OpMIPSMOVDconst:
   246  		p := gc.Prog(v.Op.Asm())
   247  		p.From.Type = obj.TYPE_FCONST
   248  		p.From.Val = math.Float64frombits(uint64(v.AuxInt))
   249  		p.To.Type = obj.TYPE_REG
   250  		p.To.Reg = v.Reg()
   251  	case ssa.OpMIPSCMOVZ:
   252  		if v.Reg() != v.Args[0].Reg() {
   253  			v.Fatalf("input[0] and output not in same register %s", v.LongString())
   254  		}
   255  		p := gc.Prog(v.Op.Asm())
   256  		p.From.Type = obj.TYPE_REG
   257  		p.From.Reg = v.Args[2].Reg()
   258  		p.Reg = v.Args[1].Reg()
   259  		p.To.Type = obj.TYPE_REG
   260  		p.To.Reg = v.Reg()
   261  	case ssa.OpMIPSCMOVZzero:
   262  		if v.Reg() != v.Args[0].Reg() {
   263  			v.Fatalf("input[0] and output not in same register %s", v.LongString())
   264  		}
   265  		p := gc.Prog(v.Op.Asm())
   266  		p.From.Type = obj.TYPE_REG
   267  		p.From.Reg = v.Args[1].Reg()
   268  		p.Reg = mips.REGZERO
   269  		p.To.Type = obj.TYPE_REG
   270  		p.To.Reg = v.Reg()
   271  	case ssa.OpMIPSCMPEQF,
   272  		ssa.OpMIPSCMPEQD,
   273  		ssa.OpMIPSCMPGEF,
   274  		ssa.OpMIPSCMPGED,
   275  		ssa.OpMIPSCMPGTF,
   276  		ssa.OpMIPSCMPGTD:
   277  		p := gc.Prog(v.Op.Asm())
   278  		p.From.Type = obj.TYPE_REG
   279  		p.From.Reg = v.Args[0].Reg()
   280  		p.Reg = v.Args[1].Reg()
   281  	case ssa.OpMIPSMOVWaddr:
   282  		p := gc.Prog(mips.AMOVW)
   283  		p.From.Type = obj.TYPE_ADDR
   284  		var wantreg string
   285  		// MOVW $sym+off(base), R
   286  		// the assembler expands it as the following:
   287  		// - base is SP: add constant offset to SP (R29)
   288  		//               when constant is large, tmp register (R23) may be used
   289  		// - base is SB: load external address with relocation
   290  		switch v.Aux.(type) {
   291  		default:
   292  			v.Fatalf("aux is of unknown type %T", v.Aux)
   293  		case *ssa.ExternSymbol:
   294  			wantreg = "SB"
   295  			gc.AddAux(&p.From, v)
   296  		case *ssa.ArgSymbol, *ssa.AutoSymbol:
   297  			wantreg = "SP"
   298  			gc.AddAux(&p.From, v)
   299  		case nil:
   300  			// No sym, just MOVW $off(SP), R
   301  			wantreg = "SP"
   302  			p.From.Reg = mips.REGSP
   303  			p.From.Offset = v.AuxInt
   304  		}
   305  		if reg := v.Args[0].RegName(); reg != wantreg {
   306  			v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
   307  		}
   308  		p.To.Type = obj.TYPE_REG
   309  		p.To.Reg = v.Reg()
   310  	case ssa.OpMIPSMOVBload,
   311  		ssa.OpMIPSMOVBUload,
   312  		ssa.OpMIPSMOVHload,
   313  		ssa.OpMIPSMOVHUload,
   314  		ssa.OpMIPSMOVWload,
   315  		ssa.OpMIPSMOVFload,
   316  		ssa.OpMIPSMOVDload:
   317  		p := gc.Prog(v.Op.Asm())
   318  		p.From.Type = obj.TYPE_MEM
   319  		p.From.Reg = v.Args[0].Reg()
   320  		gc.AddAux(&p.From, v)
   321  		p.To.Type = obj.TYPE_REG
   322  		p.To.Reg = v.Reg()
   323  	case ssa.OpMIPSMOVBstore,
   324  		ssa.OpMIPSMOVHstore,
   325  		ssa.OpMIPSMOVWstore,
   326  		ssa.OpMIPSMOVFstore,
   327  		ssa.OpMIPSMOVDstore:
   328  		p := gc.Prog(v.Op.Asm())
   329  		p.From.Type = obj.TYPE_REG
   330  		p.From.Reg = v.Args[1].Reg()
   331  		p.To.Type = obj.TYPE_MEM
   332  		p.To.Reg = v.Args[0].Reg()
   333  		gc.AddAux(&p.To, v)
   334  	case ssa.OpMIPSMOVBstorezero,
   335  		ssa.OpMIPSMOVHstorezero,
   336  		ssa.OpMIPSMOVWstorezero:
   337  		p := gc.Prog(v.Op.Asm())
   338  		p.From.Type = obj.TYPE_REG
   339  		p.From.Reg = mips.REGZERO
   340  		p.To.Type = obj.TYPE_MEM
   341  		p.To.Reg = v.Args[0].Reg()
   342  		gc.AddAux(&p.To, v)
   343  	case ssa.OpMIPSMOVBreg,
   344  		ssa.OpMIPSMOVBUreg,
   345  		ssa.OpMIPSMOVHreg,
   346  		ssa.OpMIPSMOVHUreg:
   347  		a := v.Args[0]
   348  		for a.Op == ssa.OpCopy || a.Op == ssa.OpMIPSMOVWreg || a.Op == ssa.OpMIPSMOVWnop {
   349  			a = a.Args[0]
   350  		}
   351  		if a.Op == ssa.OpLoadReg {
   352  			t := a.Type
   353  			switch {
   354  			case v.Op == ssa.OpMIPSMOVBreg && t.Size() == 1 && t.IsSigned(),
   355  				v.Op == ssa.OpMIPSMOVBUreg && t.Size() == 1 && !t.IsSigned(),
   356  				v.Op == ssa.OpMIPSMOVHreg && t.Size() == 2 && t.IsSigned(),
   357  				v.Op == ssa.OpMIPSMOVHUreg && t.Size() == 2 && !t.IsSigned():
   358  				// arg is a proper-typed load, already zero/sign-extended, don't extend again
   359  				if v.Reg() == v.Args[0].Reg() {
   360  					return
   361  				}
   362  				p := gc.Prog(mips.AMOVW)
   363  				p.From.Type = obj.TYPE_REG
   364  				p.From.Reg = v.Args[0].Reg()
   365  				p.To.Type = obj.TYPE_REG
   366  				p.To.Reg = v.Reg()
   367  				return
   368  			default:
   369  			}
   370  		}
   371  		fallthrough
   372  	case ssa.OpMIPSMOVWF,
   373  		ssa.OpMIPSMOVWD,
   374  		ssa.OpMIPSTRUNCFW,
   375  		ssa.OpMIPSTRUNCDW,
   376  		ssa.OpMIPSMOVFD,
   377  		ssa.OpMIPSMOVDF,
   378  		ssa.OpMIPSNEGF,
   379  		ssa.OpMIPSNEGD,
   380  		ssa.OpMIPSSQRTD,
   381  		ssa.OpMIPSCLZ:
   382  		p := gc.Prog(v.Op.Asm())
   383  		p.From.Type = obj.TYPE_REG
   384  		p.From.Reg = v.Args[0].Reg()
   385  		p.To.Type = obj.TYPE_REG
   386  		p.To.Reg = v.Reg()
   387  	case ssa.OpMIPSNEG:
   388  		// SUB from REGZERO
   389  		p := gc.Prog(mips.ASUBU)
   390  		p.From.Type = obj.TYPE_REG
   391  		p.From.Reg = v.Args[0].Reg()
   392  		p.Reg = mips.REGZERO
   393  		p.To.Type = obj.TYPE_REG
   394  		p.To.Reg = v.Reg()
   395  	case ssa.OpMIPSLoweredZero:
   396  		// SUBU	$4, R1
   397  		// MOVW	R0, 4(R1)
   398  		// ADDU	$4, R1
   399  		// BNE	Rarg1, R1, -2(PC)
   400  		// arg1 is the address of the last element to zero
   401  		var sz int64
   402  		var mov obj.As
   403  		switch {
   404  		case v.AuxInt%4 == 0:
   405  			sz = 4
   406  			mov = mips.AMOVW
   407  		case v.AuxInt%2 == 0:
   408  			sz = 2
   409  			mov = mips.AMOVH
   410  		default:
   411  			sz = 1
   412  			mov = mips.AMOVB
   413  		}
   414  		p := gc.Prog(mips.ASUBU)
   415  		p.From.Type = obj.TYPE_CONST
   416  		p.From.Offset = sz
   417  		p.To.Type = obj.TYPE_REG
   418  		p.To.Reg = mips.REG_R1
   419  		p2 := gc.Prog(mov)
   420  		p2.From.Type = obj.TYPE_REG
   421  		p2.From.Reg = mips.REGZERO
   422  		p2.To.Type = obj.TYPE_MEM
   423  		p2.To.Reg = mips.REG_R1
   424  		p2.To.Offset = sz
   425  		p3 := gc.Prog(mips.AADDU)
   426  		p3.From.Type = obj.TYPE_CONST
   427  		p3.From.Offset = sz
   428  		p3.To.Type = obj.TYPE_REG
   429  		p3.To.Reg = mips.REG_R1
   430  		p4 := gc.Prog(mips.ABNE)
   431  		p4.From.Type = obj.TYPE_REG
   432  		p4.From.Reg = v.Args[1].Reg()
   433  		p4.Reg = mips.REG_R1
   434  		p4.To.Type = obj.TYPE_BRANCH
   435  		gc.Patch(p4, p2)
   436  	case ssa.OpMIPSLoweredMove:
   437  		// SUBU	$4, R1
   438  		// MOVW	4(R1), Rtmp
   439  		// MOVW	Rtmp, (R2)
   440  		// ADDU	$4, R1
   441  		// ADDU	$4, R2
   442  		// BNE	Rarg2, R1, -4(PC)
   443  		// arg2 is the address of the last element of src
   444  		var sz int64
   445  		var mov obj.As
   446  		switch {
   447  		case v.AuxInt%4 == 0:
   448  			sz = 4
   449  			mov = mips.AMOVW
   450  		case v.AuxInt%2 == 0:
   451  			sz = 2
   452  			mov = mips.AMOVH
   453  		default:
   454  			sz = 1
   455  			mov = mips.AMOVB
   456  		}
   457  		p := gc.Prog(mips.ASUBU)
   458  		p.From.Type = obj.TYPE_CONST
   459  		p.From.Offset = sz
   460  		p.To.Type = obj.TYPE_REG
   461  		p.To.Reg = mips.REG_R1
   462  		p2 := gc.Prog(mov)
   463  		p2.From.Type = obj.TYPE_MEM
   464  		p2.From.Reg = mips.REG_R1
   465  		p2.From.Offset = sz
   466  		p2.To.Type = obj.TYPE_REG
   467  		p2.To.Reg = mips.REGTMP
   468  		p3 := gc.Prog(mov)
   469  		p3.From.Type = obj.TYPE_REG
   470  		p3.From.Reg = mips.REGTMP
   471  		p3.To.Type = obj.TYPE_MEM
   472  		p3.To.Reg = mips.REG_R2
   473  		p4 := gc.Prog(mips.AADDU)
   474  		p4.From.Type = obj.TYPE_CONST
   475  		p4.From.Offset = sz
   476  		p4.To.Type = obj.TYPE_REG
   477  		p4.To.Reg = mips.REG_R1
   478  		p5 := gc.Prog(mips.AADDU)
   479  		p5.From.Type = obj.TYPE_CONST
   480  		p5.From.Offset = sz
   481  		p5.To.Type = obj.TYPE_REG
   482  		p5.To.Reg = mips.REG_R2
   483  		p6 := gc.Prog(mips.ABNE)
   484  		p6.From.Type = obj.TYPE_REG
   485  		p6.From.Reg = v.Args[2].Reg()
   486  		p6.Reg = mips.REG_R1
   487  		p6.To.Type = obj.TYPE_BRANCH
   488  		gc.Patch(p6, p2)
   489  	case ssa.OpMIPSCALLstatic:
   490  		if v.Aux.(*gc.Sym) == gc.Deferreturn.Sym {
   491  			// Deferred calls will appear to be returning to
   492  			// the CALL deferreturn(SB) that we are about to emit.
   493  			// However, the stack trace code will show the line
   494  			// of the instruction byte before the return PC.
   495  			// To avoid that being an unrelated instruction,
   496  			// insert an actual hardware NOP that will have the right line number.
   497  			// This is different from obj.ANOP, which is a virtual no-op
   498  			// that doesn't make it into the instruction stream.
   499  			ginsnop()
   500  		}
   501  		p := gc.Prog(obj.ACALL)
   502  		p.To.Type = obj.TYPE_MEM
   503  		p.To.Name = obj.NAME_EXTERN
   504  		p.To.Sym = gc.Linksym(v.Aux.(*gc.Sym))
   505  		if gc.Maxarg < v.AuxInt {
   506  			gc.Maxarg = v.AuxInt
   507  		}
   508  	case ssa.OpMIPSCALLclosure:
   509  		p := gc.Prog(obj.ACALL)
   510  		p.To.Type = obj.TYPE_MEM
   511  		p.To.Offset = 0
   512  		p.To.Reg = v.Args[0].Reg()
   513  		if gc.Maxarg < v.AuxInt {
   514  			gc.Maxarg = v.AuxInt
   515  		}
   516  	case ssa.OpMIPSCALLdefer:
   517  		p := gc.Prog(obj.ACALL)
   518  		p.To.Type = obj.TYPE_MEM
   519  		p.To.Name = obj.NAME_EXTERN
   520  		p.To.Sym = gc.Linksym(gc.Deferproc.Sym)
   521  		if gc.Maxarg < v.AuxInt {
   522  			gc.Maxarg = v.AuxInt
   523  		}
   524  	case ssa.OpMIPSCALLgo:
   525  		p := gc.Prog(obj.ACALL)
   526  		p.To.Type = obj.TYPE_MEM
   527  		p.To.Name = obj.NAME_EXTERN
   528  		p.To.Sym = gc.Linksym(gc.Newproc.Sym)
   529  		if gc.Maxarg < v.AuxInt {
   530  			gc.Maxarg = v.AuxInt
   531  		}
   532  	case ssa.OpMIPSCALLinter:
   533  		p := gc.Prog(obj.ACALL)
   534  		p.To.Type = obj.TYPE_MEM
   535  		p.To.Offset = 0
   536  		p.To.Reg = v.Args[0].Reg()
   537  		if gc.Maxarg < v.AuxInt {
   538  			gc.Maxarg = v.AuxInt
   539  		}
   540  	case ssa.OpMIPSLoweredAtomicLoad:
   541  		gc.Prog(mips.ASYNC)
   542  
   543  		p := gc.Prog(mips.AMOVW)
   544  		p.From.Type = obj.TYPE_MEM
   545  		p.From.Reg = v.Args[0].Reg()
   546  		p.To.Type = obj.TYPE_REG
   547  		p.To.Reg = v.Reg0()
   548  
   549  		gc.Prog(mips.ASYNC)
   550  	case ssa.OpMIPSLoweredAtomicStore:
   551  		gc.Prog(mips.ASYNC)
   552  
   553  		p := gc.Prog(mips.AMOVW)
   554  		p.From.Type = obj.TYPE_REG
   555  		p.From.Reg = v.Args[1].Reg()
   556  		p.To.Type = obj.TYPE_MEM
   557  		p.To.Reg = v.Args[0].Reg()
   558  
   559  		gc.Prog(mips.ASYNC)
   560  	case ssa.OpMIPSLoweredAtomicStorezero:
   561  		gc.Prog(mips.ASYNC)
   562  
   563  		p := gc.Prog(mips.AMOVW)
   564  		p.From.Type = obj.TYPE_REG
   565  		p.From.Reg = mips.REGZERO
   566  		p.To.Type = obj.TYPE_MEM
   567  		p.To.Reg = v.Args[0].Reg()
   568  
   569  		gc.Prog(mips.ASYNC)
   570  	case ssa.OpMIPSLoweredAtomicExchange:
   571  		// SYNC
   572  		// MOVW Rarg1, Rtmp
   573  		// LL	(Rarg0), Rout
   574  		// SC	Rtmp, (Rarg0)
   575  		// BEQ	Rtmp, -3(PC)
   576  		// SYNC
   577  		gc.Prog(mips.ASYNC)
   578  
   579  		p := gc.Prog(mips.AMOVW)
   580  		p.From.Type = obj.TYPE_REG
   581  		p.From.Reg = v.Args[1].Reg()
   582  		p.To.Type = obj.TYPE_REG
   583  		p.To.Reg = mips.REGTMP
   584  
   585  		p1 := gc.Prog(mips.ALL)
   586  		p1.From.Type = obj.TYPE_MEM
   587  		p1.From.Reg = v.Args[0].Reg()
   588  		p1.To.Type = obj.TYPE_REG
   589  		p1.To.Reg = v.Reg0()
   590  
   591  		p2 := gc.Prog(mips.ASC)
   592  		p2.From.Type = obj.TYPE_REG
   593  		p2.From.Reg = mips.REGTMP
   594  		p2.To.Type = obj.TYPE_MEM
   595  		p2.To.Reg = v.Args[0].Reg()
   596  
   597  		p3 := gc.Prog(mips.ABEQ)
   598  		p3.From.Type = obj.TYPE_REG
   599  		p3.From.Reg = mips.REGTMP
   600  		p3.To.Type = obj.TYPE_BRANCH
   601  		gc.Patch(p3, p)
   602  
   603  		gc.Prog(mips.ASYNC)
   604  	case ssa.OpMIPSLoweredAtomicAdd:
   605  		// SYNC
   606  		// LL	(Rarg0), Rout
   607  		// ADDU Rarg1, Rout, Rtmp
   608  		// SC	Rtmp, (Rarg0)
   609  		// BEQ	Rtmp, -3(PC)
   610  		// SYNC
   611  		// ADDU Rarg1, Rout
   612  		gc.Prog(mips.ASYNC)
   613  
   614  		p := gc.Prog(mips.ALL)
   615  		p.From.Type = obj.TYPE_MEM
   616  		p.From.Reg = v.Args[0].Reg()
   617  		p.To.Type = obj.TYPE_REG
   618  		p.To.Reg = v.Reg0()
   619  
   620  		p1 := gc.Prog(mips.AADDU)
   621  		p1.From.Type = obj.TYPE_REG
   622  		p1.From.Reg = v.Args[1].Reg()
   623  		p1.Reg = v.Reg0()
   624  		p1.To.Type = obj.TYPE_REG
   625  		p1.To.Reg = mips.REGTMP
   626  
   627  		p2 := gc.Prog(mips.ASC)
   628  		p2.From.Type = obj.TYPE_REG
   629  		p2.From.Reg = mips.REGTMP
   630  		p2.To.Type = obj.TYPE_MEM
   631  		p2.To.Reg = v.Args[0].Reg()
   632  
   633  		p3 := gc.Prog(mips.ABEQ)
   634  		p3.From.Type = obj.TYPE_REG
   635  		p3.From.Reg = mips.REGTMP
   636  		p3.To.Type = obj.TYPE_BRANCH
   637  		gc.Patch(p3, p)
   638  
   639  		gc.Prog(mips.ASYNC)
   640  
   641  		p4 := gc.Prog(mips.AADDU)
   642  		p4.From.Type = obj.TYPE_REG
   643  		p4.From.Reg = v.Args[1].Reg()
   644  		p4.Reg = v.Reg0()
   645  		p4.To.Type = obj.TYPE_REG
   646  		p4.To.Reg = v.Reg0()
   647  
   648  	case ssa.OpMIPSLoweredAtomicAddconst:
   649  		// SYNC
   650  		// LL	(Rarg0), Rout
   651  		// ADDU $auxInt, Rout, Rtmp
   652  		// SC	Rtmp, (Rarg0)
   653  		// BEQ	Rtmp, -3(PC)
   654  		// SYNC
   655  		// ADDU $auxInt, Rout
   656  		gc.Prog(mips.ASYNC)
   657  
   658  		p := gc.Prog(mips.ALL)
   659  		p.From.Type = obj.TYPE_MEM
   660  		p.From.Reg = v.Args[0].Reg()
   661  		p.To.Type = obj.TYPE_REG
   662  		p.To.Reg = v.Reg0()
   663  
   664  		p1 := gc.Prog(mips.AADDU)
   665  		p1.From.Type = obj.TYPE_CONST
   666  		p1.From.Offset = v.AuxInt
   667  		p1.Reg = v.Reg0()
   668  		p1.To.Type = obj.TYPE_REG
   669  		p1.To.Reg = mips.REGTMP
   670  
   671  		p2 := gc.Prog(mips.ASC)
   672  		p2.From.Type = obj.TYPE_REG
   673  		p2.From.Reg = mips.REGTMP
   674  		p2.To.Type = obj.TYPE_MEM
   675  		p2.To.Reg = v.Args[0].Reg()
   676  
   677  		p3 := gc.Prog(mips.ABEQ)
   678  		p3.From.Type = obj.TYPE_REG
   679  		p3.From.Reg = mips.REGTMP
   680  		p3.To.Type = obj.TYPE_BRANCH
   681  		gc.Patch(p3, p)
   682  
   683  		gc.Prog(mips.ASYNC)
   684  
   685  		p4 := gc.Prog(mips.AADDU)
   686  		p4.From.Type = obj.TYPE_CONST
   687  		p4.From.Offset = v.AuxInt
   688  		p4.Reg = v.Reg0()
   689  		p4.To.Type = obj.TYPE_REG
   690  		p4.To.Reg = v.Reg0()
   691  
   692  	case ssa.OpMIPSLoweredAtomicAnd,
   693  		ssa.OpMIPSLoweredAtomicOr:
   694  		// SYNC
   695  		// LL	(Rarg0), Rtmp
   696  		// AND/OR	Rarg1, Rtmp
   697  		// SC	Rtmp, (Rarg0)
   698  		// BEQ	Rtmp, -3(PC)
   699  		// SYNC
   700  		gc.Prog(mips.ASYNC)
   701  
   702  		p := gc.Prog(mips.ALL)
   703  		p.From.Type = obj.TYPE_MEM
   704  		p.From.Reg = v.Args[0].Reg()
   705  		p.To.Type = obj.TYPE_REG
   706  		p.To.Reg = mips.REGTMP
   707  
   708  		p1 := gc.Prog(v.Op.Asm())
   709  		p1.From.Type = obj.TYPE_REG
   710  		p1.From.Reg = v.Args[1].Reg()
   711  		p1.Reg = mips.REGTMP
   712  		p1.To.Type = obj.TYPE_REG
   713  		p1.To.Reg = mips.REGTMP
   714  
   715  		p2 := gc.Prog(mips.ASC)
   716  		p2.From.Type = obj.TYPE_REG
   717  		p2.From.Reg = mips.REGTMP
   718  		p2.To.Type = obj.TYPE_MEM
   719  		p2.To.Reg = v.Args[0].Reg()
   720  
   721  		p3 := gc.Prog(mips.ABEQ)
   722  		p3.From.Type = obj.TYPE_REG
   723  		p3.From.Reg = mips.REGTMP
   724  		p3.To.Type = obj.TYPE_BRANCH
   725  		gc.Patch(p3, p)
   726  
   727  		gc.Prog(mips.ASYNC)
   728  
   729  	case ssa.OpMIPSLoweredAtomicCas:
   730  		// MOVW $0, Rout
   731  		// SYNC
   732  		// LL	(Rarg0), Rtmp
   733  		// BNE	Rtmp, Rarg1, 4(PC)
   734  		// MOVW Rarg2, Rout
   735  		// SC	Rout, (Rarg0)
   736  		// BEQ	Rout, -4(PC)
   737  		// SYNC
   738  		p := gc.Prog(mips.AMOVW)
   739  		p.From.Type = obj.TYPE_REG
   740  		p.From.Reg = mips.REGZERO
   741  		p.To.Type = obj.TYPE_REG
   742  		p.To.Reg = v.Reg0()
   743  
   744  		gc.Prog(mips.ASYNC)
   745  
   746  		p1 := gc.Prog(mips.ALL)
   747  		p1.From.Type = obj.TYPE_MEM
   748  		p1.From.Reg = v.Args[0].Reg()
   749  		p1.To.Type = obj.TYPE_REG
   750  		p1.To.Reg = mips.REGTMP
   751  
   752  		p2 := gc.Prog(mips.ABNE)
   753  		p2.From.Type = obj.TYPE_REG
   754  		p2.From.Reg = v.Args[1].Reg()
   755  		p2.Reg = mips.REGTMP
   756  		p2.To.Type = obj.TYPE_BRANCH
   757  
   758  		p3 := gc.Prog(mips.AMOVW)
   759  		p3.From.Type = obj.TYPE_REG
   760  		p3.From.Reg = v.Args[2].Reg()
   761  		p3.To.Type = obj.TYPE_REG
   762  		p3.To.Reg = v.Reg0()
   763  
   764  		p4 := gc.Prog(mips.ASC)
   765  		p4.From.Type = obj.TYPE_REG
   766  		p4.From.Reg = v.Reg0()
   767  		p4.To.Type = obj.TYPE_MEM
   768  		p4.To.Reg = v.Args[0].Reg()
   769  
   770  		p5 := gc.Prog(mips.ABEQ)
   771  		p5.From.Type = obj.TYPE_REG
   772  		p5.From.Reg = v.Reg0()
   773  		p5.To.Type = obj.TYPE_BRANCH
   774  		gc.Patch(p5, p1)
   775  
   776  		gc.Prog(mips.ASYNC)
   777  
   778  		p6 := gc.Prog(obj.ANOP)
   779  		gc.Patch(p2, p6)
   780  
   781  	case ssa.OpVarDef:
   782  		gc.Gvardef(v.Aux.(*gc.Node))
   783  	case ssa.OpVarKill:
   784  		gc.Gvarkill(v.Aux.(*gc.Node))
   785  	case ssa.OpVarLive:
   786  		gc.Gvarlive(v.Aux.(*gc.Node))
   787  	case ssa.OpKeepAlive:
   788  		gc.KeepAlive(v)
   789  	case ssa.OpPhi:
   790  		gc.CheckLoweredPhi(v)
   791  	case ssa.OpMIPSLoweredNilCheck:
   792  		// Issue a load which will fault if arg is nil.
   793  		p := gc.Prog(mips.AMOVB)
   794  		p.From.Type = obj.TYPE_MEM
   795  		p.From.Reg = v.Args[0].Reg()
   796  		gc.AddAux(&p.From, v)
   797  		p.To.Type = obj.TYPE_REG
   798  		p.To.Reg = mips.REGTMP
   799  		if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
   800  			gc.Warnl(v.Line, "generated nil check")
   801  		}
   802  	case ssa.OpMIPSFPFlagTrue,
   803  		ssa.OpMIPSFPFlagFalse:
   804  		// MOVW		$1, r
   805  		// CMOVF	R0, r
   806  
   807  		cmov := mips.ACMOVF
   808  		if v.Op == ssa.OpMIPSFPFlagFalse {
   809  			cmov = mips.ACMOVT
   810  		}
   811  		p := gc.Prog(mips.AMOVW)
   812  		p.From.Type = obj.TYPE_CONST
   813  		p.From.Offset = 1
   814  		p.To.Type = obj.TYPE_REG
   815  		p.To.Reg = v.Reg()
   816  		p1 := gc.Prog(cmov)
   817  		p1.From.Type = obj.TYPE_REG
   818  		p1.From.Reg = mips.REGZERO
   819  		p1.To.Type = obj.TYPE_REG
   820  		p1.To.Reg = v.Reg()
   821  
   822  	case ssa.OpMIPSLoweredGetClosurePtr:
   823  		// Closure pointer is R22 (mips.REGCTXT).
   824  		gc.CheckLoweredGetClosurePtr(v)
   825  	default:
   826  		v.Fatalf("genValue not implemented: %s", v.LongString())
   827  	}
   828  }
   829  
   830  var blockJump = map[ssa.BlockKind]struct {
   831  	asm, invasm obj.As
   832  }{
   833  	ssa.BlockMIPSEQ:  {mips.ABEQ, mips.ABNE},
   834  	ssa.BlockMIPSNE:  {mips.ABNE, mips.ABEQ},
   835  	ssa.BlockMIPSLTZ: {mips.ABLTZ, mips.ABGEZ},
   836  	ssa.BlockMIPSGEZ: {mips.ABGEZ, mips.ABLTZ},
   837  	ssa.BlockMIPSLEZ: {mips.ABLEZ, mips.ABGTZ},
   838  	ssa.BlockMIPSGTZ: {mips.ABGTZ, mips.ABLEZ},
   839  	ssa.BlockMIPSFPT: {mips.ABFPT, mips.ABFPF},
   840  	ssa.BlockMIPSFPF: {mips.ABFPF, mips.ABFPT},
   841  }
   842  
   843  func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
   844  	s.SetLineno(b.Line)
   845  
   846  	switch b.Kind {
   847  	case ssa.BlockPlain:
   848  		if b.Succs[0].Block() != next {
   849  			p := gc.Prog(obj.AJMP)
   850  			p.To.Type = obj.TYPE_BRANCH
   851  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   852  		}
   853  	case ssa.BlockDefer:
   854  		// defer returns in R1:
   855  		// 0 if we should continue executing
   856  		// 1 if we should jump to deferreturn call
   857  		p := gc.Prog(mips.ABNE)
   858  		p.From.Type = obj.TYPE_REG
   859  		p.From.Reg = mips.REGZERO
   860  		p.Reg = mips.REG_R1
   861  		p.To.Type = obj.TYPE_BRANCH
   862  		s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
   863  		if b.Succs[0].Block() != next {
   864  			p := gc.Prog(obj.AJMP)
   865  			p.To.Type = obj.TYPE_BRANCH
   866  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   867  		}
   868  	case ssa.BlockExit:
   869  		gc.Prog(obj.AUNDEF) // tell plive.go that we never reach here
   870  	case ssa.BlockRet:
   871  		gc.Prog(obj.ARET)
   872  	case ssa.BlockRetJmp:
   873  		p := gc.Prog(obj.ARET)
   874  		p.To.Type = obj.TYPE_MEM
   875  		p.To.Name = obj.NAME_EXTERN
   876  		p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym))
   877  	case ssa.BlockMIPSEQ, ssa.BlockMIPSNE,
   878  		ssa.BlockMIPSLTZ, ssa.BlockMIPSGEZ,
   879  		ssa.BlockMIPSLEZ, ssa.BlockMIPSGTZ,
   880  		ssa.BlockMIPSFPT, ssa.BlockMIPSFPF:
   881  		jmp := blockJump[b.Kind]
   882  		var p *obj.Prog
   883  		switch next {
   884  		case b.Succs[0].Block():
   885  			p = gc.Prog(jmp.invasm)
   886  			p.To.Type = obj.TYPE_BRANCH
   887  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
   888  		case b.Succs[1].Block():
   889  			p = gc.Prog(jmp.asm)
   890  			p.To.Type = obj.TYPE_BRANCH
   891  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   892  		default:
   893  			p = gc.Prog(jmp.asm)
   894  			p.To.Type = obj.TYPE_BRANCH
   895  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   896  			q := gc.Prog(obj.AJMP)
   897  			q.To.Type = obj.TYPE_BRANCH
   898  			s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
   899  		}
   900  		if !b.Control.Type.IsFlags() {
   901  			p.From.Type = obj.TYPE_REG
   902  			p.From.Reg = b.Control.Reg()
   903  		}
   904  	default:
   905  		b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
   906  	}
   907  }