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.OpMIPSNORconst,
   201  		ssa.OpMIPSSLLconst,
   202  		ssa.OpMIPSSRLconst,
   203  		ssa.OpMIPSSRAconst,
   204  		ssa.OpMIPSSGTconst,
   205  		ssa.OpMIPSSGTUconst:
   206  		p := s.Prog(v.Op.Asm())
   207  		p.From.Type = obj.TYPE_CONST
   208  		p.From.Offset = v.AuxInt
   209  		p.Reg = v.Args[0].Reg()
   210  		p.To.Type = obj.TYPE_REG
   211  		p.To.Reg = v.Reg()
   212  	case ssa.OpMIPSMULT,
   213  		ssa.OpMIPSMULTU,
   214  		ssa.OpMIPSDIV,
   215  		ssa.OpMIPSDIVU:
   216  		// result in hi,lo
   217  		p := s.Prog(v.Op.Asm())
   218  		p.From.Type = obj.TYPE_REG
   219  		p.From.Reg = v.Args[1].Reg()
   220  		p.Reg = v.Args[0].Reg()
   221  	case ssa.OpMIPSMOVWconst:
   222  		r := v.Reg()
   223  		p := s.Prog(v.Op.Asm())
   224  		p.From.Type = obj.TYPE_CONST
   225  		p.From.Offset = v.AuxInt
   226  		p.To.Type = obj.TYPE_REG
   227  		p.To.Reg = r
   228  		if isFPreg(r) || isHILO(r) {
   229  			// cannot move into FP or special registers, use TMP as intermediate
   230  			p.To.Reg = mips.REGTMP
   231  			p = s.Prog(mips.AMOVW)
   232  			p.From.Type = obj.TYPE_REG
   233  			p.From.Reg = mips.REGTMP
   234  			p.To.Type = obj.TYPE_REG
   235  			p.To.Reg = r
   236  		}
   237  	case ssa.OpMIPSMOVFconst,
   238  		ssa.OpMIPSMOVDconst:
   239  		p := s.Prog(v.Op.Asm())
   240  		p.From.Type = obj.TYPE_FCONST
   241  		p.From.Val = math.Float64frombits(uint64(v.AuxInt))
   242  		p.To.Type = obj.TYPE_REG
   243  		p.To.Reg = v.Reg()
   244  	case ssa.OpMIPSCMOVZ:
   245  		p := s.Prog(v.Op.Asm())
   246  		p.From.Type = obj.TYPE_REG
   247  		p.From.Reg = v.Args[2].Reg()
   248  		p.Reg = v.Args[1].Reg()
   249  		p.To.Type = obj.TYPE_REG
   250  		p.To.Reg = v.Reg()
   251  	case ssa.OpMIPSCMOVZzero:
   252  		p := s.Prog(v.Op.Asm())
   253  		p.From.Type = obj.TYPE_REG
   254  		p.From.Reg = v.Args[1].Reg()
   255  		p.Reg = mips.REGZERO
   256  		p.To.Type = obj.TYPE_REG
   257  		p.To.Reg = v.Reg()
   258  	case ssa.OpMIPSCMPEQF,
   259  		ssa.OpMIPSCMPEQD,
   260  		ssa.OpMIPSCMPGEF,
   261  		ssa.OpMIPSCMPGED,
   262  		ssa.OpMIPSCMPGTF,
   263  		ssa.OpMIPSCMPGTD:
   264  		p := s.Prog(v.Op.Asm())
   265  		p.From.Type = obj.TYPE_REG
   266  		p.From.Reg = v.Args[0].Reg()
   267  		p.Reg = v.Args[1].Reg()
   268  	case ssa.OpMIPSMOVWaddr:
   269  		p := s.Prog(mips.AMOVW)
   270  		p.From.Type = obj.TYPE_ADDR
   271  		p.From.Reg = v.Args[0].Reg()
   272  		var wantreg string
   273  		// MOVW $sym+off(base), R
   274  		// the assembler expands it as the following:
   275  		// - base is SP: add constant offset to SP (R29)
   276  		//               when constant is large, tmp register (R23) may be used
   277  		// - base is SB: load external address with relocation
   278  		switch v.Aux.(type) {
   279  		default:
   280  			v.Fatalf("aux is of unknown type %T", v.Aux)
   281  		case *obj.LSym:
   282  			wantreg = "SB"
   283  			ssagen.AddAux(&p.From, v)
   284  		case *ir.Name:
   285  			wantreg = "SP"
   286  			ssagen.AddAux(&p.From, v)
   287  		case nil:
   288  			// No sym, just MOVW $off(SP), R
   289  			wantreg = "SP"
   290  			p.From.Offset = v.AuxInt
   291  		}
   292  		if reg := v.Args[0].RegName(); reg != wantreg {
   293  			v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
   294  		}
   295  		p.To.Type = obj.TYPE_REG
   296  		p.To.Reg = v.Reg()
   297  	case ssa.OpMIPSMOVBload,
   298  		ssa.OpMIPSMOVBUload,
   299  		ssa.OpMIPSMOVHload,
   300  		ssa.OpMIPSMOVHUload,
   301  		ssa.OpMIPSMOVWload,
   302  		ssa.OpMIPSMOVFload,
   303  		ssa.OpMIPSMOVDload:
   304  		p := s.Prog(v.Op.Asm())
   305  		p.From.Type = obj.TYPE_MEM
   306  		p.From.Reg = v.Args[0].Reg()
   307  		ssagen.AddAux(&p.From, v)
   308  		p.To.Type = obj.TYPE_REG
   309  		p.To.Reg = v.Reg()
   310  	case ssa.OpMIPSMOVBstore,
   311  		ssa.OpMIPSMOVHstore,
   312  		ssa.OpMIPSMOVWstore,
   313  		ssa.OpMIPSMOVFstore,
   314  		ssa.OpMIPSMOVDstore:
   315  		p := s.Prog(v.Op.Asm())
   316  		p.From.Type = obj.TYPE_REG
   317  		p.From.Reg = v.Args[1].Reg()
   318  		p.To.Type = obj.TYPE_MEM
   319  		p.To.Reg = v.Args[0].Reg()
   320  		ssagen.AddAux(&p.To, v)
   321  	case ssa.OpMIPSMOVBstorezero,
   322  		ssa.OpMIPSMOVHstorezero,
   323  		ssa.OpMIPSMOVWstorezero:
   324  		p := s.Prog(v.Op.Asm())
   325  		p.From.Type = obj.TYPE_REG
   326  		p.From.Reg = mips.REGZERO
   327  		p.To.Type = obj.TYPE_MEM
   328  		p.To.Reg = v.Args[0].Reg()
   329  		ssagen.AddAux(&p.To, v)
   330  	case ssa.OpMIPSMOVBreg,
   331  		ssa.OpMIPSMOVBUreg,
   332  		ssa.OpMIPSMOVHreg,
   333  		ssa.OpMIPSMOVHUreg:
   334  		a := v.Args[0]
   335  		for a.Op == ssa.OpCopy || a.Op == ssa.OpMIPSMOVWreg || a.Op == ssa.OpMIPSMOVWnop {
   336  			a = a.Args[0]
   337  		}
   338  		if a.Op == ssa.OpLoadReg {
   339  			t := a.Type
   340  			switch {
   341  			case v.Op == ssa.OpMIPSMOVBreg && t.Size() == 1 && t.IsSigned(),
   342  				v.Op == ssa.OpMIPSMOVBUreg && t.Size() == 1 && !t.IsSigned(),
   343  				v.Op == ssa.OpMIPSMOVHreg && t.Size() == 2 && t.IsSigned(),
   344  				v.Op == ssa.OpMIPSMOVHUreg && t.Size() == 2 && !t.IsSigned():
   345  				// arg is a proper-typed load, already zero/sign-extended, don't extend again
   346  				if v.Reg() == v.Args[0].Reg() {
   347  					return
   348  				}
   349  				p := s.Prog(mips.AMOVW)
   350  				p.From.Type = obj.TYPE_REG
   351  				p.From.Reg = v.Args[0].Reg()
   352  				p.To.Type = obj.TYPE_REG
   353  				p.To.Reg = v.Reg()
   354  				return
   355  			default:
   356  			}
   357  		}
   358  		fallthrough
   359  	case ssa.OpMIPSMOVWF,
   360  		ssa.OpMIPSMOVWD,
   361  		ssa.OpMIPSTRUNCFW,
   362  		ssa.OpMIPSTRUNCDW,
   363  		ssa.OpMIPSMOVFD,
   364  		ssa.OpMIPSMOVDF,
   365  		ssa.OpMIPSMOVWfpgp,
   366  		ssa.OpMIPSMOVWgpfp,
   367  		ssa.OpMIPSNEGF,
   368  		ssa.OpMIPSNEGD,
   369  		ssa.OpMIPSABSD,
   370  		ssa.OpMIPSSQRTF,
   371  		ssa.OpMIPSSQRTD,
   372  		ssa.OpMIPSCLZ:
   373  		p := s.Prog(v.Op.Asm())
   374  		p.From.Type = obj.TYPE_REG
   375  		p.From.Reg = v.Args[0].Reg()
   376  		p.To.Type = obj.TYPE_REG
   377  		p.To.Reg = v.Reg()
   378  	case ssa.OpMIPSNEG:
   379  		// SUB from REGZERO
   380  		p := s.Prog(mips.ASUBU)
   381  		p.From.Type = obj.TYPE_REG
   382  		p.From.Reg = v.Args[0].Reg()
   383  		p.Reg = mips.REGZERO
   384  		p.To.Type = obj.TYPE_REG
   385  		p.To.Reg = v.Reg()
   386  	case ssa.OpMIPSLoweredZero:
   387  		// SUBU	$4, R1
   388  		// MOVW	R0, 4(R1)
   389  		// ADDU	$4, R1
   390  		// BNE	Rarg1, R1, -2(PC)
   391  		// arg1 is the address of the last element to zero
   392  		var sz int64
   393  		var mov obj.As
   394  		switch {
   395  		case v.AuxInt%4 == 0:
   396  			sz = 4
   397  			mov = mips.AMOVW
   398  		case v.AuxInt%2 == 0:
   399  			sz = 2
   400  			mov = mips.AMOVH
   401  		default:
   402  			sz = 1
   403  			mov = mips.AMOVB
   404  		}
   405  		p := s.Prog(mips.ASUBU)
   406  		p.From.Type = obj.TYPE_CONST
   407  		p.From.Offset = sz
   408  		p.To.Type = obj.TYPE_REG
   409  		p.To.Reg = mips.REG_R1
   410  		p2 := s.Prog(mov)
   411  		p2.From.Type = obj.TYPE_REG
   412  		p2.From.Reg = mips.REGZERO
   413  		p2.To.Type = obj.TYPE_MEM
   414  		p2.To.Reg = mips.REG_R1
   415  		p2.To.Offset = sz
   416  		p3 := s.Prog(mips.AADDU)
   417  		p3.From.Type = obj.TYPE_CONST
   418  		p3.From.Offset = sz
   419  		p3.To.Type = obj.TYPE_REG
   420  		p3.To.Reg = mips.REG_R1
   421  		p4 := s.Prog(mips.ABNE)
   422  		p4.From.Type = obj.TYPE_REG
   423  		p4.From.Reg = v.Args[1].Reg()
   424  		p4.Reg = mips.REG_R1
   425  		p4.To.Type = obj.TYPE_BRANCH
   426  		p4.To.SetTarget(p2)
   427  	case ssa.OpMIPSLoweredMove:
   428  		// SUBU	$4, R1
   429  		// MOVW	4(R1), Rtmp
   430  		// MOVW	Rtmp, (R2)
   431  		// ADDU	$4, R1
   432  		// ADDU	$4, R2
   433  		// BNE	Rarg2, R1, -4(PC)
   434  		// arg2 is the address of the last element of src
   435  		var sz int64
   436  		var mov obj.As
   437  		switch {
   438  		case v.AuxInt%4 == 0:
   439  			sz = 4
   440  			mov = mips.AMOVW
   441  		case v.AuxInt%2 == 0:
   442  			sz = 2
   443  			mov = mips.AMOVH
   444  		default:
   445  			sz = 1
   446  			mov = mips.AMOVB
   447  		}
   448  		p := s.Prog(mips.ASUBU)
   449  		p.From.Type = obj.TYPE_CONST
   450  		p.From.Offset = sz
   451  		p.To.Type = obj.TYPE_REG
   452  		p.To.Reg = mips.REG_R1
   453  		p2 := s.Prog(mov)
   454  		p2.From.Type = obj.TYPE_MEM
   455  		p2.From.Reg = mips.REG_R1
   456  		p2.From.Offset = sz
   457  		p2.To.Type = obj.TYPE_REG
   458  		p2.To.Reg = mips.REGTMP
   459  		p3 := s.Prog(mov)
   460  		p3.From.Type = obj.TYPE_REG
   461  		p3.From.Reg = mips.REGTMP
   462  		p3.To.Type = obj.TYPE_MEM
   463  		p3.To.Reg = mips.REG_R2
   464  		p4 := s.Prog(mips.AADDU)
   465  		p4.From.Type = obj.TYPE_CONST
   466  		p4.From.Offset = sz
   467  		p4.To.Type = obj.TYPE_REG
   468  		p4.To.Reg = mips.REG_R1
   469  		p5 := s.Prog(mips.AADDU)
   470  		p5.From.Type = obj.TYPE_CONST
   471  		p5.From.Offset = sz
   472  		p5.To.Type = obj.TYPE_REG
   473  		p5.To.Reg = mips.REG_R2
   474  		p6 := s.Prog(mips.ABNE)
   475  		p6.From.Type = obj.TYPE_REG
   476  		p6.From.Reg = v.Args[2].Reg()
   477  		p6.Reg = mips.REG_R1
   478  		p6.To.Type = obj.TYPE_BRANCH
   479  		p6.To.SetTarget(p2)
   480  	case ssa.OpMIPSCALLstatic, ssa.OpMIPSCALLclosure, ssa.OpMIPSCALLinter:
   481  		s.Call(v)
   482  	case ssa.OpMIPSCALLtail:
   483  		s.TailCall(v)
   484  	case ssa.OpMIPSLoweredWB:
   485  		p := s.Prog(obj.ACALL)
   486  		p.To.Type = obj.TYPE_MEM
   487  		p.To.Name = obj.NAME_EXTERN
   488  		// AuxInt encodes how many buffer entries we need.
   489  		p.To.Sym = ir.Syms.GCWriteBarrier[v.AuxInt-1]
   490  
   491  	case ssa.OpMIPSLoweredPanicBoundsRR, ssa.OpMIPSLoweredPanicBoundsRC, ssa.OpMIPSLoweredPanicBoundsCR, ssa.OpMIPSLoweredPanicBoundsCC,
   492  		ssa.OpMIPSLoweredPanicExtendRR, ssa.OpMIPSLoweredPanicExtendRC:
   493  		// Compute the constant we put in the PCData entry for this call.
   494  		code, signed := ssa.BoundsKind(v.AuxInt).Code()
   495  		xIsReg := false
   496  		yIsReg := false
   497  		xVal := 0
   498  		yVal := 0
   499  		extend := false
   500  		switch v.Op {
   501  		case ssa.OpMIPSLoweredPanicBoundsRR:
   502  			xIsReg = true
   503  			xVal = int(v.Args[0].Reg() - mips.REG_R1)
   504  			yIsReg = true
   505  			yVal = int(v.Args[1].Reg() - mips.REG_R1)
   506  		case ssa.OpMIPSLoweredPanicExtendRR:
   507  			extend = true
   508  			xIsReg = true
   509  			hi := int(v.Args[0].Reg() - mips.REG_R1)
   510  			lo := int(v.Args[1].Reg() - mips.REG_R1)
   511  			xVal = hi<<2 + lo // encode 2 register numbers
   512  			yIsReg = true
   513  			yVal = int(v.Args[2].Reg() - mips.REG_R1)
   514  		case ssa.OpMIPSLoweredPanicBoundsRC:
   515  			xIsReg = true
   516  			xVal = int(v.Args[0].Reg() - mips.REG_R1)
   517  			c := v.Aux.(ssa.PanicBoundsC).C
   518  			if c >= 0 && c <= abi.BoundsMaxConst {
   519  				yVal = int(c)
   520  			} else {
   521  				// Move constant to a register
   522  				yIsReg = true
   523  				if yVal == xVal {
   524  					yVal = 1
   525  				}
   526  				p := s.Prog(mips.AMOVW)
   527  				p.From.Type = obj.TYPE_CONST
   528  				p.From.Offset = c
   529  				p.To.Type = obj.TYPE_REG
   530  				p.To.Reg = mips.REG_R1 + int16(yVal)
   531  			}
   532  		case ssa.OpMIPSLoweredPanicExtendRC:
   533  			extend = true
   534  			xIsReg = true
   535  			hi := int(v.Args[0].Reg() - mips.REG_R1)
   536  			lo := int(v.Args[1].Reg() - mips.REG_R1)
   537  			xVal = hi<<2 + lo // encode 2 register numbers
   538  			c := v.Aux.(ssa.PanicBoundsC).C
   539  			if c >= 0 && c <= abi.BoundsMaxConst {
   540  				yVal = int(c)
   541  			} else {
   542  				// Move constant to a register
   543  				for yVal == hi || yVal == lo {
   544  					yVal++
   545  				}
   546  				p := s.Prog(mips.AMOVW)
   547  				p.From.Type = obj.TYPE_CONST
   548  				p.From.Offset = c
   549  				p.To.Type = obj.TYPE_REG
   550  				p.To.Reg = mips.REG_R1 + int16(yVal)
   551  			}
   552  		case ssa.OpMIPSLoweredPanicBoundsCR:
   553  			yIsReg = true
   554  			yVal := int(v.Args[0].Reg() - mips.REG_R1)
   555  			c := v.Aux.(ssa.PanicBoundsC).C
   556  			if c >= 0 && c <= abi.BoundsMaxConst {
   557  				xVal = int(c)
   558  			} else if signed && int64(int32(c)) == c || !signed && int64(uint32(c)) == c {
   559  				// Move constant to a register
   560  				xIsReg = true
   561  				if xVal == yVal {
   562  					xVal = 1
   563  				}
   564  				p := s.Prog(mips.AMOVW)
   565  				p.From.Type = obj.TYPE_CONST
   566  				p.From.Offset = c
   567  				p.To.Type = obj.TYPE_REG
   568  				p.To.Reg = mips.REG_R1 + int16(xVal)
   569  			} else {
   570  				// Move constant to two registers
   571  				extend = true
   572  				xIsReg = true
   573  				hi := 0
   574  				lo := 1
   575  				if hi == yVal {
   576  					hi = 2
   577  				}
   578  				if lo == yVal {
   579  					lo = 2
   580  				}
   581  				xVal = hi<<2 + lo
   582  				p := s.Prog(mips.AMOVW)
   583  				p.From.Type = obj.TYPE_CONST
   584  				p.From.Offset = c >> 32
   585  				p.To.Type = obj.TYPE_REG
   586  				p.To.Reg = mips.REG_R1 + int16(hi)
   587  				p = s.Prog(mips.AMOVW)
   588  				p.From.Type = obj.TYPE_CONST
   589  				p.From.Offset = int64(int32(c))
   590  				p.To.Type = obj.TYPE_REG
   591  				p.To.Reg = mips.REG_R1 + int16(lo)
   592  			}
   593  		case ssa.OpMIPSLoweredPanicBoundsCC:
   594  			c := v.Aux.(ssa.PanicBoundsCC).Cx
   595  			if c >= 0 && c <= abi.BoundsMaxConst {
   596  				xVal = int(c)
   597  			} else if signed && int64(int32(c)) == c || !signed && int64(uint32(c)) == c {
   598  				// Move constant to a register
   599  				xIsReg = true
   600  				p := s.Prog(mips.AMOVW)
   601  				p.From.Type = obj.TYPE_CONST
   602  				p.From.Offset = c
   603  				p.To.Type = obj.TYPE_REG
   604  				p.To.Reg = mips.REG_R1 + int16(xVal)
   605  			} else {
   606  				// Move constant to two registers
   607  				extend = true
   608  				xIsReg = true
   609  				hi := 0
   610  				lo := 1
   611  				xVal = hi<<2 + lo
   612  				p := s.Prog(mips.AMOVW)
   613  				p.From.Type = obj.TYPE_CONST
   614  				p.From.Offset = c >> 32
   615  				p.To.Type = obj.TYPE_REG
   616  				p.To.Reg = mips.REG_R1 + int16(hi)
   617  				p = s.Prog(mips.AMOVW)
   618  				p.From.Type = obj.TYPE_CONST
   619  				p.From.Offset = int64(int32(c))
   620  				p.To.Type = obj.TYPE_REG
   621  				p.To.Reg = mips.REG_R1 + int16(lo)
   622  			}
   623  			c = v.Aux.(ssa.PanicBoundsCC).Cy
   624  			if c >= 0 && c <= abi.BoundsMaxConst {
   625  				yVal = int(c)
   626  			} else {
   627  				// Move constant to a register
   628  				yIsReg = true
   629  				yVal = 2
   630  				p := s.Prog(mips.AMOVW)
   631  				p.From.Type = obj.TYPE_CONST
   632  				p.From.Offset = c
   633  				p.To.Type = obj.TYPE_REG
   634  				p.To.Reg = mips.REG_R1 + int16(yVal)
   635  			}
   636  		}
   637  		c := abi.BoundsEncode(code, signed, xIsReg, yIsReg, xVal, yVal)
   638  
   639  		p := s.Prog(obj.APCDATA)
   640  		p.From.SetConst(abi.PCDATA_PanicBounds)
   641  		p.To.SetConst(int64(c))
   642  		p = s.Prog(obj.ACALL)
   643  		p.To.Type = obj.TYPE_MEM
   644  		p.To.Name = obj.NAME_EXTERN
   645  		if extend {
   646  			p.To.Sym = ir.Syms.PanicExtend
   647  		} else {
   648  			p.To.Sym = ir.Syms.PanicBounds
   649  		}
   650  
   651  	case ssa.OpMIPSLoweredAtomicLoad8,
   652  		ssa.OpMIPSLoweredAtomicLoad32:
   653  		s.Prog(mips.ASYNC)
   654  
   655  		var op obj.As
   656  		switch v.Op {
   657  		case ssa.OpMIPSLoweredAtomicLoad8:
   658  			op = mips.AMOVB
   659  		case ssa.OpMIPSLoweredAtomicLoad32:
   660  			op = mips.AMOVW
   661  		}
   662  		p := s.Prog(op)
   663  		p.From.Type = obj.TYPE_MEM
   664  		p.From.Reg = v.Args[0].Reg()
   665  		p.To.Type = obj.TYPE_REG
   666  		p.To.Reg = v.Reg0()
   667  
   668  		s.Prog(mips.ASYNC)
   669  	case ssa.OpMIPSLoweredAtomicStore8,
   670  		ssa.OpMIPSLoweredAtomicStore32:
   671  		s.Prog(mips.ASYNC)
   672  
   673  		var op obj.As
   674  		switch v.Op {
   675  		case ssa.OpMIPSLoweredAtomicStore8:
   676  			op = mips.AMOVB
   677  		case ssa.OpMIPSLoweredAtomicStore32:
   678  			op = mips.AMOVW
   679  		}
   680  		p := s.Prog(op)
   681  		p.From.Type = obj.TYPE_REG
   682  		p.From.Reg = v.Args[1].Reg()
   683  		p.To.Type = obj.TYPE_MEM
   684  		p.To.Reg = v.Args[0].Reg()
   685  
   686  		s.Prog(mips.ASYNC)
   687  	case ssa.OpMIPSLoweredAtomicStorezero:
   688  		s.Prog(mips.ASYNC)
   689  
   690  		p := s.Prog(mips.AMOVW)
   691  		p.From.Type = obj.TYPE_REG
   692  		p.From.Reg = mips.REGZERO
   693  		p.To.Type = obj.TYPE_MEM
   694  		p.To.Reg = v.Args[0].Reg()
   695  
   696  		s.Prog(mips.ASYNC)
   697  	case ssa.OpMIPSLoweredAtomicExchange:
   698  		// SYNC
   699  		// MOVW Rarg1, Rtmp
   700  		// LL	(Rarg0), Rout
   701  		// SC	Rtmp, (Rarg0)
   702  		// BEQ	Rtmp, -3(PC)
   703  		// SYNC
   704  		s.Prog(mips.ASYNC)
   705  
   706  		p := s.Prog(mips.AMOVW)
   707  		p.From.Type = obj.TYPE_REG
   708  		p.From.Reg = v.Args[1].Reg()
   709  		p.To.Type = obj.TYPE_REG
   710  		p.To.Reg = mips.REGTMP
   711  
   712  		p1 := s.Prog(mips.ALL)
   713  		p1.From.Type = obj.TYPE_MEM
   714  		p1.From.Reg = v.Args[0].Reg()
   715  		p1.To.Type = obj.TYPE_REG
   716  		p1.To.Reg = v.Reg0()
   717  
   718  		p2 := s.Prog(mips.ASC)
   719  		p2.From.Type = obj.TYPE_REG
   720  		p2.From.Reg = mips.REGTMP
   721  		p2.To.Type = obj.TYPE_MEM
   722  		p2.To.Reg = v.Args[0].Reg()
   723  
   724  		p3 := s.Prog(mips.ABEQ)
   725  		p3.From.Type = obj.TYPE_REG
   726  		p3.From.Reg = mips.REGTMP
   727  		p3.To.Type = obj.TYPE_BRANCH
   728  		p3.To.SetTarget(p)
   729  
   730  		s.Prog(mips.ASYNC)
   731  	case ssa.OpMIPSLoweredAtomicAdd:
   732  		// SYNC
   733  		// LL	(Rarg0), Rout
   734  		// ADDU Rarg1, Rout, Rtmp
   735  		// SC	Rtmp, (Rarg0)
   736  		// BEQ	Rtmp, -3(PC)
   737  		// SYNC
   738  		// ADDU Rarg1, Rout
   739  		s.Prog(mips.ASYNC)
   740  
   741  		p := s.Prog(mips.ALL)
   742  		p.From.Type = obj.TYPE_MEM
   743  		p.From.Reg = v.Args[0].Reg()
   744  		p.To.Type = obj.TYPE_REG
   745  		p.To.Reg = v.Reg0()
   746  
   747  		p1 := s.Prog(mips.AADDU)
   748  		p1.From.Type = obj.TYPE_REG
   749  		p1.From.Reg = v.Args[1].Reg()
   750  		p1.Reg = v.Reg0()
   751  		p1.To.Type = obj.TYPE_REG
   752  		p1.To.Reg = mips.REGTMP
   753  
   754  		p2 := s.Prog(mips.ASC)
   755  		p2.From.Type = obj.TYPE_REG
   756  		p2.From.Reg = mips.REGTMP
   757  		p2.To.Type = obj.TYPE_MEM
   758  		p2.To.Reg = v.Args[0].Reg()
   759  
   760  		p3 := s.Prog(mips.ABEQ)
   761  		p3.From.Type = obj.TYPE_REG
   762  		p3.From.Reg = mips.REGTMP
   763  		p3.To.Type = obj.TYPE_BRANCH
   764  		p3.To.SetTarget(p)
   765  
   766  		s.Prog(mips.ASYNC)
   767  
   768  		p4 := s.Prog(mips.AADDU)
   769  		p4.From.Type = obj.TYPE_REG
   770  		p4.From.Reg = v.Args[1].Reg()
   771  		p4.Reg = v.Reg0()
   772  		p4.To.Type = obj.TYPE_REG
   773  		p4.To.Reg = v.Reg0()
   774  
   775  	case ssa.OpMIPSLoweredAtomicAddconst:
   776  		// SYNC
   777  		// LL	(Rarg0), Rout
   778  		// ADDU $auxInt, Rout, Rtmp
   779  		// SC	Rtmp, (Rarg0)
   780  		// BEQ	Rtmp, -3(PC)
   781  		// SYNC
   782  		// ADDU $auxInt, Rout
   783  		s.Prog(mips.ASYNC)
   784  
   785  		p := s.Prog(mips.ALL)
   786  		p.From.Type = obj.TYPE_MEM
   787  		p.From.Reg = v.Args[0].Reg()
   788  		p.To.Type = obj.TYPE_REG
   789  		p.To.Reg = v.Reg0()
   790  
   791  		p1 := s.Prog(mips.AADDU)
   792  		p1.From.Type = obj.TYPE_CONST
   793  		p1.From.Offset = v.AuxInt
   794  		p1.Reg = v.Reg0()
   795  		p1.To.Type = obj.TYPE_REG
   796  		p1.To.Reg = mips.REGTMP
   797  
   798  		p2 := s.Prog(mips.ASC)
   799  		p2.From.Type = obj.TYPE_REG
   800  		p2.From.Reg = mips.REGTMP
   801  		p2.To.Type = obj.TYPE_MEM
   802  		p2.To.Reg = v.Args[0].Reg()
   803  
   804  		p3 := s.Prog(mips.ABEQ)
   805  		p3.From.Type = obj.TYPE_REG
   806  		p3.From.Reg = mips.REGTMP
   807  		p3.To.Type = obj.TYPE_BRANCH
   808  		p3.To.SetTarget(p)
   809  
   810  		s.Prog(mips.ASYNC)
   811  
   812  		p4 := s.Prog(mips.AADDU)
   813  		p4.From.Type = obj.TYPE_CONST
   814  		p4.From.Offset = v.AuxInt
   815  		p4.Reg = v.Reg0()
   816  		p4.To.Type = obj.TYPE_REG
   817  		p4.To.Reg = v.Reg0()
   818  
   819  	case ssa.OpMIPSLoweredAtomicAnd,
   820  		ssa.OpMIPSLoweredAtomicOr:
   821  		// SYNC
   822  		// LL	(Rarg0), Rtmp
   823  		// AND/OR	Rarg1, Rtmp
   824  		// SC	Rtmp, (Rarg0)
   825  		// BEQ	Rtmp, -3(PC)
   826  		// SYNC
   827  		s.Prog(mips.ASYNC)
   828  
   829  		p := s.Prog(mips.ALL)
   830  		p.From.Type = obj.TYPE_MEM
   831  		p.From.Reg = v.Args[0].Reg()
   832  		p.To.Type = obj.TYPE_REG
   833  		p.To.Reg = mips.REGTMP
   834  
   835  		p1 := s.Prog(v.Op.Asm())
   836  		p1.From.Type = obj.TYPE_REG
   837  		p1.From.Reg = v.Args[1].Reg()
   838  		p1.Reg = mips.REGTMP
   839  		p1.To.Type = obj.TYPE_REG
   840  		p1.To.Reg = mips.REGTMP
   841  
   842  		p2 := s.Prog(mips.ASC)
   843  		p2.From.Type = obj.TYPE_REG
   844  		p2.From.Reg = mips.REGTMP
   845  		p2.To.Type = obj.TYPE_MEM
   846  		p2.To.Reg = v.Args[0].Reg()
   847  
   848  		p3 := s.Prog(mips.ABEQ)
   849  		p3.From.Type = obj.TYPE_REG
   850  		p3.From.Reg = mips.REGTMP
   851  		p3.To.Type = obj.TYPE_BRANCH
   852  		p3.To.SetTarget(p)
   853  
   854  		s.Prog(mips.ASYNC)
   855  
   856  	case ssa.OpMIPSLoweredAtomicCas:
   857  		// MOVW $0, Rout
   858  		// SYNC
   859  		// LL	(Rarg0), Rtmp
   860  		// BNE	Rtmp, Rarg1, 4(PC)
   861  		// MOVW Rarg2, Rout
   862  		// SC	Rout, (Rarg0)
   863  		// BEQ	Rout, -4(PC)
   864  		// SYNC
   865  		p := s.Prog(mips.AMOVW)
   866  		p.From.Type = obj.TYPE_REG
   867  		p.From.Reg = mips.REGZERO
   868  		p.To.Type = obj.TYPE_REG
   869  		p.To.Reg = v.Reg0()
   870  
   871  		s.Prog(mips.ASYNC)
   872  
   873  		p1 := s.Prog(mips.ALL)
   874  		p1.From.Type = obj.TYPE_MEM
   875  		p1.From.Reg = v.Args[0].Reg()
   876  		p1.To.Type = obj.TYPE_REG
   877  		p1.To.Reg = mips.REGTMP
   878  
   879  		p2 := s.Prog(mips.ABNE)
   880  		p2.From.Type = obj.TYPE_REG
   881  		p2.From.Reg = v.Args[1].Reg()
   882  		p2.Reg = mips.REGTMP
   883  		p2.To.Type = obj.TYPE_BRANCH
   884  
   885  		p3 := s.Prog(mips.AMOVW)
   886  		p3.From.Type = obj.TYPE_REG
   887  		p3.From.Reg = v.Args[2].Reg()
   888  		p3.To.Type = obj.TYPE_REG
   889  		p3.To.Reg = v.Reg0()
   890  
   891  		p4 := s.Prog(mips.ASC)
   892  		p4.From.Type = obj.TYPE_REG
   893  		p4.From.Reg = v.Reg0()
   894  		p4.To.Type = obj.TYPE_MEM
   895  		p4.To.Reg = v.Args[0].Reg()
   896  
   897  		p5 := s.Prog(mips.ABEQ)
   898  		p5.From.Type = obj.TYPE_REG
   899  		p5.From.Reg = v.Reg0()
   900  		p5.To.Type = obj.TYPE_BRANCH
   901  		p5.To.SetTarget(p1)
   902  
   903  		s.Prog(mips.ASYNC)
   904  
   905  		p6 := s.Prog(obj.ANOP)
   906  		p2.To.SetTarget(p6)
   907  
   908  	case ssa.OpMIPSLoweredNilCheck:
   909  		// Issue a load which will fault if arg is nil.
   910  		p := s.Prog(mips.AMOVB)
   911  		p.From.Type = obj.TYPE_MEM
   912  		p.From.Reg = v.Args[0].Reg()
   913  		ssagen.AddAux(&p.From, v)
   914  		p.To.Type = obj.TYPE_REG
   915  		p.To.Reg = mips.REGTMP
   916  		if logopt.Enabled() {
   917  			logopt.LogOpt(v.Pos, "nilcheck", "genssa", v.Block.Func.Name)
   918  		}
   919  		if base.Debug.Nil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
   920  			base.WarnfAt(v.Pos, "generated nil check")
   921  		}
   922  	case ssa.OpMIPSFPFlagTrue,
   923  		ssa.OpMIPSFPFlagFalse:
   924  		// MOVW		$1, r
   925  		// CMOVF	R0, r
   926  
   927  		cmov := mips.ACMOVF
   928  		if v.Op == ssa.OpMIPSFPFlagFalse {
   929  			cmov = mips.ACMOVT
   930  		}
   931  		p := s.Prog(mips.AMOVW)
   932  		p.From.Type = obj.TYPE_CONST
   933  		p.From.Offset = 1
   934  		p.To.Type = obj.TYPE_REG
   935  		p.To.Reg = v.Reg()
   936  		p1 := s.Prog(cmov)
   937  		p1.From.Type = obj.TYPE_REG
   938  		p1.From.Reg = mips.REGZERO
   939  		p1.To.Type = obj.TYPE_REG
   940  		p1.To.Reg = v.Reg()
   941  
   942  	case ssa.OpMIPSLoweredGetClosurePtr:
   943  		// Closure pointer is R22 (mips.REGCTXT).
   944  		ssagen.CheckLoweredGetClosurePtr(v)
   945  	case ssa.OpMIPSLoweredGetCallerSP:
   946  		// caller's SP is FixedFrameSize below the address of the first arg
   947  		p := s.Prog(mips.AMOVW)
   948  		p.From.Type = obj.TYPE_ADDR
   949  		p.From.Offset = -base.Ctxt.Arch.FixedFrameSize
   950  		p.From.Name = obj.NAME_PARAM
   951  		p.To.Type = obj.TYPE_REG
   952  		p.To.Reg = v.Reg()
   953  	case ssa.OpMIPSLoweredGetCallerPC:
   954  		p := s.Prog(obj.AGETCALLERPC)
   955  		p.To.Type = obj.TYPE_REG
   956  		p.To.Reg = v.Reg()
   957  	case ssa.OpMIPSLoweredPubBarrier:
   958  		// SYNC
   959  		s.Prog(v.Op.Asm())
   960  	case ssa.OpClobber, ssa.OpClobberReg:
   961  		// TODO: implement for clobberdead experiment. Nop is ok for now.
   962  	default:
   963  		v.Fatalf("genValue not implemented: %s", v.LongString())
   964  	}
   965  }
   966  
   967  var blockJump = map[ssa.BlockKind]struct {
   968  	asm, invasm obj.As
   969  }{
   970  	ssa.BlockMIPSEQ:  {mips.ABEQ, mips.ABNE},
   971  	ssa.BlockMIPSNE:  {mips.ABNE, mips.ABEQ},
   972  	ssa.BlockMIPSLTZ: {mips.ABLTZ, mips.ABGEZ},
   973  	ssa.BlockMIPSGEZ: {mips.ABGEZ, mips.ABLTZ},
   974  	ssa.BlockMIPSLEZ: {mips.ABLEZ, mips.ABGTZ},
   975  	ssa.BlockMIPSGTZ: {mips.ABGTZ, mips.ABLEZ},
   976  	ssa.BlockMIPSFPT: {mips.ABFPT, mips.ABFPF},
   977  	ssa.BlockMIPSFPF: {mips.ABFPF, mips.ABFPT},
   978  }
   979  
   980  func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
   981  	switch b.Kind {
   982  	case ssa.BlockPlain, ssa.BlockDefer:
   983  		if b.Succs[0].Block() != next {
   984  			p := s.Prog(obj.AJMP)
   985  			p.To.Type = obj.TYPE_BRANCH
   986  			s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
   987  		}
   988  	case ssa.BlockExit, ssa.BlockRetJmp:
   989  	case ssa.BlockRet:
   990  		s.Prog(obj.ARET)
   991  	case ssa.BlockMIPSEQ, ssa.BlockMIPSNE,
   992  		ssa.BlockMIPSLTZ, ssa.BlockMIPSGEZ,
   993  		ssa.BlockMIPSLEZ, ssa.BlockMIPSGTZ,
   994  		ssa.BlockMIPSFPT, ssa.BlockMIPSFPF:
   995  		jmp := blockJump[b.Kind]
   996  		var p *obj.Prog
   997  		switch next {
   998  		case b.Succs[0].Block():
   999  			p = s.Br(jmp.invasm, b.Succs[1].Block())
  1000  		case b.Succs[1].Block():
  1001  			p = s.Br(jmp.asm, b.Succs[0].Block())
  1002  		default:
  1003  			if b.Likely != ssa.BranchUnlikely {
  1004  				p = s.Br(jmp.asm, b.Succs[0].Block())
  1005  				s.Br(obj.AJMP, b.Succs[1].Block())
  1006  			} else {
  1007  				p = s.Br(jmp.invasm, b.Succs[1].Block())
  1008  				s.Br(obj.AJMP, b.Succs[0].Block())
  1009  			}
  1010  		}
  1011  		if !b.Controls[0].Type.IsFlags() {
  1012  			p.From.Type = obj.TYPE_REG
  1013  			p.From.Reg = b.Controls[0].Reg()
  1014  		}
  1015  	default:
  1016  		b.Fatalf("branch not implemented: %s", b.LongString())
  1017  	}
  1018  }
  1019  

View as plain text