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  	"internal/abi"
    19  )
    20  
    21  // isFPreg reports whether r is an FP register.
    22  func isFPreg(r int16) bool {
    23  	return mips.REG_F0 <= r && r <= mips.REG_F31
    24  }
    25  
    26  // isHILO reports whether r is HI or LO register.
    27  func isHILO(r int16) bool {
    28  	return r == mips.REG_HI || r == mips.REG_LO
    29  }
    30  
    31  // loadByType returns the load instruction of the given type.
    32  func loadByType(t *types.Type, r int16) obj.As {
    33  	if isFPreg(r) {
    34  		if t.Size() == 4 { // float32 or int32
    35  			return mips.AMOVF
    36  		} else { // float64 or int64
    37  			return mips.AMOVD
    38  		}
    39  	} else {
    40  		switch t.Size() {
    41  		case 1:
    42  			if t.IsSigned() {
    43  				return mips.AMOVB
    44  			} else {
    45  				return mips.AMOVBU
    46  			}
    47  		case 2:
    48  			if t.IsSigned() {
    49  				return mips.AMOVH
    50  			} else {
    51  				return mips.AMOVHU
    52  			}
    53  		case 4:
    54  			return mips.AMOVW
    55  		}
    56  	}
    57  	panic("bad load type")
    58  }
    59  
    60  // storeByType returns the store instruction of the given type.
    61  func storeByType(t *types.Type, r int16) obj.As {
    62  	if isFPreg(r) {
    63  		if t.Size() == 4 { // float32 or int32
    64  			return mips.AMOVF
    65  		} else { // float64 or int64
    66  			return mips.AMOVD
    67  		}
    68  	} else {
    69  		switch t.Size() {
    70  		case 1:
    71  			return mips.AMOVB
    72  		case 2:
    73  			return mips.AMOVH
    74  		case 4:
    75  			return mips.AMOVW
    76  		}
    77  	}
    78  	panic("bad store type")
    79  }
    80  
    81  func ssaGenValue(s *ssagen.State, v *ssa.Value) {
    82  	switch v.Op {
    83  	case ssa.OpCopy, ssa.OpMIPSMOVWreg:
    84  		t := v.Type
    85  		if t.IsMemory() {
    86  			return
    87  		}
    88  		x := v.Args[0].Reg()
    89  		y := v.Reg()
    90  		if x == y {
    91  			return
    92  		}
    93  		as := mips.AMOVW
    94  		if isFPreg(x) && isFPreg(y) {
    95  			as = mips.AMOVF
    96  			if t.Size() == 8 {
    97  				as = mips.AMOVD
    98  			}
    99  		}
   100  
   101  		p := s.Prog(as)
   102  		p.From.Type = obj.TYPE_REG
   103  		p.From.Reg = x
   104  		p.To.Type = obj.TYPE_REG
   105  		p.To.Reg = y
   106  		if isHILO(x) && isHILO(y) || isHILO(x) && isFPreg(y) || isFPreg(x) && isHILO(y) {
   107  			// cannot move between special registers, use TMP as intermediate
   108  			p.To.Reg = mips.REGTMP
   109  			p = s.Prog(mips.AMOVW)
   110  			p.From.Type = obj.TYPE_REG
   111  			p.From.Reg = mips.REGTMP
   112  			p.To.Type = obj.TYPE_REG
   113  			p.To.Reg = y
   114  		}
   115  	case ssa.OpMIPSMOVWnop:
   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  		ssagen.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  		ssagen.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.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.OpMIPSMOVWfpgp,
   365  		ssa.OpMIPSMOVWgpfp,
   366  		ssa.OpMIPSNEGF,
   367  		ssa.OpMIPSNEGD,
   368  		ssa.OpMIPSABSD,
   369  		ssa.OpMIPSSQRTF,
   370  		ssa.OpMIPSSQRTD,
   371  		ssa.OpMIPSCLZ:
   372  		p := s.Prog(v.Op.Asm())
   373  		p.From.Type = obj.TYPE_REG
   374  		p.From.Reg = v.Args[0].Reg()
   375  		p.To.Type = obj.TYPE_REG
   376  		p.To.Reg = v.Reg()
   377  	case ssa.OpMIPSNEG:
   378  		// SUB from REGZERO
   379  		p := s.Prog(mips.ASUBU)
   380  		p.From.Type = obj.TYPE_REG
   381  		p.From.Reg = v.Args[0].Reg()
   382  		p.Reg = mips.REGZERO
   383  		p.To.Type = obj.TYPE_REG
   384  		p.To.Reg = v.Reg()
   385  	case ssa.OpMIPSLoweredZero:
   386  		// SUBU	$4, R1
   387  		// MOVW	R0, 4(R1)
   388  		// ADDU	$4, R1
   389  		// BNE	Rarg1, R1, -2(PC)
   390  		// arg1 is the address of the last element to zero
   391  		var sz int64
   392  		var mov obj.As
   393  		switch {
   394  		case v.AuxInt%4 == 0:
   395  			sz = 4
   396  			mov = mips.AMOVW
   397  		case v.AuxInt%2 == 0:
   398  			sz = 2
   399  			mov = mips.AMOVH
   400  		default:
   401  			sz = 1
   402  			mov = mips.AMOVB
   403  		}
   404  		p := s.Prog(mips.ASUBU)
   405  		p.From.Type = obj.TYPE_CONST
   406  		p.From.Offset = sz
   407  		p.To.Type = obj.TYPE_REG
   408  		p.To.Reg = mips.REG_R1
   409  		p2 := s.Prog(mov)
   410  		p2.From.Type = obj.TYPE_REG
   411  		p2.From.Reg = mips.REGZERO
   412  		p2.To.Type = obj.TYPE_MEM
   413  		p2.To.Reg = mips.REG_R1
   414  		p2.To.Offset = sz
   415  		p3 := s.Prog(mips.AADDU)
   416  		p3.From.Type = obj.TYPE_CONST
   417  		p3.From.Offset = sz
   418  		p3.To.Type = obj.TYPE_REG
   419  		p3.To.Reg = mips.REG_R1
   420  		p4 := s.Prog(mips.ABNE)
   421  		p4.From.Type = obj.TYPE_REG
   422  		p4.From.Reg = v.Args[1].Reg()
   423  		p4.Reg = mips.REG_R1
   424  		p4.To.Type = obj.TYPE_BRANCH
   425  		p4.To.SetTarget(p2)
   426  	case ssa.OpMIPSLoweredMove:
   427  		// SUBU	$4, R1
   428  		// MOVW	4(R1), Rtmp
   429  		// MOVW	Rtmp, (R2)
   430  		// ADDU	$4, R1
   431  		// ADDU	$4, R2
   432  		// BNE	Rarg2, R1, -4(PC)
   433  		// arg2 is the address of the last element of src
   434  		var sz int64
   435  		var mov obj.As
   436  		switch {
   437  		case v.AuxInt%4 == 0:
   438  			sz = 4
   439  			mov = mips.AMOVW
   440  		case v.AuxInt%2 == 0:
   441  			sz = 2
   442  			mov = mips.AMOVH
   443  		default:
   444  			sz = 1
   445  			mov = mips.AMOVB
   446  		}
   447  		p := s.Prog(mips.ASUBU)
   448  		p.From.Type = obj.TYPE_CONST
   449  		p.From.Offset = sz
   450  		p.To.Type = obj.TYPE_REG
   451  		p.To.Reg = mips.REG_R1
   452  		p2 := s.Prog(mov)
   453  		p2.From.Type = obj.TYPE_MEM
   454  		p2.From.Reg = mips.REG_R1
   455  		p2.From.Offset = sz
   456  		p2.To.Type = obj.TYPE_REG
   457  		p2.To.Reg = mips.REGTMP
   458  		p3 := s.Prog(mov)
   459  		p3.From.Type = obj.TYPE_REG
   460  		p3.From.Reg = mips.REGTMP
   461  		p3.To.Type = obj.TYPE_MEM
   462  		p3.To.Reg = mips.REG_R2
   463  		p4 := s.Prog(mips.AADDU)
   464  		p4.From.Type = obj.TYPE_CONST
   465  		p4.From.Offset = sz
   466  		p4.To.Type = obj.TYPE_REG
   467  		p4.To.Reg = mips.REG_R1
   468  		p5 := s.Prog(mips.AADDU)
   469  		p5.From.Type = obj.TYPE_CONST
   470  		p5.From.Offset = sz
   471  		p5.To.Type = obj.TYPE_REG
   472  		p5.To.Reg = mips.REG_R2
   473  		p6 := s.Prog(mips.ABNE)
   474  		p6.From.Type = obj.TYPE_REG
   475  		p6.From.Reg = v.Args[2].Reg()
   476  		p6.Reg = mips.REG_R1
   477  		p6.To.Type = obj.TYPE_BRANCH
   478  		p6.To.SetTarget(p2)
   479  	case ssa.OpMIPSCALLstatic, ssa.OpMIPSCALLclosure, ssa.OpMIPSCALLinter:
   480  		s.Call(v)
   481  	case ssa.OpMIPSCALLtail, ssa.OpMIPSCALLtailinter:
   482  		s.TailCall(v)
   483  	case ssa.OpMIPSLoweredWB:
   484  		p := s.Prog(obj.ACALL)
   485  		p.To.Type = obj.TYPE_MEM
   486  		p.To.Name = obj.NAME_EXTERN
   487  		// AuxInt encodes how many buffer entries we need.
   488  		p.To.Sym = ir.Syms.GCWriteBarrier[v.AuxInt-1]
   489  
   490  	case ssa.OpMIPSLoweredPanicBoundsRR, ssa.OpMIPSLoweredPanicBoundsRC, ssa.OpMIPSLoweredPanicBoundsCR, ssa.OpMIPSLoweredPanicBoundsCC,
   491  		ssa.OpMIPSLoweredPanicExtendRR, ssa.OpMIPSLoweredPanicExtendRC:
   492  		// Compute the constant we put in the PCData entry for this call.
   493  		code, signed := ssa.BoundsKind(v.AuxInt).Code()
   494  		xIsReg := false
   495  		yIsReg := false
   496  		xVal := 0
   497  		yVal := 0
   498  		extend := false
   499  		switch v.Op {
   500  		case ssa.OpMIPSLoweredPanicBoundsRR:
   501  			xIsReg = true
   502  			xVal = int(v.Args[0].Reg() - mips.REG_R1)
   503  			yIsReg = true
   504  			yVal = int(v.Args[1].Reg() - mips.REG_R1)
   505  		case ssa.OpMIPSLoweredPanicExtendRR:
   506  			extend = true
   507  			xIsReg = true
   508  			hi := int(v.Args[0].Reg() - mips.REG_R1)
   509  			lo := int(v.Args[1].Reg() - mips.REG_R1)
   510  			xVal = hi<<2 + lo // encode 2 register numbers
   511  			yIsReg = true
   512  			yVal = int(v.Args[2].Reg() - mips.REG_R1)
   513  		case ssa.OpMIPSLoweredPanicBoundsRC:
   514  			xIsReg = true
   515  			xVal = int(v.Args[0].Reg() - mips.REG_R1)
   516  			c := v.Aux.(ssa.PanicBoundsC).C
   517  			if c >= 0 && c <= abi.BoundsMaxConst {
   518  				yVal = int(c)
   519  			} else {
   520  				// Move constant to a register
   521  				yIsReg = true
   522  				if yVal == xVal {
   523  					yVal = 1
   524  				}
   525  				p := s.Prog(mips.AMOVW)
   526  				p.From.Type = obj.TYPE_CONST
   527  				p.From.Offset = c
   528  				p.To.Type = obj.TYPE_REG
   529  				p.To.Reg = mips.REG_R1 + int16(yVal)
   530  			}
   531  		case ssa.OpMIPSLoweredPanicExtendRC:
   532  			extend = true
   533  			xIsReg = true
   534  			hi := int(v.Args[0].Reg() - mips.REG_R1)
   535  			lo := int(v.Args[1].Reg() - mips.REG_R1)
   536  			xVal = hi<<2 + lo // encode 2 register numbers
   537  			c := v.Aux.(ssa.PanicBoundsC).C
   538  			if c >= 0 && c <= abi.BoundsMaxConst {
   539  				yVal = int(c)
   540  			} else {
   541  				// Move constant to a register
   542  				for yVal == hi || yVal == lo {
   543  					yVal++
   544  				}
   545  				p := s.Prog(mips.AMOVW)
   546  				p.From.Type = obj.TYPE_CONST
   547  				p.From.Offset = c
   548  				p.To.Type = obj.TYPE_REG
   549  				p.To.Reg = mips.REG_R1 + int16(yVal)
   550  			}
   551  		case ssa.OpMIPSLoweredPanicBoundsCR:
   552  			yIsReg = true
   553  			yVal = int(v.Args[0].Reg() - mips.REG_R1)
   554  			c := v.Aux.(ssa.PanicBoundsC).C
   555  			if c >= 0 && c <= abi.BoundsMaxConst {
   556  				xVal = int(c)
   557  			} else if signed && int64(int32(c)) == c || !signed && int64(uint32(c)) == c {
   558  				// Move constant to a register
   559  				xIsReg = true
   560  				if xVal == yVal {
   561  					xVal = 1
   562  				}
   563  				p := s.Prog(mips.AMOVW)
   564  				p.From.Type = obj.TYPE_CONST
   565  				p.From.Offset = c
   566  				p.To.Type = obj.TYPE_REG
   567  				p.To.Reg = mips.REG_R1 + int16(xVal)
   568  			} else {
   569  				// Move constant to two registers
   570  				extend = true
   571  				xIsReg = true
   572  				hi := 0
   573  				lo := 1
   574  				if hi == yVal {
   575  					hi = 2
   576  				}
   577  				if lo == yVal {
   578  					lo = 2
   579  				}
   580  				xVal = hi<<2 + lo
   581  				p := s.Prog(mips.AMOVW)
   582  				p.From.Type = obj.TYPE_CONST
   583  				p.From.Offset = c >> 32
   584  				p.To.Type = obj.TYPE_REG
   585  				p.To.Reg = mips.REG_R1 + int16(hi)
   586  				p = s.Prog(mips.AMOVW)
   587  				p.From.Type = obj.TYPE_CONST
   588  				p.From.Offset = int64(int32(c))
   589  				p.To.Type = obj.TYPE_REG
   590  				p.To.Reg = mips.REG_R1 + int16(lo)
   591  			}
   592  		case ssa.OpMIPSLoweredPanicBoundsCC:
   593  			c := v.Aux.(ssa.PanicBoundsCC).Cx
   594  			if c >= 0 && c <= abi.BoundsMaxConst {
   595  				xVal = int(c)
   596  			} else if signed && int64(int32(c)) == c || !signed && int64(uint32(c)) == c {
   597  				// Move constant to a register
   598  				xIsReg = true
   599  				p := s.Prog(mips.AMOVW)
   600  				p.From.Type = obj.TYPE_CONST
   601  				p.From.Offset = c
   602  				p.To.Type = obj.TYPE_REG
   603  				p.To.Reg = mips.REG_R1 + int16(xVal)
   604  			} else {
   605  				// Move constant to two registers
   606  				extend = true
   607  				xIsReg = true
   608  				hi := 0
   609  				lo := 1
   610  				xVal = hi<<2 + lo
   611  				p := s.Prog(mips.AMOVW)
   612  				p.From.Type = obj.TYPE_CONST
   613  				p.From.Offset = c >> 32
   614  				p.To.Type = obj.TYPE_REG
   615  				p.To.Reg = mips.REG_R1 + int16(hi)
   616  				p = s.Prog(mips.AMOVW)
   617  				p.From.Type = obj.TYPE_CONST
   618  				p.From.Offset = int64(int32(c))
   619  				p.To.Type = obj.TYPE_REG
   620  				p.To.Reg = mips.REG_R1 + int16(lo)
   621  			}
   622  			c = v.Aux.(ssa.PanicBoundsCC).Cy
   623  			if c >= 0 && c <= abi.BoundsMaxConst {
   624  				yVal = int(c)
   625  			} else {
   626  				// Move constant to a register
   627  				yIsReg = true
   628  				yVal = 2
   629  				p := s.Prog(mips.AMOVW)
   630  				p.From.Type = obj.TYPE_CONST
   631  				p.From.Offset = c
   632  				p.To.Type = obj.TYPE_REG
   633  				p.To.Reg = mips.REG_R1 + int16(yVal)
   634  			}
   635  		}
   636  		c := abi.BoundsEncode(code, signed, xIsReg, yIsReg, xVal, yVal)
   637  
   638  		p := s.Prog(obj.APCDATA)
   639  		p.From.SetConst(abi.PCDATA_PanicBounds)
   640  		p.To.SetConst(int64(c))
   641  		p = s.Prog(obj.ACALL)
   642  		p.To.Type = obj.TYPE_MEM
   643  		p.To.Name = obj.NAME_EXTERN
   644  		if extend {
   645  			p.To.Sym = ir.Syms.PanicExtend
   646  		} else {
   647  			p.To.Sym = ir.Syms.PanicBounds
   648  		}
   649  
   650  	case ssa.OpMIPSLoweredAtomicLoad8,
   651  		ssa.OpMIPSLoweredAtomicLoad32:
   652  		s.Prog(mips.ASYNC)
   653  
   654  		var op obj.As
   655  		switch v.Op {
   656  		case ssa.OpMIPSLoweredAtomicLoad8:
   657  			op = mips.AMOVB
   658  		case ssa.OpMIPSLoweredAtomicLoad32:
   659  			op = mips.AMOVW
   660  		}
   661  		p := s.Prog(op)
   662  		p.From.Type = obj.TYPE_MEM
   663  		p.From.Reg = v.Args[0].Reg()
   664  		p.To.Type = obj.TYPE_REG
   665  		p.To.Reg = v.Reg0()
   666  
   667  		s.Prog(mips.ASYNC)
   668  	case ssa.OpMIPSLoweredAtomicStore8,
   669  		ssa.OpMIPSLoweredAtomicStore32:
   670  		s.Prog(mips.ASYNC)
   671  
   672  		var op obj.As
   673  		switch v.Op {
   674  		case ssa.OpMIPSLoweredAtomicStore8:
   675  			op = mips.AMOVB
   676  		case ssa.OpMIPSLoweredAtomicStore32:
   677  			op = mips.AMOVW
   678  		}
   679  		p := s.Prog(op)
   680  		p.From.Type = obj.TYPE_REG
   681  		p.From.Reg = v.Args[1].Reg()
   682  		p.To.Type = obj.TYPE_MEM
   683  		p.To.Reg = v.Args[0].Reg()
   684  
   685  		s.Prog(mips.ASYNC)
   686  	case ssa.OpMIPSLoweredAtomicStorezero:
   687  		s.Prog(mips.ASYNC)
   688  
   689  		p := s.Prog(mips.AMOVW)
   690  		p.From.Type = obj.TYPE_REG
   691  		p.From.Reg = mips.REGZERO
   692  		p.To.Type = obj.TYPE_MEM
   693  		p.To.Reg = v.Args[0].Reg()
   694  
   695  		s.Prog(mips.ASYNC)
   696  	case ssa.OpMIPSLoweredAtomicExchange:
   697  		// SYNC
   698  		// MOVW Rarg1, Rtmp
   699  		// LL	(Rarg0), Rout
   700  		// SC	Rtmp, (Rarg0)
   701  		// BEQ	Rtmp, -3(PC)
   702  		// SYNC
   703  		s.Prog(mips.ASYNC)
   704  
   705  		p := s.Prog(mips.AMOVW)
   706  		p.From.Type = obj.TYPE_REG
   707  		p.From.Reg = v.Args[1].Reg()
   708  		p.To.Type = obj.TYPE_REG
   709  		p.To.Reg = mips.REGTMP
   710  
   711  		p1 := s.Prog(mips.ALL)
   712  		p1.From.Type = obj.TYPE_MEM
   713  		p1.From.Reg = v.Args[0].Reg()
   714  		p1.To.Type = obj.TYPE_REG
   715  		p1.To.Reg = v.Reg0()
   716  
   717  		p2 := s.Prog(mips.ASC)
   718  		p2.From.Type = obj.TYPE_REG
   719  		p2.From.Reg = mips.REGTMP
   720  		p2.To.Type = obj.TYPE_MEM
   721  		p2.To.Reg = v.Args[0].Reg()
   722  
   723  		p3 := s.Prog(mips.ABEQ)
   724  		p3.From.Type = obj.TYPE_REG
   725  		p3.From.Reg = mips.REGTMP
   726  		p3.To.Type = obj.TYPE_BRANCH
   727  		p3.To.SetTarget(p)
   728  
   729  		s.Prog(mips.ASYNC)
   730  	case ssa.OpMIPSLoweredAtomicAdd:
   731  		// SYNC
   732  		// LL	(Rarg0), Rout
   733  		// ADDU Rarg1, Rout, Rtmp
   734  		// SC	Rtmp, (Rarg0)
   735  		// BEQ	Rtmp, -3(PC)
   736  		// SYNC
   737  		// ADDU Rarg1, Rout
   738  		s.Prog(mips.ASYNC)
   739  
   740  		p := s.Prog(mips.ALL)
   741  		p.From.Type = obj.TYPE_MEM
   742  		p.From.Reg = v.Args[0].Reg()
   743  		p.To.Type = obj.TYPE_REG
   744  		p.To.Reg = v.Reg0()
   745  
   746  		p1 := s.Prog(mips.AADDU)
   747  		p1.From.Type = obj.TYPE_REG
   748  		p1.From.Reg = v.Args[1].Reg()
   749  		p1.Reg = v.Reg0()
   750  		p1.To.Type = obj.TYPE_REG
   751  		p1.To.Reg = mips.REGTMP
   752  
   753  		p2 := s.Prog(mips.ASC)
   754  		p2.From.Type = obj.TYPE_REG
   755  		p2.From.Reg = mips.REGTMP
   756  		p2.To.Type = obj.TYPE_MEM
   757  		p2.To.Reg = v.Args[0].Reg()
   758  
   759  		p3 := s.Prog(mips.ABEQ)
   760  		p3.From.Type = obj.TYPE_REG
   761  		p3.From.Reg = mips.REGTMP
   762  		p3.To.Type = obj.TYPE_BRANCH
   763  		p3.To.SetTarget(p)
   764  
   765  		s.Prog(mips.ASYNC)
   766  
   767  		p4 := s.Prog(mips.AADDU)
   768  		p4.From.Type = obj.TYPE_REG
   769  		p4.From.Reg = v.Args[1].Reg()
   770  		p4.Reg = v.Reg0()
   771  		p4.To.Type = obj.TYPE_REG
   772  		p4.To.Reg = v.Reg0()
   773  
   774  	case ssa.OpMIPSLoweredAtomicAddconst:
   775  		// SYNC
   776  		// LL	(Rarg0), Rout
   777  		// ADDU $auxInt, Rout, Rtmp
   778  		// SC	Rtmp, (Rarg0)
   779  		// BEQ	Rtmp, -3(PC)
   780  		// SYNC
   781  		// ADDU $auxInt, Rout
   782  		s.Prog(mips.ASYNC)
   783  
   784  		p := s.Prog(mips.ALL)
   785  		p.From.Type = obj.TYPE_MEM
   786  		p.From.Reg = v.Args[0].Reg()
   787  		p.To.Type = obj.TYPE_REG
   788  		p.To.Reg = v.Reg0()
   789  
   790  		p1 := s.Prog(mips.AADDU)
   791  		p1.From.Type = obj.TYPE_CONST
   792  		p1.From.Offset = v.AuxInt
   793  		p1.Reg = v.Reg0()
   794  		p1.To.Type = obj.TYPE_REG
   795  		p1.To.Reg = mips.REGTMP
   796  
   797  		p2 := s.Prog(mips.ASC)
   798  		p2.From.Type = obj.TYPE_REG
   799  		p2.From.Reg = mips.REGTMP
   800  		p2.To.Type = obj.TYPE_MEM
   801  		p2.To.Reg = v.Args[0].Reg()
   802  
   803  		p3 := s.Prog(mips.ABEQ)
   804  		p3.From.Type = obj.TYPE_REG
   805  		p3.From.Reg = mips.REGTMP
   806  		p3.To.Type = obj.TYPE_BRANCH
   807  		p3.To.SetTarget(p)
   808  
   809  		s.Prog(mips.ASYNC)
   810  
   811  		p4 := s.Prog(mips.AADDU)
   812  		p4.From.Type = obj.TYPE_CONST
   813  		p4.From.Offset = v.AuxInt
   814  		p4.Reg = v.Reg0()
   815  		p4.To.Type = obj.TYPE_REG
   816  		p4.To.Reg = v.Reg0()
   817  
   818  	case ssa.OpMIPSLoweredAtomicAnd,
   819  		ssa.OpMIPSLoweredAtomicOr:
   820  		// SYNC
   821  		// LL	(Rarg0), Rtmp
   822  		// AND/OR	Rarg1, Rtmp
   823  		// SC	Rtmp, (Rarg0)
   824  		// BEQ	Rtmp, -3(PC)
   825  		// SYNC
   826  		s.Prog(mips.ASYNC)
   827  
   828  		p := s.Prog(mips.ALL)
   829  		p.From.Type = obj.TYPE_MEM
   830  		p.From.Reg = v.Args[0].Reg()
   831  		p.To.Type = obj.TYPE_REG
   832  		p.To.Reg = mips.REGTMP
   833  
   834  		p1 := s.Prog(v.Op.Asm())
   835  		p1.From.Type = obj.TYPE_REG
   836  		p1.From.Reg = v.Args[1].Reg()
   837  		p1.Reg = mips.REGTMP
   838  		p1.To.Type = obj.TYPE_REG
   839  		p1.To.Reg = mips.REGTMP
   840  
   841  		p2 := s.Prog(mips.ASC)
   842  		p2.From.Type = obj.TYPE_REG
   843  		p2.From.Reg = mips.REGTMP
   844  		p2.To.Type = obj.TYPE_MEM
   845  		p2.To.Reg = v.Args[0].Reg()
   846  
   847  		p3 := s.Prog(mips.ABEQ)
   848  		p3.From.Type = obj.TYPE_REG
   849  		p3.From.Reg = mips.REGTMP
   850  		p3.To.Type = obj.TYPE_BRANCH
   851  		p3.To.SetTarget(p)
   852  
   853  		s.Prog(mips.ASYNC)
   854  
   855  	case ssa.OpMIPSLoweredAtomicCas:
   856  		// MOVW $0, Rout
   857  		// SYNC
   858  		// LL	(Rarg0), Rtmp
   859  		// BNE	Rtmp, Rarg1, 4(PC)
   860  		// MOVW Rarg2, Rout
   861  		// SC	Rout, (Rarg0)
   862  		// BEQ	Rout, -4(PC)
   863  		// SYNC
   864  		p := s.Prog(mips.AMOVW)
   865  		p.From.Type = obj.TYPE_REG
   866  		p.From.Reg = mips.REGZERO
   867  		p.To.Type = obj.TYPE_REG
   868  		p.To.Reg = v.Reg0()
   869  
   870  		s.Prog(mips.ASYNC)
   871  
   872  		p1 := s.Prog(mips.ALL)
   873  		p1.From.Type = obj.TYPE_MEM
   874  		p1.From.Reg = v.Args[0].Reg()
   875  		p1.To.Type = obj.TYPE_REG
   876  		p1.To.Reg = mips.REGTMP
   877  
   878  		p2 := s.Prog(mips.ABNE)
   879  		p2.From.Type = obj.TYPE_REG
   880  		p2.From.Reg = v.Args[1].Reg()
   881  		p2.Reg = mips.REGTMP
   882  		p2.To.Type = obj.TYPE_BRANCH
   883  
   884  		p3 := s.Prog(mips.AMOVW)
   885  		p3.From.Type = obj.TYPE_REG
   886  		p3.From.Reg = v.Args[2].Reg()
   887  		p3.To.Type = obj.TYPE_REG
   888  		p3.To.Reg = v.Reg0()
   889  
   890  		p4 := s.Prog(mips.ASC)
   891  		p4.From.Type = obj.TYPE_REG
   892  		p4.From.Reg = v.Reg0()
   893  		p4.To.Type = obj.TYPE_MEM
   894  		p4.To.Reg = v.Args[0].Reg()
   895  
   896  		p5 := s.Prog(mips.ABEQ)
   897  		p5.From.Type = obj.TYPE_REG
   898  		p5.From.Reg = v.Reg0()
   899  		p5.To.Type = obj.TYPE_BRANCH
   900  		p5.To.SetTarget(p1)
   901  
   902  		s.Prog(mips.ASYNC)
   903  
   904  		p6 := s.Prog(obj.ANOP)
   905  		p2.To.SetTarget(p6)
   906  
   907  	case ssa.OpMIPSLoweredNilCheck:
   908  		// Issue a load which will fault if arg is nil.
   909  		p := s.Prog(mips.AMOVB)
   910  		p.From.Type = obj.TYPE_MEM
   911  		p.From.Reg = v.Args[0].Reg()
   912  		ssagen.AddAux(&p.From, v)
   913  		p.To.Type = obj.TYPE_REG
   914  		p.To.Reg = mips.REGTMP
   915  		if logopt.Enabled() {
   916  			logopt.LogOpt(v.Pos, "nilcheck", "genssa", v.Block.Func.Name)
   917  		}
   918  		if base.Debug.Nil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
   919  			base.WarnfAt(v.Pos, "generated nil check")
   920  		}
   921  	case ssa.OpMIPSFPFlagTrue,
   922  		ssa.OpMIPSFPFlagFalse:
   923  		// MOVW		$1, r
   924  		// CMOVF	R0, r
   925  
   926  		cmov := mips.ACMOVF
   927  		if v.Op == ssa.OpMIPSFPFlagFalse {
   928  			cmov = mips.ACMOVT
   929  		}
   930  		p := s.Prog(mips.AMOVW)
   931  		p.From.Type = obj.TYPE_CONST
   932  		p.From.Offset = 1
   933  		p.To.Type = obj.TYPE_REG
   934  		p.To.Reg = v.Reg()
   935  		p1 := s.Prog(cmov)
   936  		p1.From.Type = obj.TYPE_REG
   937  		p1.From.Reg = mips.REGZERO
   938  		p1.To.Type = obj.TYPE_REG
   939  		p1.To.Reg = v.Reg()
   940  
   941  	case ssa.OpMIPSLoweredGetClosurePtr:
   942  		// Closure pointer is R22 (mips.REGCTXT).
   943  		ssagen.CheckLoweredGetClosurePtr(v)
   944  	case ssa.OpMIPSLoweredGetCallerSP:
   945  		// caller's SP is FixedFrameSize below the address of the first arg
   946  		p := s.Prog(mips.AMOVW)
   947  		p.From.Type = obj.TYPE_ADDR
   948  		p.From.Offset = -base.Ctxt.Arch.FixedFrameSize
   949  		p.From.Name = obj.NAME_PARAM
   950  		p.To.Type = obj.TYPE_REG
   951  		p.To.Reg = v.Reg()
   952  	case ssa.OpMIPSLoweredGetCallerPC:
   953  		p := s.Prog(obj.AGETCALLERPC)
   954  		p.To.Type = obj.TYPE_REG
   955  		p.To.Reg = v.Reg()
   956  	case ssa.OpMIPSLoweredPubBarrier:
   957  		// SYNC
   958  		s.Prog(v.Op.Asm())
   959  	case ssa.OpClobber, ssa.OpClobberReg:
   960  		// TODO: implement for clobberdead experiment. Nop is ok for now.
   961  	default:
   962  		v.Fatalf("genValue not implemented: %s", v.LongString())
   963  	}
   964  }
   965  
   966  var blockJump = map[ssa.BlockKind]struct {
   967  	asm, invasm obj.As
   968  }{
   969  	ssa.BlockMIPSEQ:  {mips.ABEQ, mips.ABNE},
   970  	ssa.BlockMIPSNE:  {mips.ABNE, mips.ABEQ},
   971  	ssa.BlockMIPSLTZ: {mips.ABLTZ, mips.ABGEZ},
   972  	ssa.BlockMIPSGEZ: {mips.ABGEZ, mips.ABLTZ},
   973  	ssa.BlockMIPSLEZ: {mips.ABLEZ, mips.ABGTZ},
   974  	ssa.BlockMIPSGTZ: {mips.ABGTZ, mips.ABLEZ},
   975  	ssa.BlockMIPSFPT: {mips.ABFPT, mips.ABFPF},
   976  	ssa.BlockMIPSFPF: {mips.ABFPF, mips.ABFPT},
   977  }
   978  
   979  func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
   980  	switch b.Kind {
   981  	case ssa.BlockPlain, ssa.BlockDefer:
   982  		if b.Succs[0].Block() != next {
   983  			p := s.Prog(obj.AJMP)
   984  			p.To.Type = obj.TYPE_BRANCH
   985  			s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
   986  		}
   987  	case ssa.BlockExit, ssa.BlockRetJmp:
   988  	case ssa.BlockRet:
   989  		s.Prog(obj.ARET)
   990  	case ssa.BlockMIPSEQ, ssa.BlockMIPSNE,
   991  		ssa.BlockMIPSLTZ, ssa.BlockMIPSGEZ,
   992  		ssa.BlockMIPSLEZ, ssa.BlockMIPSGTZ,
   993  		ssa.BlockMIPSFPT, ssa.BlockMIPSFPF:
   994  		jmp := blockJump[b.Kind]
   995  		var p *obj.Prog
   996  		switch next {
   997  		case b.Succs[0].Block():
   998  			p = s.Br(jmp.invasm, b.Succs[1].Block())
   999  		case b.Succs[1].Block():
  1000  			p = s.Br(jmp.asm, b.Succs[0].Block())
  1001  		default:
  1002  			if b.Likely != ssa.BranchUnlikely {
  1003  				p = s.Br(jmp.asm, b.Succs[0].Block())
  1004  				s.Br(obj.AJMP, b.Succs[1].Block())
  1005  			} else {
  1006  				p = s.Br(jmp.invasm, b.Succs[1].Block())
  1007  				s.Br(obj.AJMP, b.Succs[0].Block())
  1008  			}
  1009  		}
  1010  		if !b.Controls[0].Type.IsFlags() {
  1011  			p.From.Type = obj.TYPE_REG
  1012  			p.From.Reg = b.Controls[0].Reg()
  1013  		}
  1014  	default:
  1015  		b.Fatalf("branch not implemented: %s", b.LongString())
  1016  	}
  1017  }
  1018  

View as plain text