Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/compile/internal/mips/ssa.go

Documentation: cmd/compile/internal/mips

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

View as plain text