github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/src/cmd/compile/internal/mips64/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 mips64
     6  
     7  import (
     8  	"math"
     9  
    10  	"cmd/compile/internal/gc"
    11  	"cmd/compile/internal/ssa"
    12  	"cmd/compile/internal/types"
    13  	"cmd/internal/obj"
    14  	"cmd/internal/obj/mips"
    15  )
    16  
    17  // isFPreg returns whether r is an FP register
    18  func isFPreg(r int16) bool {
    19  	return mips.REG_F0 <= r && r <= mips.REG_F31
    20  }
    21  
    22  // isHILO returns whether r is HI or LO register
    23  func isHILO(r int16) bool {
    24  	return r == mips.REG_HI || r == mips.REG_LO
    25  }
    26  
    27  // loadByType returns the load instruction of the given type.
    28  func loadByType(t *types.Type, r int16) obj.As {
    29  	if isFPreg(r) {
    30  		if t.Size() == 4 { // float32 or int32
    31  			return mips.AMOVF
    32  		} else { // float64 or int64
    33  			return mips.AMOVD
    34  		}
    35  	} else {
    36  		switch t.Size() {
    37  		case 1:
    38  			if t.IsSigned() {
    39  				return mips.AMOVB
    40  			} else {
    41  				return mips.AMOVBU
    42  			}
    43  		case 2:
    44  			if t.IsSigned() {
    45  				return mips.AMOVH
    46  			} else {
    47  				return mips.AMOVHU
    48  			}
    49  		case 4:
    50  			if t.IsSigned() {
    51  				return mips.AMOVW
    52  			} else {
    53  				return mips.AMOVWU
    54  			}
    55  		case 8:
    56  			return mips.AMOVV
    57  		}
    58  	}
    59  	panic("bad load type")
    60  }
    61  
    62  // storeByType returns the store instruction of the given type.
    63  func storeByType(t *types.Type, r int16) obj.As {
    64  	if isFPreg(r) {
    65  		if t.Size() == 4 { // float32 or int32
    66  			return mips.AMOVF
    67  		} else { // float64 or int64
    68  			return mips.AMOVD
    69  		}
    70  	} else {
    71  		switch t.Size() {
    72  		case 1:
    73  			return mips.AMOVB
    74  		case 2:
    75  			return mips.AMOVH
    76  		case 4:
    77  			return mips.AMOVW
    78  		case 8:
    79  			return mips.AMOVV
    80  		}
    81  	}
    82  	panic("bad store type")
    83  }
    84  
    85  func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
    86  	switch v.Op {
    87  	case ssa.OpCopy, ssa.OpMIPS64MOVVconvert, ssa.OpMIPS64MOVVreg:
    88  		if v.Type.IsMemory() {
    89  			return
    90  		}
    91  		x := v.Args[0].Reg()
    92  		y := v.Reg()
    93  		if x == y {
    94  			return
    95  		}
    96  		as := mips.AMOVV
    97  		if isFPreg(x) && isFPreg(y) {
    98  			as = mips.AMOVD
    99  		}
   100  		p := s.Prog(as)
   101  		p.From.Type = obj.TYPE_REG
   102  		p.From.Reg = x
   103  		p.To.Type = obj.TYPE_REG
   104  		p.To.Reg = y
   105  		if isHILO(x) && isHILO(y) || isHILO(x) && isFPreg(y) || isFPreg(x) && isHILO(y) {
   106  			// cannot move between special registers, use TMP as intermediate
   107  			p.To.Reg = mips.REGTMP
   108  			p = s.Prog(mips.AMOVV)
   109  			p.From.Type = obj.TYPE_REG
   110  			p.From.Reg = mips.REGTMP
   111  			p.To.Type = obj.TYPE_REG
   112  			p.To.Reg = y
   113  		}
   114  	case ssa.OpMIPS64MOVVnop:
   115  		if v.Reg() != v.Args[0].Reg() {
   116  			v.Fatalf("input[0] and output not in same register %s", v.LongString())
   117  		}
   118  		// nothing to do
   119  	case ssa.OpLoadReg:
   120  		if v.Type.IsFlags() {
   121  			v.Fatalf("load flags not implemented: %v", v.LongString())
   122  			return
   123  		}
   124  		r := v.Reg()
   125  		p := s.Prog(loadByType(v.Type, r))
   126  		gc.AddrAuto(&p.From, v.Args[0])
   127  		p.To.Type = obj.TYPE_REG
   128  		p.To.Reg = r
   129  		if isHILO(r) {
   130  			// cannot directly load, load to TMP and move
   131  			p.To.Reg = mips.REGTMP
   132  			p = s.Prog(mips.AMOVV)
   133  			p.From.Type = obj.TYPE_REG
   134  			p.From.Reg = mips.REGTMP
   135  			p.To.Type = obj.TYPE_REG
   136  			p.To.Reg = r
   137  		}
   138  	case ssa.OpStoreReg:
   139  		if v.Type.IsFlags() {
   140  			v.Fatalf("store flags not implemented: %v", v.LongString())
   141  			return
   142  		}
   143  		r := v.Args[0].Reg()
   144  		if isHILO(r) {
   145  			// cannot directly store, move to TMP and store
   146  			p := s.Prog(mips.AMOVV)
   147  			p.From.Type = obj.TYPE_REG
   148  			p.From.Reg = r
   149  			p.To.Type = obj.TYPE_REG
   150  			p.To.Reg = mips.REGTMP
   151  			r = mips.REGTMP
   152  		}
   153  		p := s.Prog(storeByType(v.Type, r))
   154  		p.From.Type = obj.TYPE_REG
   155  		p.From.Reg = r
   156  		gc.AddrAuto(&p.To, v)
   157  	case ssa.OpMIPS64ADDV,
   158  		ssa.OpMIPS64SUBV,
   159  		ssa.OpMIPS64AND,
   160  		ssa.OpMIPS64OR,
   161  		ssa.OpMIPS64XOR,
   162  		ssa.OpMIPS64NOR,
   163  		ssa.OpMIPS64SLLV,
   164  		ssa.OpMIPS64SRLV,
   165  		ssa.OpMIPS64SRAV,
   166  		ssa.OpMIPS64ADDF,
   167  		ssa.OpMIPS64ADDD,
   168  		ssa.OpMIPS64SUBF,
   169  		ssa.OpMIPS64SUBD,
   170  		ssa.OpMIPS64MULF,
   171  		ssa.OpMIPS64MULD,
   172  		ssa.OpMIPS64DIVF,
   173  		ssa.OpMIPS64DIVD:
   174  		p := s.Prog(v.Op.Asm())
   175  		p.From.Type = obj.TYPE_REG
   176  		p.From.Reg = v.Args[1].Reg()
   177  		p.Reg = v.Args[0].Reg()
   178  		p.To.Type = obj.TYPE_REG
   179  		p.To.Reg = v.Reg()
   180  	case ssa.OpMIPS64SGT,
   181  		ssa.OpMIPS64SGTU:
   182  		p := s.Prog(v.Op.Asm())
   183  		p.From.Type = obj.TYPE_REG
   184  		p.From.Reg = v.Args[0].Reg()
   185  		p.Reg = v.Args[1].Reg()
   186  		p.To.Type = obj.TYPE_REG
   187  		p.To.Reg = v.Reg()
   188  	case ssa.OpMIPS64ADDVconst,
   189  		ssa.OpMIPS64SUBVconst,
   190  		ssa.OpMIPS64ANDconst,
   191  		ssa.OpMIPS64ORconst,
   192  		ssa.OpMIPS64XORconst,
   193  		ssa.OpMIPS64NORconst,
   194  		ssa.OpMIPS64SLLVconst,
   195  		ssa.OpMIPS64SRLVconst,
   196  		ssa.OpMIPS64SRAVconst,
   197  		ssa.OpMIPS64SGTconst,
   198  		ssa.OpMIPS64SGTUconst:
   199  		p := s.Prog(v.Op.Asm())
   200  		p.From.Type = obj.TYPE_CONST
   201  		p.From.Offset = v.AuxInt
   202  		p.Reg = v.Args[0].Reg()
   203  		p.To.Type = obj.TYPE_REG
   204  		p.To.Reg = v.Reg()
   205  	case ssa.OpMIPS64MULV,
   206  		ssa.OpMIPS64MULVU,
   207  		ssa.OpMIPS64DIVV,
   208  		ssa.OpMIPS64DIVVU:
   209  		// result in hi,lo
   210  		p := s.Prog(v.Op.Asm())
   211  		p.From.Type = obj.TYPE_REG
   212  		p.From.Reg = v.Args[1].Reg()
   213  		p.Reg = v.Args[0].Reg()
   214  	case ssa.OpMIPS64MOVVconst:
   215  		r := v.Reg()
   216  		p := s.Prog(v.Op.Asm())
   217  		p.From.Type = obj.TYPE_CONST
   218  		p.From.Offset = v.AuxInt
   219  		p.To.Type = obj.TYPE_REG
   220  		p.To.Reg = r
   221  		if isFPreg(r) || isHILO(r) {
   222  			// cannot move into FP or special registers, use TMP as intermediate
   223  			p.To.Reg = mips.REGTMP
   224  			p = s.Prog(mips.AMOVV)
   225  			p.From.Type = obj.TYPE_REG
   226  			p.From.Reg = mips.REGTMP
   227  			p.To.Type = obj.TYPE_REG
   228  			p.To.Reg = r
   229  		}
   230  	case ssa.OpMIPS64MOVFconst,
   231  		ssa.OpMIPS64MOVDconst:
   232  		p := s.Prog(v.Op.Asm())
   233  		p.From.Type = obj.TYPE_FCONST
   234  		p.From.Val = math.Float64frombits(uint64(v.AuxInt))
   235  		p.To.Type = obj.TYPE_REG
   236  		p.To.Reg = v.Reg()
   237  	case ssa.OpMIPS64CMPEQF,
   238  		ssa.OpMIPS64CMPEQD,
   239  		ssa.OpMIPS64CMPGEF,
   240  		ssa.OpMIPS64CMPGED,
   241  		ssa.OpMIPS64CMPGTF,
   242  		ssa.OpMIPS64CMPGTD:
   243  		p := s.Prog(v.Op.Asm())
   244  		p.From.Type = obj.TYPE_REG
   245  		p.From.Reg = v.Args[0].Reg()
   246  		p.Reg = v.Args[1].Reg()
   247  	case ssa.OpMIPS64MOVVaddr:
   248  		p := s.Prog(mips.AMOVV)
   249  		p.From.Type = obj.TYPE_ADDR
   250  		p.From.Reg = v.Args[0].Reg()
   251  		var wantreg string
   252  		// MOVV $sym+off(base), R
   253  		// the assembler expands it as the following:
   254  		// - base is SP: add constant offset to SP (R29)
   255  		//               when constant is large, tmp register (R23) may be used
   256  		// - base is SB: load external address with relocation
   257  		switch v.Aux.(type) {
   258  		default:
   259  			v.Fatalf("aux is of unknown type %T", v.Aux)
   260  		case *obj.LSym:
   261  			wantreg = "SB"
   262  			gc.AddAux(&p.From, v)
   263  		case *gc.Node:
   264  			wantreg = "SP"
   265  			gc.AddAux(&p.From, v)
   266  		case nil:
   267  			// No sym, just MOVV $off(SP), R
   268  			wantreg = "SP"
   269  			p.From.Offset = v.AuxInt
   270  		}
   271  		if reg := v.Args[0].RegName(); reg != wantreg {
   272  			v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
   273  		}
   274  		p.To.Type = obj.TYPE_REG
   275  		p.To.Reg = v.Reg()
   276  	case ssa.OpMIPS64MOVBload,
   277  		ssa.OpMIPS64MOVBUload,
   278  		ssa.OpMIPS64MOVHload,
   279  		ssa.OpMIPS64MOVHUload,
   280  		ssa.OpMIPS64MOVWload,
   281  		ssa.OpMIPS64MOVWUload,
   282  		ssa.OpMIPS64MOVVload,
   283  		ssa.OpMIPS64MOVFload,
   284  		ssa.OpMIPS64MOVDload:
   285  		p := s.Prog(v.Op.Asm())
   286  		p.From.Type = obj.TYPE_MEM
   287  		p.From.Reg = v.Args[0].Reg()
   288  		gc.AddAux(&p.From, v)
   289  		p.To.Type = obj.TYPE_REG
   290  		p.To.Reg = v.Reg()
   291  	case ssa.OpMIPS64MOVBstore,
   292  		ssa.OpMIPS64MOVHstore,
   293  		ssa.OpMIPS64MOVWstore,
   294  		ssa.OpMIPS64MOVVstore,
   295  		ssa.OpMIPS64MOVFstore,
   296  		ssa.OpMIPS64MOVDstore:
   297  		p := s.Prog(v.Op.Asm())
   298  		p.From.Type = obj.TYPE_REG
   299  		p.From.Reg = v.Args[1].Reg()
   300  		p.To.Type = obj.TYPE_MEM
   301  		p.To.Reg = v.Args[0].Reg()
   302  		gc.AddAux(&p.To, v)
   303  	case ssa.OpMIPS64MOVBstorezero,
   304  		ssa.OpMIPS64MOVHstorezero,
   305  		ssa.OpMIPS64MOVWstorezero,
   306  		ssa.OpMIPS64MOVVstorezero:
   307  		p := s.Prog(v.Op.Asm())
   308  		p.From.Type = obj.TYPE_REG
   309  		p.From.Reg = mips.REGZERO
   310  		p.To.Type = obj.TYPE_MEM
   311  		p.To.Reg = v.Args[0].Reg()
   312  		gc.AddAux(&p.To, v)
   313  	case ssa.OpMIPS64MOVBreg,
   314  		ssa.OpMIPS64MOVBUreg,
   315  		ssa.OpMIPS64MOVHreg,
   316  		ssa.OpMIPS64MOVHUreg,
   317  		ssa.OpMIPS64MOVWreg,
   318  		ssa.OpMIPS64MOVWUreg:
   319  		a := v.Args[0]
   320  		for a.Op == ssa.OpCopy || a.Op == ssa.OpMIPS64MOVVreg {
   321  			a = a.Args[0]
   322  		}
   323  		if a.Op == ssa.OpLoadReg {
   324  			t := a.Type
   325  			switch {
   326  			case v.Op == ssa.OpMIPS64MOVBreg && t.Size() == 1 && t.IsSigned(),
   327  				v.Op == ssa.OpMIPS64MOVBUreg && t.Size() == 1 && !t.IsSigned(),
   328  				v.Op == ssa.OpMIPS64MOVHreg && t.Size() == 2 && t.IsSigned(),
   329  				v.Op == ssa.OpMIPS64MOVHUreg && t.Size() == 2 && !t.IsSigned(),
   330  				v.Op == ssa.OpMIPS64MOVWreg && t.Size() == 4 && t.IsSigned(),
   331  				v.Op == ssa.OpMIPS64MOVWUreg && t.Size() == 4 && !t.IsSigned():
   332  				// arg is a proper-typed load, already zero/sign-extended, don't extend again
   333  				if v.Reg() == v.Args[0].Reg() {
   334  					return
   335  				}
   336  				p := s.Prog(mips.AMOVV)
   337  				p.From.Type = obj.TYPE_REG
   338  				p.From.Reg = v.Args[0].Reg()
   339  				p.To.Type = obj.TYPE_REG
   340  				p.To.Reg = v.Reg()
   341  				return
   342  			default:
   343  			}
   344  		}
   345  		fallthrough
   346  	case ssa.OpMIPS64MOVWF,
   347  		ssa.OpMIPS64MOVWD,
   348  		ssa.OpMIPS64TRUNCFW,
   349  		ssa.OpMIPS64TRUNCDW,
   350  		ssa.OpMIPS64MOVVF,
   351  		ssa.OpMIPS64MOVVD,
   352  		ssa.OpMIPS64TRUNCFV,
   353  		ssa.OpMIPS64TRUNCDV,
   354  		ssa.OpMIPS64MOVFD,
   355  		ssa.OpMIPS64MOVDF,
   356  		ssa.OpMIPS64NEGF,
   357  		ssa.OpMIPS64NEGD:
   358  		p := s.Prog(v.Op.Asm())
   359  		p.From.Type = obj.TYPE_REG
   360  		p.From.Reg = v.Args[0].Reg()
   361  		p.To.Type = obj.TYPE_REG
   362  		p.To.Reg = v.Reg()
   363  	case ssa.OpMIPS64NEGV:
   364  		// SUB from REGZERO
   365  		p := s.Prog(mips.ASUBVU)
   366  		p.From.Type = obj.TYPE_REG
   367  		p.From.Reg = v.Args[0].Reg()
   368  		p.Reg = mips.REGZERO
   369  		p.To.Type = obj.TYPE_REG
   370  		p.To.Reg = v.Reg()
   371  	case ssa.OpMIPS64DUFFZERO:
   372  		// runtime.duffzero expects start address - 8 in R1
   373  		p := s.Prog(mips.ASUBVU)
   374  		p.From.Type = obj.TYPE_CONST
   375  		p.From.Offset = 8
   376  		p.Reg = v.Args[0].Reg()
   377  		p.To.Type = obj.TYPE_REG
   378  		p.To.Reg = mips.REG_R1
   379  		p = s.Prog(obj.ADUFFZERO)
   380  		p.To.Type = obj.TYPE_MEM
   381  		p.To.Name = obj.NAME_EXTERN
   382  		p.To.Sym = gc.Duffzero
   383  		p.To.Offset = v.AuxInt
   384  	case ssa.OpMIPS64LoweredZero:
   385  		// SUBV	$8, R1
   386  		// MOVV	R0, 8(R1)
   387  		// ADDV	$8, R1
   388  		// BNE	Rarg1, R1, -2(PC)
   389  		// arg1 is the address of the last element to zero
   390  		var sz int64
   391  		var mov obj.As
   392  		switch {
   393  		case v.AuxInt%8 == 0:
   394  			sz = 8
   395  			mov = mips.AMOVV
   396  		case v.AuxInt%4 == 0:
   397  			sz = 4
   398  			mov = mips.AMOVW
   399  		case v.AuxInt%2 == 0:
   400  			sz = 2
   401  			mov = mips.AMOVH
   402  		default:
   403  			sz = 1
   404  			mov = mips.AMOVB
   405  		}
   406  		p := s.Prog(mips.ASUBVU)
   407  		p.From.Type = obj.TYPE_CONST
   408  		p.From.Offset = sz
   409  		p.To.Type = obj.TYPE_REG
   410  		p.To.Reg = mips.REG_R1
   411  		p2 := s.Prog(mov)
   412  		p2.From.Type = obj.TYPE_REG
   413  		p2.From.Reg = mips.REGZERO
   414  		p2.To.Type = obj.TYPE_MEM
   415  		p2.To.Reg = mips.REG_R1
   416  		p2.To.Offset = sz
   417  		p3 := s.Prog(mips.AADDVU)
   418  		p3.From.Type = obj.TYPE_CONST
   419  		p3.From.Offset = sz
   420  		p3.To.Type = obj.TYPE_REG
   421  		p3.To.Reg = mips.REG_R1
   422  		p4 := s.Prog(mips.ABNE)
   423  		p4.From.Type = obj.TYPE_REG
   424  		p4.From.Reg = v.Args[1].Reg()
   425  		p4.Reg = mips.REG_R1
   426  		p4.To.Type = obj.TYPE_BRANCH
   427  		gc.Patch(p4, p2)
   428  	case ssa.OpMIPS64LoweredMove:
   429  		// SUBV	$8, R1
   430  		// MOVV	8(R1), Rtmp
   431  		// MOVV	Rtmp, (R2)
   432  		// ADDV	$8, R1
   433  		// ADDV	$8, R2
   434  		// BNE	Rarg2, R1, -4(PC)
   435  		// arg2 is the address of the last element of src
   436  		var sz int64
   437  		var mov obj.As
   438  		switch {
   439  		case v.AuxInt%8 == 0:
   440  			sz = 8
   441  			mov = mips.AMOVV
   442  		case v.AuxInt%4 == 0:
   443  			sz = 4
   444  			mov = mips.AMOVW
   445  		case v.AuxInt%2 == 0:
   446  			sz = 2
   447  			mov = mips.AMOVH
   448  		default:
   449  			sz = 1
   450  			mov = mips.AMOVB
   451  		}
   452  		p := s.Prog(mips.ASUBVU)
   453  		p.From.Type = obj.TYPE_CONST
   454  		p.From.Offset = sz
   455  		p.To.Type = obj.TYPE_REG
   456  		p.To.Reg = mips.REG_R1
   457  		p2 := s.Prog(mov)
   458  		p2.From.Type = obj.TYPE_MEM
   459  		p2.From.Reg = mips.REG_R1
   460  		p2.From.Offset = sz
   461  		p2.To.Type = obj.TYPE_REG
   462  		p2.To.Reg = mips.REGTMP
   463  		p3 := s.Prog(mov)
   464  		p3.From.Type = obj.TYPE_REG
   465  		p3.From.Reg = mips.REGTMP
   466  		p3.To.Type = obj.TYPE_MEM
   467  		p3.To.Reg = mips.REG_R2
   468  		p4 := s.Prog(mips.AADDVU)
   469  		p4.From.Type = obj.TYPE_CONST
   470  		p4.From.Offset = sz
   471  		p4.To.Type = obj.TYPE_REG
   472  		p4.To.Reg = mips.REG_R1
   473  		p5 := s.Prog(mips.AADDVU)
   474  		p5.From.Type = obj.TYPE_CONST
   475  		p5.From.Offset = sz
   476  		p5.To.Type = obj.TYPE_REG
   477  		p5.To.Reg = mips.REG_R2
   478  		p6 := s.Prog(mips.ABNE)
   479  		p6.From.Type = obj.TYPE_REG
   480  		p6.From.Reg = v.Args[2].Reg()
   481  		p6.Reg = mips.REG_R1
   482  		p6.To.Type = obj.TYPE_BRANCH
   483  		gc.Patch(p6, p2)
   484  	case ssa.OpMIPS64CALLstatic, ssa.OpMIPS64CALLclosure, ssa.OpMIPS64CALLinter:
   485  		s.Call(v)
   486  	case ssa.OpMIPS64LoweredAtomicLoad32, ssa.OpMIPS64LoweredAtomicLoad64:
   487  		as := mips.AMOVV
   488  		if v.Op == ssa.OpMIPS64LoweredAtomicLoad32 {
   489  			as = mips.AMOVW
   490  		}
   491  		s.Prog(mips.ASYNC)
   492  		p := s.Prog(as)
   493  		p.From.Type = obj.TYPE_MEM
   494  		p.From.Reg = v.Args[0].Reg()
   495  		p.To.Type = obj.TYPE_REG
   496  		p.To.Reg = v.Reg0()
   497  		s.Prog(mips.ASYNC)
   498  	case ssa.OpMIPS64LoweredAtomicStore32, ssa.OpMIPS64LoweredAtomicStore64:
   499  		as := mips.AMOVV
   500  		if v.Op == ssa.OpMIPS64LoweredAtomicStore32 {
   501  			as = mips.AMOVW
   502  		}
   503  		s.Prog(mips.ASYNC)
   504  		p := s.Prog(as)
   505  		p.From.Type = obj.TYPE_REG
   506  		p.From.Reg = v.Args[1].Reg()
   507  		p.To.Type = obj.TYPE_MEM
   508  		p.To.Reg = v.Args[0].Reg()
   509  		s.Prog(mips.ASYNC)
   510  	case ssa.OpMIPS64LoweredAtomicStorezero32, ssa.OpMIPS64LoweredAtomicStorezero64:
   511  		as := mips.AMOVV
   512  		if v.Op == ssa.OpMIPS64LoweredAtomicStorezero32 {
   513  			as = mips.AMOVW
   514  		}
   515  		s.Prog(mips.ASYNC)
   516  		p := s.Prog(as)
   517  		p.From.Type = obj.TYPE_REG
   518  		p.From.Reg = mips.REGZERO
   519  		p.To.Type = obj.TYPE_MEM
   520  		p.To.Reg = v.Args[0].Reg()
   521  		s.Prog(mips.ASYNC)
   522  	case ssa.OpMIPS64LoweredAtomicExchange32, ssa.OpMIPS64LoweredAtomicExchange64:
   523  		// SYNC
   524  		// MOVV	Rarg1, Rtmp
   525  		// LL	(Rarg0), Rout
   526  		// SC	Rtmp, (Rarg0)
   527  		// BEQ	Rtmp, -3(PC)
   528  		// SYNC
   529  		ll := mips.ALLV
   530  		sc := mips.ASCV
   531  		if v.Op == ssa.OpMIPS64LoweredAtomicExchange32 {
   532  			ll = mips.ALL
   533  			sc = mips.ASC
   534  		}
   535  		s.Prog(mips.ASYNC)
   536  		p := s.Prog(mips.AMOVV)
   537  		p.From.Type = obj.TYPE_REG
   538  		p.From.Reg = v.Args[1].Reg()
   539  		p.To.Type = obj.TYPE_REG
   540  		p.To.Reg = mips.REGTMP
   541  		p1 := s.Prog(ll)
   542  		p1.From.Type = obj.TYPE_MEM
   543  		p1.From.Reg = v.Args[0].Reg()
   544  		p1.To.Type = obj.TYPE_REG
   545  		p1.To.Reg = v.Reg0()
   546  		p2 := s.Prog(sc)
   547  		p2.From.Type = obj.TYPE_REG
   548  		p2.From.Reg = mips.REGTMP
   549  		p2.To.Type = obj.TYPE_MEM
   550  		p2.To.Reg = v.Args[0].Reg()
   551  		p3 := s.Prog(mips.ABEQ)
   552  		p3.From.Type = obj.TYPE_REG
   553  		p3.From.Reg = mips.REGTMP
   554  		p3.To.Type = obj.TYPE_BRANCH
   555  		gc.Patch(p3, p)
   556  		s.Prog(mips.ASYNC)
   557  	case ssa.OpMIPS64LoweredAtomicAdd32, ssa.OpMIPS64LoweredAtomicAdd64:
   558  		// SYNC
   559  		// LL	(Rarg0), Rout
   560  		// ADDV Rarg1, Rout, Rtmp
   561  		// SC	Rtmp, (Rarg0)
   562  		// BEQ	Rtmp, -3(PC)
   563  		// SYNC
   564  		// ADDV Rarg1, Rout
   565  		ll := mips.ALLV
   566  		sc := mips.ASCV
   567  		if v.Op == ssa.OpMIPS64LoweredAtomicAdd32 {
   568  			ll = mips.ALL
   569  			sc = mips.ASC
   570  		}
   571  		s.Prog(mips.ASYNC)
   572  		p := s.Prog(ll)
   573  		p.From.Type = obj.TYPE_MEM
   574  		p.From.Reg = v.Args[0].Reg()
   575  		p.To.Type = obj.TYPE_REG
   576  		p.To.Reg = v.Reg0()
   577  		p1 := s.Prog(mips.AADDVU)
   578  		p1.From.Type = obj.TYPE_REG
   579  		p1.From.Reg = v.Args[1].Reg()
   580  		p1.Reg = v.Reg0()
   581  		p1.To.Type = obj.TYPE_REG
   582  		p1.To.Reg = mips.REGTMP
   583  		p2 := s.Prog(sc)
   584  		p2.From.Type = obj.TYPE_REG
   585  		p2.From.Reg = mips.REGTMP
   586  		p2.To.Type = obj.TYPE_MEM
   587  		p2.To.Reg = v.Args[0].Reg()
   588  		p3 := s.Prog(mips.ABEQ)
   589  		p3.From.Type = obj.TYPE_REG
   590  		p3.From.Reg = mips.REGTMP
   591  		p3.To.Type = obj.TYPE_BRANCH
   592  		gc.Patch(p3, p)
   593  		s.Prog(mips.ASYNC)
   594  		p4 := s.Prog(mips.AADDVU)
   595  		p4.From.Type = obj.TYPE_REG
   596  		p4.From.Reg = v.Args[1].Reg()
   597  		p4.Reg = v.Reg0()
   598  		p4.To.Type = obj.TYPE_REG
   599  		p4.To.Reg = v.Reg0()
   600  	case ssa.OpMIPS64LoweredAtomicAddconst32, ssa.OpMIPS64LoweredAtomicAddconst64:
   601  		// SYNC
   602  		// LL	(Rarg0), Rout
   603  		// ADDV $auxint, Rout, Rtmp
   604  		// SC	Rtmp, (Rarg0)
   605  		// BEQ	Rtmp, -3(PC)
   606  		// SYNC
   607  		// ADDV $auxint, Rout
   608  		ll := mips.ALLV
   609  		sc := mips.ASCV
   610  		if v.Op == ssa.OpMIPS64LoweredAtomicAddconst32 {
   611  			ll = mips.ALL
   612  			sc = mips.ASC
   613  		}
   614  		s.Prog(mips.ASYNC)
   615  		p := s.Prog(ll)
   616  		p.From.Type = obj.TYPE_MEM
   617  		p.From.Reg = v.Args[0].Reg()
   618  		p.To.Type = obj.TYPE_REG
   619  		p.To.Reg = v.Reg0()
   620  		p1 := s.Prog(mips.AADDVU)
   621  		p1.From.Type = obj.TYPE_CONST
   622  		p1.From.Offset = v.AuxInt
   623  		p1.Reg = v.Reg0()
   624  		p1.To.Type = obj.TYPE_REG
   625  		p1.To.Reg = mips.REGTMP
   626  		p2 := s.Prog(sc)
   627  		p2.From.Type = obj.TYPE_REG
   628  		p2.From.Reg = mips.REGTMP
   629  		p2.To.Type = obj.TYPE_MEM
   630  		p2.To.Reg = v.Args[0].Reg()
   631  		p3 := s.Prog(mips.ABEQ)
   632  		p3.From.Type = obj.TYPE_REG
   633  		p3.From.Reg = mips.REGTMP
   634  		p3.To.Type = obj.TYPE_BRANCH
   635  		gc.Patch(p3, p)
   636  		s.Prog(mips.ASYNC)
   637  		p4 := s.Prog(mips.AADDVU)
   638  		p4.From.Type = obj.TYPE_CONST
   639  		p4.From.Offset = v.AuxInt
   640  		p4.Reg = v.Reg0()
   641  		p4.To.Type = obj.TYPE_REG
   642  		p4.To.Reg = v.Reg0()
   643  	case ssa.OpMIPS64LoweredAtomicCas32, ssa.OpMIPS64LoweredAtomicCas64:
   644  		// MOVV $0, Rout
   645  		// SYNC
   646  		// LL	(Rarg0), Rtmp
   647  		// BNE	Rtmp, Rarg1, 4(PC)
   648  		// MOVV Rarg2, Rout
   649  		// SC	Rout, (Rarg0)
   650  		// BEQ	Rout, -4(PC)
   651  		// SYNC
   652  		ll := mips.ALLV
   653  		sc := mips.ASCV
   654  		if v.Op == ssa.OpMIPS64LoweredAtomicCas32 {
   655  			ll = mips.ALL
   656  			sc = mips.ASC
   657  		}
   658  		p := s.Prog(mips.AMOVV)
   659  		p.From.Type = obj.TYPE_REG
   660  		p.From.Reg = mips.REGZERO
   661  		p.To.Type = obj.TYPE_REG
   662  		p.To.Reg = v.Reg0()
   663  		s.Prog(mips.ASYNC)
   664  		p1 := s.Prog(ll)
   665  		p1.From.Type = obj.TYPE_MEM
   666  		p1.From.Reg = v.Args[0].Reg()
   667  		p1.To.Type = obj.TYPE_REG
   668  		p1.To.Reg = mips.REGTMP
   669  		p2 := s.Prog(mips.ABNE)
   670  		p2.From.Type = obj.TYPE_REG
   671  		p2.From.Reg = v.Args[1].Reg()
   672  		p2.Reg = mips.REGTMP
   673  		p2.To.Type = obj.TYPE_BRANCH
   674  		p3 := s.Prog(mips.AMOVV)
   675  		p3.From.Type = obj.TYPE_REG
   676  		p3.From.Reg = v.Args[2].Reg()
   677  		p3.To.Type = obj.TYPE_REG
   678  		p3.To.Reg = v.Reg0()
   679  		p4 := s.Prog(sc)
   680  		p4.From.Type = obj.TYPE_REG
   681  		p4.From.Reg = v.Reg0()
   682  		p4.To.Type = obj.TYPE_MEM
   683  		p4.To.Reg = v.Args[0].Reg()
   684  		p5 := s.Prog(mips.ABEQ)
   685  		p5.From.Type = obj.TYPE_REG
   686  		p5.From.Reg = v.Reg0()
   687  		p5.To.Type = obj.TYPE_BRANCH
   688  		gc.Patch(p5, p1)
   689  		p6 := s.Prog(mips.ASYNC)
   690  		gc.Patch(p2, p6)
   691  	case ssa.OpMIPS64LoweredNilCheck:
   692  		// Issue a load which will fault if arg is nil.
   693  		p := s.Prog(mips.AMOVB)
   694  		p.From.Type = obj.TYPE_MEM
   695  		p.From.Reg = v.Args[0].Reg()
   696  		gc.AddAux(&p.From, v)
   697  		p.To.Type = obj.TYPE_REG
   698  		p.To.Reg = mips.REGTMP
   699  		if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
   700  			gc.Warnl(v.Pos, "generated nil check")
   701  		}
   702  	case ssa.OpMIPS64FPFlagTrue,
   703  		ssa.OpMIPS64FPFlagFalse:
   704  		// MOVV	$0, r
   705  		// BFPF	2(PC)
   706  		// MOVV	$1, r
   707  		branch := mips.ABFPF
   708  		if v.Op == ssa.OpMIPS64FPFlagFalse {
   709  			branch = mips.ABFPT
   710  		}
   711  		p := s.Prog(mips.AMOVV)
   712  		p.From.Type = obj.TYPE_REG
   713  		p.From.Reg = mips.REGZERO
   714  		p.To.Type = obj.TYPE_REG
   715  		p.To.Reg = v.Reg()
   716  		p2 := s.Prog(branch)
   717  		p2.To.Type = obj.TYPE_BRANCH
   718  		p3 := s.Prog(mips.AMOVV)
   719  		p3.From.Type = obj.TYPE_CONST
   720  		p3.From.Offset = 1
   721  		p3.To.Type = obj.TYPE_REG
   722  		p3.To.Reg = v.Reg()
   723  		p4 := s.Prog(obj.ANOP) // not a machine instruction, for branch to land
   724  		gc.Patch(p2, p4)
   725  	case ssa.OpMIPS64LoweredGetClosurePtr:
   726  		// Closure pointer is R22 (mips.REGCTXT).
   727  		gc.CheckLoweredGetClosurePtr(v)
   728  	case ssa.OpMIPS64LoweredGetCallerSP:
   729  		// caller's SP is FixedFrameSize below the address of the first arg
   730  		p := s.Prog(mips.AMOVV)
   731  		p.From.Type = obj.TYPE_ADDR
   732  		p.From.Offset = -gc.Ctxt.FixedFrameSize()
   733  		p.From.Name = obj.NAME_PARAM
   734  		p.To.Type = obj.TYPE_REG
   735  		p.To.Reg = v.Reg()
   736  	case ssa.OpClobber:
   737  		// TODO: implement for clobberdead experiment. Nop is ok for now.
   738  	default:
   739  		v.Fatalf("genValue not implemented: %s", v.LongString())
   740  	}
   741  }
   742  
   743  var blockJump = map[ssa.BlockKind]struct {
   744  	asm, invasm obj.As
   745  }{
   746  	ssa.BlockMIPS64EQ:  {mips.ABEQ, mips.ABNE},
   747  	ssa.BlockMIPS64NE:  {mips.ABNE, mips.ABEQ},
   748  	ssa.BlockMIPS64LTZ: {mips.ABLTZ, mips.ABGEZ},
   749  	ssa.BlockMIPS64GEZ: {mips.ABGEZ, mips.ABLTZ},
   750  	ssa.BlockMIPS64LEZ: {mips.ABLEZ, mips.ABGTZ},
   751  	ssa.BlockMIPS64GTZ: {mips.ABGTZ, mips.ABLEZ},
   752  	ssa.BlockMIPS64FPT: {mips.ABFPT, mips.ABFPF},
   753  	ssa.BlockMIPS64FPF: {mips.ABFPF, mips.ABFPT},
   754  }
   755  
   756  func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
   757  	switch b.Kind {
   758  	case ssa.BlockPlain:
   759  		if b.Succs[0].Block() != next {
   760  			p := s.Prog(obj.AJMP)
   761  			p.To.Type = obj.TYPE_BRANCH
   762  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   763  		}
   764  	case ssa.BlockDefer:
   765  		// defer returns in R1:
   766  		// 0 if we should continue executing
   767  		// 1 if we should jump to deferreturn call
   768  		p := s.Prog(mips.ABNE)
   769  		p.From.Type = obj.TYPE_REG
   770  		p.From.Reg = mips.REGZERO
   771  		p.Reg = mips.REG_R1
   772  		p.To.Type = obj.TYPE_BRANCH
   773  		s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
   774  		if b.Succs[0].Block() != next {
   775  			p := s.Prog(obj.AJMP)
   776  			p.To.Type = obj.TYPE_BRANCH
   777  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   778  		}
   779  	case ssa.BlockExit:
   780  		s.Prog(obj.AUNDEF) // tell plive.go that we never reach here
   781  	case ssa.BlockRet:
   782  		s.Prog(obj.ARET)
   783  	case ssa.BlockRetJmp:
   784  		p := s.Prog(obj.ARET)
   785  		p.To.Type = obj.TYPE_MEM
   786  		p.To.Name = obj.NAME_EXTERN
   787  		p.To.Sym = b.Aux.(*obj.LSym)
   788  	case ssa.BlockMIPS64EQ, ssa.BlockMIPS64NE,
   789  		ssa.BlockMIPS64LTZ, ssa.BlockMIPS64GEZ,
   790  		ssa.BlockMIPS64LEZ, ssa.BlockMIPS64GTZ,
   791  		ssa.BlockMIPS64FPT, ssa.BlockMIPS64FPF:
   792  		jmp := blockJump[b.Kind]
   793  		var p *obj.Prog
   794  		switch next {
   795  		case b.Succs[0].Block():
   796  			p = s.Prog(jmp.invasm)
   797  			p.To.Type = obj.TYPE_BRANCH
   798  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
   799  		case b.Succs[1].Block():
   800  			p = s.Prog(jmp.asm)
   801  			p.To.Type = obj.TYPE_BRANCH
   802  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   803  		default:
   804  			p = s.Prog(jmp.asm)
   805  			p.To.Type = obj.TYPE_BRANCH
   806  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   807  			q := s.Prog(obj.AJMP)
   808  			q.To.Type = obj.TYPE_BRANCH
   809  			s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
   810  		}
   811  		if !b.Control.Type.IsFlags() {
   812  			p.From.Type = obj.TYPE_REG
   813  			p.From.Reg = b.Control.Reg()
   814  		}
   815  	default:
   816  		b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
   817  	}
   818  }