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

View as plain text