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

     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.OpMIPSCALLtail:
   479  		s.TailCall(v)
   480  	case ssa.OpMIPSLoweredWB:
   481  		p := s.Prog(obj.ACALL)
   482  		p.To.Type = obj.TYPE_MEM
   483  		p.To.Name = obj.NAME_EXTERN
   484  		p.To.Sym = v.Aux.(*obj.LSym)
   485  	case ssa.OpMIPSLoweredPanicBoundsA, ssa.OpMIPSLoweredPanicBoundsB, ssa.OpMIPSLoweredPanicBoundsC:
   486  		p := s.Prog(obj.ACALL)
   487  		p.To.Type = obj.TYPE_MEM
   488  		p.To.Name = obj.NAME_EXTERN
   489  		p.To.Sym = ssagen.BoundsCheckFunc[v.AuxInt]
   490  		s.UseArgs(8) // space used in callee args area by assembly stubs
   491  	case ssa.OpMIPSLoweredPanicExtendA, ssa.OpMIPSLoweredPanicExtendB, ssa.OpMIPSLoweredPanicExtendC:
   492  		p := s.Prog(obj.ACALL)
   493  		p.To.Type = obj.TYPE_MEM
   494  		p.To.Name = obj.NAME_EXTERN
   495  		p.To.Sym = ssagen.ExtendCheckFunc[v.AuxInt]
   496  		s.UseArgs(12) // space used in callee args area by assembly stubs
   497  	case ssa.OpMIPSLoweredAtomicLoad8,
   498  		ssa.OpMIPSLoweredAtomicLoad32:
   499  		s.Prog(mips.ASYNC)
   500  
   501  		var op obj.As
   502  		switch v.Op {
   503  		case ssa.OpMIPSLoweredAtomicLoad8:
   504  			op = mips.AMOVB
   505  		case ssa.OpMIPSLoweredAtomicLoad32:
   506  			op = mips.AMOVW
   507  		}
   508  		p := s.Prog(op)
   509  		p.From.Type = obj.TYPE_MEM
   510  		p.From.Reg = v.Args[0].Reg()
   511  		p.To.Type = obj.TYPE_REG
   512  		p.To.Reg = v.Reg0()
   513  
   514  		s.Prog(mips.ASYNC)
   515  	case ssa.OpMIPSLoweredAtomicStore8,
   516  		ssa.OpMIPSLoweredAtomicStore32:
   517  		s.Prog(mips.ASYNC)
   518  
   519  		var op obj.As
   520  		switch v.Op {
   521  		case ssa.OpMIPSLoweredAtomicStore8:
   522  			op = mips.AMOVB
   523  		case ssa.OpMIPSLoweredAtomicStore32:
   524  			op = mips.AMOVW
   525  		}
   526  		p := s.Prog(op)
   527  		p.From.Type = obj.TYPE_REG
   528  		p.From.Reg = v.Args[1].Reg()
   529  		p.To.Type = obj.TYPE_MEM
   530  		p.To.Reg = v.Args[0].Reg()
   531  
   532  		s.Prog(mips.ASYNC)
   533  	case ssa.OpMIPSLoweredAtomicStorezero:
   534  		s.Prog(mips.ASYNC)
   535  
   536  		p := s.Prog(mips.AMOVW)
   537  		p.From.Type = obj.TYPE_REG
   538  		p.From.Reg = mips.REGZERO
   539  		p.To.Type = obj.TYPE_MEM
   540  		p.To.Reg = v.Args[0].Reg()
   541  
   542  		s.Prog(mips.ASYNC)
   543  	case ssa.OpMIPSLoweredAtomicExchange:
   544  		// SYNC
   545  		// MOVW Rarg1, Rtmp
   546  		// LL	(Rarg0), Rout
   547  		// SC	Rtmp, (Rarg0)
   548  		// BEQ	Rtmp, -3(PC)
   549  		// SYNC
   550  		s.Prog(mips.ASYNC)
   551  
   552  		p := s.Prog(mips.AMOVW)
   553  		p.From.Type = obj.TYPE_REG
   554  		p.From.Reg = v.Args[1].Reg()
   555  		p.To.Type = obj.TYPE_REG
   556  		p.To.Reg = mips.REGTMP
   557  
   558  		p1 := s.Prog(mips.ALL)
   559  		p1.From.Type = obj.TYPE_MEM
   560  		p1.From.Reg = v.Args[0].Reg()
   561  		p1.To.Type = obj.TYPE_REG
   562  		p1.To.Reg = v.Reg0()
   563  
   564  		p2 := s.Prog(mips.ASC)
   565  		p2.From.Type = obj.TYPE_REG
   566  		p2.From.Reg = mips.REGTMP
   567  		p2.To.Type = obj.TYPE_MEM
   568  		p2.To.Reg = v.Args[0].Reg()
   569  
   570  		p3 := s.Prog(mips.ABEQ)
   571  		p3.From.Type = obj.TYPE_REG
   572  		p3.From.Reg = mips.REGTMP
   573  		p3.To.Type = obj.TYPE_BRANCH
   574  		p3.To.SetTarget(p)
   575  
   576  		s.Prog(mips.ASYNC)
   577  	case ssa.OpMIPSLoweredAtomicAdd:
   578  		// SYNC
   579  		// LL	(Rarg0), Rout
   580  		// ADDU Rarg1, Rout, Rtmp
   581  		// SC	Rtmp, (Rarg0)
   582  		// BEQ	Rtmp, -3(PC)
   583  		// SYNC
   584  		// ADDU Rarg1, Rout
   585  		s.Prog(mips.ASYNC)
   586  
   587  		p := s.Prog(mips.ALL)
   588  		p.From.Type = obj.TYPE_MEM
   589  		p.From.Reg = v.Args[0].Reg()
   590  		p.To.Type = obj.TYPE_REG
   591  		p.To.Reg = v.Reg0()
   592  
   593  		p1 := s.Prog(mips.AADDU)
   594  		p1.From.Type = obj.TYPE_REG
   595  		p1.From.Reg = v.Args[1].Reg()
   596  		p1.Reg = v.Reg0()
   597  		p1.To.Type = obj.TYPE_REG
   598  		p1.To.Reg = mips.REGTMP
   599  
   600  		p2 := s.Prog(mips.ASC)
   601  		p2.From.Type = obj.TYPE_REG
   602  		p2.From.Reg = mips.REGTMP
   603  		p2.To.Type = obj.TYPE_MEM
   604  		p2.To.Reg = v.Args[0].Reg()
   605  
   606  		p3 := s.Prog(mips.ABEQ)
   607  		p3.From.Type = obj.TYPE_REG
   608  		p3.From.Reg = mips.REGTMP
   609  		p3.To.Type = obj.TYPE_BRANCH
   610  		p3.To.SetTarget(p)
   611  
   612  		s.Prog(mips.ASYNC)
   613  
   614  		p4 := s.Prog(mips.AADDU)
   615  		p4.From.Type = obj.TYPE_REG
   616  		p4.From.Reg = v.Args[1].Reg()
   617  		p4.Reg = v.Reg0()
   618  		p4.To.Type = obj.TYPE_REG
   619  		p4.To.Reg = v.Reg0()
   620  
   621  	case ssa.OpMIPSLoweredAtomicAddconst:
   622  		// SYNC
   623  		// LL	(Rarg0), Rout
   624  		// ADDU $auxInt, Rout, Rtmp
   625  		// SC	Rtmp, (Rarg0)
   626  		// BEQ	Rtmp, -3(PC)
   627  		// SYNC
   628  		// ADDU $auxInt, Rout
   629  		s.Prog(mips.ASYNC)
   630  
   631  		p := s.Prog(mips.ALL)
   632  		p.From.Type = obj.TYPE_MEM
   633  		p.From.Reg = v.Args[0].Reg()
   634  		p.To.Type = obj.TYPE_REG
   635  		p.To.Reg = v.Reg0()
   636  
   637  		p1 := s.Prog(mips.AADDU)
   638  		p1.From.Type = obj.TYPE_CONST
   639  		p1.From.Offset = v.AuxInt
   640  		p1.Reg = v.Reg0()
   641  		p1.To.Type = obj.TYPE_REG
   642  		p1.To.Reg = mips.REGTMP
   643  
   644  		p2 := s.Prog(mips.ASC)
   645  		p2.From.Type = obj.TYPE_REG
   646  		p2.From.Reg = mips.REGTMP
   647  		p2.To.Type = obj.TYPE_MEM
   648  		p2.To.Reg = v.Args[0].Reg()
   649  
   650  		p3 := s.Prog(mips.ABEQ)
   651  		p3.From.Type = obj.TYPE_REG
   652  		p3.From.Reg = mips.REGTMP
   653  		p3.To.Type = obj.TYPE_BRANCH
   654  		p3.To.SetTarget(p)
   655  
   656  		s.Prog(mips.ASYNC)
   657  
   658  		p4 := s.Prog(mips.AADDU)
   659  		p4.From.Type = obj.TYPE_CONST
   660  		p4.From.Offset = v.AuxInt
   661  		p4.Reg = v.Reg0()
   662  		p4.To.Type = obj.TYPE_REG
   663  		p4.To.Reg = v.Reg0()
   664  
   665  	case ssa.OpMIPSLoweredAtomicAnd,
   666  		ssa.OpMIPSLoweredAtomicOr:
   667  		// SYNC
   668  		// LL	(Rarg0), Rtmp
   669  		// AND/OR	Rarg1, Rtmp
   670  		// SC	Rtmp, (Rarg0)
   671  		// BEQ	Rtmp, -3(PC)
   672  		// SYNC
   673  		s.Prog(mips.ASYNC)
   674  
   675  		p := s.Prog(mips.ALL)
   676  		p.From.Type = obj.TYPE_MEM
   677  		p.From.Reg = v.Args[0].Reg()
   678  		p.To.Type = obj.TYPE_REG
   679  		p.To.Reg = mips.REGTMP
   680  
   681  		p1 := s.Prog(v.Op.Asm())
   682  		p1.From.Type = obj.TYPE_REG
   683  		p1.From.Reg = v.Args[1].Reg()
   684  		p1.Reg = mips.REGTMP
   685  		p1.To.Type = obj.TYPE_REG
   686  		p1.To.Reg = mips.REGTMP
   687  
   688  		p2 := s.Prog(mips.ASC)
   689  		p2.From.Type = obj.TYPE_REG
   690  		p2.From.Reg = mips.REGTMP
   691  		p2.To.Type = obj.TYPE_MEM
   692  		p2.To.Reg = v.Args[0].Reg()
   693  
   694  		p3 := s.Prog(mips.ABEQ)
   695  		p3.From.Type = obj.TYPE_REG
   696  		p3.From.Reg = mips.REGTMP
   697  		p3.To.Type = obj.TYPE_BRANCH
   698  		p3.To.SetTarget(p)
   699  
   700  		s.Prog(mips.ASYNC)
   701  
   702  	case ssa.OpMIPSLoweredAtomicCas:
   703  		// MOVW $0, Rout
   704  		// SYNC
   705  		// LL	(Rarg0), Rtmp
   706  		// BNE	Rtmp, Rarg1, 4(PC)
   707  		// MOVW Rarg2, Rout
   708  		// SC	Rout, (Rarg0)
   709  		// BEQ	Rout, -4(PC)
   710  		// SYNC
   711  		p := s.Prog(mips.AMOVW)
   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.Reg0()
   716  
   717  		s.Prog(mips.ASYNC)
   718  
   719  		p1 := s.Prog(mips.ALL)
   720  		p1.From.Type = obj.TYPE_MEM
   721  		p1.From.Reg = v.Args[0].Reg()
   722  		p1.To.Type = obj.TYPE_REG
   723  		p1.To.Reg = mips.REGTMP
   724  
   725  		p2 := s.Prog(mips.ABNE)
   726  		p2.From.Type = obj.TYPE_REG
   727  		p2.From.Reg = v.Args[1].Reg()
   728  		p2.Reg = mips.REGTMP
   729  		p2.To.Type = obj.TYPE_BRANCH
   730  
   731  		p3 := s.Prog(mips.AMOVW)
   732  		p3.From.Type = obj.TYPE_REG
   733  		p3.From.Reg = v.Args[2].Reg()
   734  		p3.To.Type = obj.TYPE_REG
   735  		p3.To.Reg = v.Reg0()
   736  
   737  		p4 := s.Prog(mips.ASC)
   738  		p4.From.Type = obj.TYPE_REG
   739  		p4.From.Reg = v.Reg0()
   740  		p4.To.Type = obj.TYPE_MEM
   741  		p4.To.Reg = v.Args[0].Reg()
   742  
   743  		p5 := s.Prog(mips.ABEQ)
   744  		p5.From.Type = obj.TYPE_REG
   745  		p5.From.Reg = v.Reg0()
   746  		p5.To.Type = obj.TYPE_BRANCH
   747  		p5.To.SetTarget(p1)
   748  
   749  		s.Prog(mips.ASYNC)
   750  
   751  		p6 := s.Prog(obj.ANOP)
   752  		p2.To.SetTarget(p6)
   753  
   754  	case ssa.OpMIPSLoweredNilCheck:
   755  		// Issue a load which will fault if arg is nil.
   756  		p := s.Prog(mips.AMOVB)
   757  		p.From.Type = obj.TYPE_MEM
   758  		p.From.Reg = v.Args[0].Reg()
   759  		ssagen.AddAux(&p.From, v)
   760  		p.To.Type = obj.TYPE_REG
   761  		p.To.Reg = mips.REGTMP
   762  		if logopt.Enabled() {
   763  			logopt.LogOpt(v.Pos, "nilcheck", "genssa", v.Block.Func.Name)
   764  		}
   765  		if base.Debug.Nil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
   766  			base.WarnfAt(v.Pos, "generated nil check")
   767  		}
   768  	case ssa.OpMIPSFPFlagTrue,
   769  		ssa.OpMIPSFPFlagFalse:
   770  		// MOVW		$1, r
   771  		// CMOVF	R0, r
   772  
   773  		cmov := mips.ACMOVF
   774  		if v.Op == ssa.OpMIPSFPFlagFalse {
   775  			cmov = mips.ACMOVT
   776  		}
   777  		p := s.Prog(mips.AMOVW)
   778  		p.From.Type = obj.TYPE_CONST
   779  		p.From.Offset = 1
   780  		p.To.Type = obj.TYPE_REG
   781  		p.To.Reg = v.Reg()
   782  		p1 := s.Prog(cmov)
   783  		p1.From.Type = obj.TYPE_REG
   784  		p1.From.Reg = mips.REGZERO
   785  		p1.To.Type = obj.TYPE_REG
   786  		p1.To.Reg = v.Reg()
   787  
   788  	case ssa.OpMIPSLoweredGetClosurePtr:
   789  		// Closure pointer is R22 (mips.REGCTXT).
   790  		ssagen.CheckLoweredGetClosurePtr(v)
   791  	case ssa.OpMIPSLoweredGetCallerSP:
   792  		// caller's SP is FixedFrameSize below the address of the first arg
   793  		p := s.Prog(mips.AMOVW)
   794  		p.From.Type = obj.TYPE_ADDR
   795  		p.From.Offset = -base.Ctxt.FixedFrameSize()
   796  		p.From.Name = obj.NAME_PARAM
   797  		p.To.Type = obj.TYPE_REG
   798  		p.To.Reg = v.Reg()
   799  	case ssa.OpMIPSLoweredGetCallerPC:
   800  		p := s.Prog(obj.AGETCALLERPC)
   801  		p.To.Type = obj.TYPE_REG
   802  		p.To.Reg = v.Reg()
   803  	case ssa.OpClobber, ssa.OpClobberReg:
   804  		// TODO: implement for clobberdead experiment. Nop is ok for now.
   805  	default:
   806  		v.Fatalf("genValue not implemented: %s", v.LongString())
   807  	}
   808  }
   809  
   810  var blockJump = map[ssa.BlockKind]struct {
   811  	asm, invasm obj.As
   812  }{
   813  	ssa.BlockMIPSEQ:  {mips.ABEQ, mips.ABNE},
   814  	ssa.BlockMIPSNE:  {mips.ABNE, mips.ABEQ},
   815  	ssa.BlockMIPSLTZ: {mips.ABLTZ, mips.ABGEZ},
   816  	ssa.BlockMIPSGEZ: {mips.ABGEZ, mips.ABLTZ},
   817  	ssa.BlockMIPSLEZ: {mips.ABLEZ, mips.ABGTZ},
   818  	ssa.BlockMIPSGTZ: {mips.ABGTZ, mips.ABLEZ},
   819  	ssa.BlockMIPSFPT: {mips.ABFPT, mips.ABFPF},
   820  	ssa.BlockMIPSFPF: {mips.ABFPF, mips.ABFPT},
   821  }
   822  
   823  func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
   824  	switch b.Kind {
   825  	case ssa.BlockPlain:
   826  		if b.Succs[0].Block() != next {
   827  			p := s.Prog(obj.AJMP)
   828  			p.To.Type = obj.TYPE_BRANCH
   829  			s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
   830  		}
   831  	case ssa.BlockDefer:
   832  		// defer returns in R1:
   833  		// 0 if we should continue executing
   834  		// 1 if we should jump to deferreturn call
   835  		p := s.Prog(mips.ABNE)
   836  		p.From.Type = obj.TYPE_REG
   837  		p.From.Reg = mips.REGZERO
   838  		p.Reg = mips.REG_R1
   839  		p.To.Type = obj.TYPE_BRANCH
   840  		s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[1].Block()})
   841  		if b.Succs[0].Block() != next {
   842  			p := s.Prog(obj.AJMP)
   843  			p.To.Type = obj.TYPE_BRANCH
   844  			s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
   845  		}
   846  	case ssa.BlockExit, ssa.BlockRetJmp:
   847  	case ssa.BlockRet:
   848  		s.Prog(obj.ARET)
   849  	case ssa.BlockMIPSEQ, ssa.BlockMIPSNE,
   850  		ssa.BlockMIPSLTZ, ssa.BlockMIPSGEZ,
   851  		ssa.BlockMIPSLEZ, ssa.BlockMIPSGTZ,
   852  		ssa.BlockMIPSFPT, ssa.BlockMIPSFPF:
   853  		jmp := blockJump[b.Kind]
   854  		var p *obj.Prog
   855  		switch next {
   856  		case b.Succs[0].Block():
   857  			p = s.Br(jmp.invasm, b.Succs[1].Block())
   858  		case b.Succs[1].Block():
   859  			p = s.Br(jmp.asm, b.Succs[0].Block())
   860  		default:
   861  			if b.Likely != ssa.BranchUnlikely {
   862  				p = s.Br(jmp.asm, b.Succs[0].Block())
   863  				s.Br(obj.AJMP, b.Succs[1].Block())
   864  			} else {
   865  				p = s.Br(jmp.invasm, b.Succs[1].Block())
   866  				s.Br(obj.AJMP, b.Succs[0].Block())
   867  			}
   868  		}
   869  		if !b.Controls[0].Type.IsFlags() {
   870  			p.From.Type = obj.TYPE_REG
   871  			p.From.Reg = b.Controls[0].Reg()
   872  		}
   873  	default:
   874  		b.Fatalf("branch not implemented: %s", b.LongString())
   875  	}
   876  }
   877  

View as plain text