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