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

View as plain text