Source file src/cmd/compile/internal/mips64/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 mips64
     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  			if t.IsSigned() {
    55  				return mips.AMOVW
    56  			} else {
    57  				return mips.AMOVWU
    58  			}
    59  		case 8:
    60  			return mips.AMOVV
    61  		}
    62  	}
    63  	panic("bad load type")
    64  }
    65  
    66  // storeByType returns the store instruction of the given type.
    67  func storeByType(t *types.Type, r int16) obj.As {
    68  	if isFPreg(r) {
    69  		if t.Size() == 4 { // float32 or int32
    70  			return mips.AMOVF
    71  		} else { // float64 or int64
    72  			return mips.AMOVD
    73  		}
    74  	} else {
    75  		switch t.Size() {
    76  		case 1:
    77  			return mips.AMOVB
    78  		case 2:
    79  			return mips.AMOVH
    80  		case 4:
    81  			return mips.AMOVW
    82  		case 8:
    83  			return mips.AMOVV
    84  		}
    85  	}
    86  	panic("bad store type")
    87  }
    88  
    89  func ssaGenValue(s *ssagen.State, v *ssa.Value) {
    90  	switch v.Op {
    91  	case ssa.OpCopy, ssa.OpMIPS64MOVVreg:
    92  		if v.Type.IsMemory() {
    93  			return
    94  		}
    95  		x := v.Args[0].Reg()
    96  		y := v.Reg()
    97  		if x == y {
    98  			return
    99  		}
   100  		as := mips.AMOVV
   101  		if isFPreg(x) && isFPreg(y) {
   102  			as = mips.AMOVD
   103  		}
   104  		p := s.Prog(as)
   105  		p.From.Type = obj.TYPE_REG
   106  		p.From.Reg = x
   107  		p.To.Type = obj.TYPE_REG
   108  		p.To.Reg = y
   109  		if isHILO(x) && isHILO(y) || isHILO(x) && isFPreg(y) || isFPreg(x) && isHILO(y) {
   110  			// cannot move between special registers, use TMP as intermediate
   111  			p.To.Reg = mips.REGTMP
   112  			p = s.Prog(mips.AMOVV)
   113  			p.From.Type = obj.TYPE_REG
   114  			p.From.Reg = mips.REGTMP
   115  			p.To.Type = obj.TYPE_REG
   116  			p.To.Reg = y
   117  		}
   118  	case ssa.OpMIPS64MOVVnop, ssa.OpMIPS64ZERO:
   119  		// nothing to do
   120  	case ssa.OpLoadReg:
   121  		if v.Type.IsFlags() {
   122  			v.Fatalf("load flags not implemented: %v", v.LongString())
   123  			return
   124  		}
   125  		r := v.Reg()
   126  		p := s.Prog(loadByType(v.Type, r))
   127  		ssagen.AddrAuto(&p.From, v.Args[0])
   128  		p.To.Type = obj.TYPE_REG
   129  		p.To.Reg = r
   130  		if isHILO(r) {
   131  			// cannot directly load, load to TMP and move
   132  			p.To.Reg = mips.REGTMP
   133  			p = s.Prog(mips.AMOVV)
   134  			p.From.Type = obj.TYPE_REG
   135  			p.From.Reg = mips.REGTMP
   136  			p.To.Type = obj.TYPE_REG
   137  			p.To.Reg = r
   138  		}
   139  	case ssa.OpStoreReg:
   140  		if v.Type.IsFlags() {
   141  			v.Fatalf("store flags not implemented: %v", v.LongString())
   142  			return
   143  		}
   144  		r := v.Args[0].Reg()
   145  		if isHILO(r) {
   146  			// cannot directly store, move to TMP and store
   147  			p := s.Prog(mips.AMOVV)
   148  			p.From.Type = obj.TYPE_REG
   149  			p.From.Reg = r
   150  			p.To.Type = obj.TYPE_REG
   151  			p.To.Reg = mips.REGTMP
   152  			r = mips.REGTMP
   153  		}
   154  		p := s.Prog(storeByType(v.Type, r))
   155  		p.From.Type = obj.TYPE_REG
   156  		p.From.Reg = r
   157  		ssagen.AddrAuto(&p.To, v)
   158  	case ssa.OpMIPS64ADDV,
   159  		ssa.OpMIPS64SUBV,
   160  		ssa.OpMIPS64AND,
   161  		ssa.OpMIPS64OR,
   162  		ssa.OpMIPS64XOR,
   163  		ssa.OpMIPS64NOR,
   164  		ssa.OpMIPS64SLLV,
   165  		ssa.OpMIPS64SRLV,
   166  		ssa.OpMIPS64SRAV,
   167  		ssa.OpMIPS64ADDF,
   168  		ssa.OpMIPS64ADDD,
   169  		ssa.OpMIPS64SUBF,
   170  		ssa.OpMIPS64SUBD,
   171  		ssa.OpMIPS64MULF,
   172  		ssa.OpMIPS64MULD,
   173  		ssa.OpMIPS64DIVF,
   174  		ssa.OpMIPS64DIVD:
   175  		p := s.Prog(v.Op.Asm())
   176  		p.From.Type = obj.TYPE_REG
   177  		p.From.Reg = v.Args[1].Reg()
   178  		p.Reg = v.Args[0].Reg()
   179  		p.To.Type = obj.TYPE_REG
   180  		p.To.Reg = v.Reg()
   181  	case ssa.OpMIPS64SGT,
   182  		ssa.OpMIPS64SGTU:
   183  		p := s.Prog(v.Op.Asm())
   184  		p.From.Type = obj.TYPE_REG
   185  		p.From.Reg = v.Args[0].Reg()
   186  		p.Reg = v.Args[1].Reg()
   187  		p.To.Type = obj.TYPE_REG
   188  		p.To.Reg = v.Reg()
   189  	case ssa.OpMIPS64ADDVconst,
   190  		ssa.OpMIPS64SUBVconst,
   191  		ssa.OpMIPS64ANDconst,
   192  		ssa.OpMIPS64ORconst,
   193  		ssa.OpMIPS64XORconst,
   194  		ssa.OpMIPS64NORconst,
   195  		ssa.OpMIPS64SLLVconst,
   196  		ssa.OpMIPS64SRLVconst,
   197  		ssa.OpMIPS64SRAVconst,
   198  		ssa.OpMIPS64SGTconst,
   199  		ssa.OpMIPS64SGTUconst:
   200  		p := s.Prog(v.Op.Asm())
   201  		p.From.Type = obj.TYPE_CONST
   202  		p.From.Offset = v.AuxInt
   203  		p.Reg = v.Args[0].Reg()
   204  		p.To.Type = obj.TYPE_REG
   205  		p.To.Reg = v.Reg()
   206  	case ssa.OpMIPS64MULV,
   207  		ssa.OpMIPS64MULVU,
   208  		ssa.OpMIPS64DIVV,
   209  		ssa.OpMIPS64DIVVU:
   210  		// HI, LO results exist in low quality registers that can't
   211  		// be stored without using REGTMP.
   212  		// This used to cause corruptions since store might also need
   213  		// REGTMP to materialize the address.
   214  		// Instead we move the result into high quality registers.
   215  		p := s.Prog(v.Op.Asm())
   216  		p.From.Type = obj.TYPE_REG
   217  		p.From.Reg = v.Args[1].Reg()
   218  		p.Reg = v.Args[0].Reg()
   219  		p1 := s.Prog(mips.AMOVV)
   220  		p1.From.Type = obj.TYPE_REG
   221  		p1.From.Reg = mips.REG_HI
   222  		p1.To.Type = obj.TYPE_REG
   223  		p1.To.Reg = v.Reg0()
   224  		p2 := s.Prog(mips.AMOVV)
   225  		p2.From.Type = obj.TYPE_REG
   226  		p2.From.Reg = mips.REG_LO
   227  		p2.To.Type = obj.TYPE_REG
   228  		p2.To.Reg = v.Reg1()
   229  	case ssa.OpMIPS64MOVVconst:
   230  		r := v.Reg()
   231  		p := s.Prog(v.Op.Asm())
   232  		p.From.Type = obj.TYPE_CONST
   233  		p.From.Offset = v.AuxInt
   234  		p.To.Type = obj.TYPE_REG
   235  		p.To.Reg = r
   236  		if isFPreg(r) || isHILO(r) {
   237  			// cannot move into FP or special registers, use TMP as intermediate
   238  			p.To.Reg = mips.REGTMP
   239  			p = s.Prog(mips.AMOVV)
   240  			p.From.Type = obj.TYPE_REG
   241  			p.From.Reg = mips.REGTMP
   242  			p.To.Type = obj.TYPE_REG
   243  			p.To.Reg = r
   244  		}
   245  	case ssa.OpMIPS64MOVFconst,
   246  		ssa.OpMIPS64MOVDconst:
   247  		p := s.Prog(v.Op.Asm())
   248  		p.From.Type = obj.TYPE_FCONST
   249  		p.From.Val = math.Float64frombits(uint64(v.AuxInt))
   250  		p.To.Type = obj.TYPE_REG
   251  		p.To.Reg = v.Reg()
   252  	case ssa.OpMIPS64CMPEQF,
   253  		ssa.OpMIPS64CMPEQD,
   254  		ssa.OpMIPS64CMPGEF,
   255  		ssa.OpMIPS64CMPGED,
   256  		ssa.OpMIPS64CMPGTF,
   257  		ssa.OpMIPS64CMPGTD:
   258  		p := s.Prog(v.Op.Asm())
   259  		p.From.Type = obj.TYPE_REG
   260  		p.From.Reg = v.Args[0].Reg()
   261  		p.Reg = v.Args[1].Reg()
   262  	case ssa.OpMIPS64MOVVaddr:
   263  		p := s.Prog(mips.AMOVV)
   264  		p.From.Type = obj.TYPE_ADDR
   265  		p.From.Reg = v.Args[0].Reg()
   266  		var wantreg string
   267  		// MOVV $sym+off(base), R
   268  		// the assembler expands it as the following:
   269  		// - base is SP: add constant offset to SP (R29)
   270  		//               when constant is large, tmp register (R23) may be used
   271  		// - base is SB: load external address with relocation
   272  		switch v.Aux.(type) {
   273  		default:
   274  			v.Fatalf("aux is of unknown type %T", v.Aux)
   275  		case *obj.LSym:
   276  			wantreg = "SB"
   277  			ssagen.AddAux(&p.From, v)
   278  		case *ir.Name:
   279  			wantreg = "SP"
   280  			ssagen.AddAux(&p.From, v)
   281  		case nil:
   282  			// No sym, just MOVV $off(SP), R
   283  			wantreg = "SP"
   284  			p.From.Offset = v.AuxInt
   285  		}
   286  		if reg := v.Args[0].RegName(); reg != wantreg {
   287  			v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
   288  		}
   289  		p.To.Type = obj.TYPE_REG
   290  		p.To.Reg = v.Reg()
   291  	case ssa.OpMIPS64MOVBload,
   292  		ssa.OpMIPS64MOVBUload,
   293  		ssa.OpMIPS64MOVHload,
   294  		ssa.OpMIPS64MOVHUload,
   295  		ssa.OpMIPS64MOVWload,
   296  		ssa.OpMIPS64MOVWUload,
   297  		ssa.OpMIPS64MOVVload,
   298  		ssa.OpMIPS64MOVFload,
   299  		ssa.OpMIPS64MOVDload:
   300  		p := s.Prog(v.Op.Asm())
   301  		p.From.Type = obj.TYPE_MEM
   302  		p.From.Reg = v.Args[0].Reg()
   303  		ssagen.AddAux(&p.From, v)
   304  		p.To.Type = obj.TYPE_REG
   305  		p.To.Reg = v.Reg()
   306  	case ssa.OpMIPS64MOVBstore,
   307  		ssa.OpMIPS64MOVHstore,
   308  		ssa.OpMIPS64MOVWstore,
   309  		ssa.OpMIPS64MOVVstore,
   310  		ssa.OpMIPS64MOVFstore,
   311  		ssa.OpMIPS64MOVDstore:
   312  		p := s.Prog(v.Op.Asm())
   313  		p.From.Type = obj.TYPE_REG
   314  		p.From.Reg = v.Args[1].Reg()
   315  		p.To.Type = obj.TYPE_MEM
   316  		p.To.Reg = v.Args[0].Reg()
   317  		ssagen.AddAux(&p.To, v)
   318  	case ssa.OpMIPS64MOVBreg,
   319  		ssa.OpMIPS64MOVBUreg,
   320  		ssa.OpMIPS64MOVHreg,
   321  		ssa.OpMIPS64MOVHUreg,
   322  		ssa.OpMIPS64MOVWreg,
   323  		ssa.OpMIPS64MOVWUreg:
   324  		a := v.Args[0]
   325  		for a.Op == ssa.OpCopy || a.Op == ssa.OpMIPS64MOVVreg {
   326  			a = a.Args[0]
   327  		}
   328  		if a.Op == ssa.OpLoadReg && mips.REG_R0 <= a.Reg() && a.Reg() <= mips.REG_R31 {
   329  			// LoadReg from a narrower type does an extension, except loading
   330  			// to a floating point register. So only eliminate the extension
   331  			// if it is loaded to an integer register.
   332  			t := a.Type
   333  			switch {
   334  			case v.Op == ssa.OpMIPS64MOVBreg && t.Size() == 1 && t.IsSigned(),
   335  				v.Op == ssa.OpMIPS64MOVBUreg && t.Size() == 1 && !t.IsSigned(),
   336  				v.Op == ssa.OpMIPS64MOVHreg && t.Size() == 2 && t.IsSigned(),
   337  				v.Op == ssa.OpMIPS64MOVHUreg && t.Size() == 2 && !t.IsSigned(),
   338  				v.Op == ssa.OpMIPS64MOVWreg && t.Size() == 4 && t.IsSigned(),
   339  				v.Op == ssa.OpMIPS64MOVWUreg && t.Size() == 4 && !t.IsSigned():
   340  				// arg is a proper-typed load, already zero/sign-extended, don't extend again
   341  				if v.Reg() == v.Args[0].Reg() {
   342  					return
   343  				}
   344  				p := s.Prog(mips.AMOVV)
   345  				p.From.Type = obj.TYPE_REG
   346  				p.From.Reg = v.Args[0].Reg()
   347  				p.To.Type = obj.TYPE_REG
   348  				p.To.Reg = v.Reg()
   349  				return
   350  			default:
   351  			}
   352  		}
   353  		fallthrough
   354  	case ssa.OpMIPS64MOVWF,
   355  		ssa.OpMIPS64MOVWD,
   356  		ssa.OpMIPS64TRUNCFW,
   357  		ssa.OpMIPS64TRUNCDW,
   358  		ssa.OpMIPS64MOVVF,
   359  		ssa.OpMIPS64MOVVD,
   360  		ssa.OpMIPS64TRUNCFV,
   361  		ssa.OpMIPS64TRUNCDV,
   362  		ssa.OpMIPS64MOVFD,
   363  		ssa.OpMIPS64MOVDF,
   364  		ssa.OpMIPS64MOVWfpgp,
   365  		ssa.OpMIPS64MOVWgpfp,
   366  		ssa.OpMIPS64MOVVfpgp,
   367  		ssa.OpMIPS64MOVVgpfp,
   368  		ssa.OpMIPS64NEGF,
   369  		ssa.OpMIPS64NEGD,
   370  		ssa.OpMIPS64ABSD,
   371  		ssa.OpMIPS64SQRTF,
   372  		ssa.OpMIPS64SQRTD:
   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.OpMIPS64NEGV:
   379  		// SUB from REGZERO
   380  		p := s.Prog(mips.ASUBVU)
   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.OpMIPS64DUFFZERO:
   387  		// runtime.duffzero expects start address - 8 in R1
   388  		p := s.Prog(mips.ASUBVU)
   389  		p.From.Type = obj.TYPE_CONST
   390  		p.From.Offset = 8
   391  		p.Reg = v.Args[0].Reg()
   392  		p.To.Type = obj.TYPE_REG
   393  		p.To.Reg = mips.REG_R1
   394  		p = s.Prog(obj.ADUFFZERO)
   395  		p.To.Type = obj.TYPE_MEM
   396  		p.To.Name = obj.NAME_EXTERN
   397  		p.To.Sym = ir.Syms.Duffzero
   398  		p.To.Offset = v.AuxInt
   399  	case ssa.OpMIPS64LoweredZero:
   400  		// SUBV	$8, R1
   401  		// MOVV	R0, 8(R1)
   402  		// ADDV	$8, 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%8 == 0:
   409  			sz = 8
   410  			mov = mips.AMOVV
   411  		case v.AuxInt%4 == 0:
   412  			sz = 4
   413  			mov = mips.AMOVW
   414  		case v.AuxInt%2 == 0:
   415  			sz = 2
   416  			mov = mips.AMOVH
   417  		default:
   418  			sz = 1
   419  			mov = mips.AMOVB
   420  		}
   421  		p := s.Prog(mips.ASUBVU)
   422  		p.From.Type = obj.TYPE_CONST
   423  		p.From.Offset = sz
   424  		p.To.Type = obj.TYPE_REG
   425  		p.To.Reg = mips.REG_R1
   426  		p2 := s.Prog(mov)
   427  		p2.From.Type = obj.TYPE_REG
   428  		p2.From.Reg = mips.REGZERO
   429  		p2.To.Type = obj.TYPE_MEM
   430  		p2.To.Reg = mips.REG_R1
   431  		p2.To.Offset = sz
   432  		p3 := s.Prog(mips.AADDVU)
   433  		p3.From.Type = obj.TYPE_CONST
   434  		p3.From.Offset = sz
   435  		p3.To.Type = obj.TYPE_REG
   436  		p3.To.Reg = mips.REG_R1
   437  		p4 := s.Prog(mips.ABNE)
   438  		p4.From.Type = obj.TYPE_REG
   439  		p4.From.Reg = v.Args[1].Reg()
   440  		p4.Reg = mips.REG_R1
   441  		p4.To.Type = obj.TYPE_BRANCH
   442  		p4.To.SetTarget(p2)
   443  	case ssa.OpMIPS64DUFFCOPY:
   444  		p := s.Prog(obj.ADUFFCOPY)
   445  		p.To.Type = obj.TYPE_MEM
   446  		p.To.Name = obj.NAME_EXTERN
   447  		p.To.Sym = ir.Syms.Duffcopy
   448  		p.To.Offset = v.AuxInt
   449  	case ssa.OpMIPS64LoweredMove:
   450  		// SUBV	$8, R1
   451  		// MOVV	8(R1), Rtmp
   452  		// MOVV	Rtmp, (R2)
   453  		// ADDV	$8, R1
   454  		// ADDV	$8, R2
   455  		// BNE	Rarg2, R1, -4(PC)
   456  		// arg2 is the address of the last element of src
   457  		var sz int64
   458  		var mov obj.As
   459  		switch {
   460  		case v.AuxInt%8 == 0:
   461  			sz = 8
   462  			mov = mips.AMOVV
   463  		case v.AuxInt%4 == 0:
   464  			sz = 4
   465  			mov = mips.AMOVW
   466  		case v.AuxInt%2 == 0:
   467  			sz = 2
   468  			mov = mips.AMOVH
   469  		default:
   470  			sz = 1
   471  			mov = mips.AMOVB
   472  		}
   473  		p := s.Prog(mips.ASUBVU)
   474  		p.From.Type = obj.TYPE_CONST
   475  		p.From.Offset = sz
   476  		p.To.Type = obj.TYPE_REG
   477  		p.To.Reg = mips.REG_R1
   478  		p2 := s.Prog(mov)
   479  		p2.From.Type = obj.TYPE_MEM
   480  		p2.From.Reg = mips.REG_R1
   481  		p2.From.Offset = sz
   482  		p2.To.Type = obj.TYPE_REG
   483  		p2.To.Reg = mips.REGTMP
   484  		p3 := s.Prog(mov)
   485  		p3.From.Type = obj.TYPE_REG
   486  		p3.From.Reg = mips.REGTMP
   487  		p3.To.Type = obj.TYPE_MEM
   488  		p3.To.Reg = mips.REG_R2
   489  		p4 := s.Prog(mips.AADDVU)
   490  		p4.From.Type = obj.TYPE_CONST
   491  		p4.From.Offset = sz
   492  		p4.To.Type = obj.TYPE_REG
   493  		p4.To.Reg = mips.REG_R1
   494  		p5 := s.Prog(mips.AADDVU)
   495  		p5.From.Type = obj.TYPE_CONST
   496  		p5.From.Offset = sz
   497  		p5.To.Type = obj.TYPE_REG
   498  		p5.To.Reg = mips.REG_R2
   499  		p6 := s.Prog(mips.ABNE)
   500  		p6.From.Type = obj.TYPE_REG
   501  		p6.From.Reg = v.Args[2].Reg()
   502  		p6.Reg = mips.REG_R1
   503  		p6.To.Type = obj.TYPE_BRANCH
   504  		p6.To.SetTarget(p2)
   505  	case ssa.OpMIPS64CALLstatic, ssa.OpMIPS64CALLclosure, ssa.OpMIPS64CALLinter:
   506  		s.Call(v)
   507  	case ssa.OpMIPS64CALLtail:
   508  		s.TailCall(v)
   509  	case ssa.OpMIPS64LoweredWB:
   510  		p := s.Prog(obj.ACALL)
   511  		p.To.Type = obj.TYPE_MEM
   512  		p.To.Name = obj.NAME_EXTERN
   513  		// AuxInt encodes how many buffer entries we need.
   514  		p.To.Sym = ir.Syms.GCWriteBarrier[v.AuxInt-1]
   515  
   516  	case ssa.OpMIPS64LoweredPanicBoundsRR, ssa.OpMIPS64LoweredPanicBoundsRC, ssa.OpMIPS64LoweredPanicBoundsCR, ssa.OpMIPS64LoweredPanicBoundsCC:
   517  		// Compute the constant we put in the PCData entry for this call.
   518  		code, signed := ssa.BoundsKind(v.AuxInt).Code()
   519  		xIsReg := false
   520  		yIsReg := false
   521  		xVal := 0
   522  		yVal := 0
   523  		switch v.Op {
   524  		case ssa.OpMIPS64LoweredPanicBoundsRR:
   525  			xIsReg = true
   526  			xVal = int(v.Args[0].Reg() - mips.REG_R1)
   527  			yIsReg = true
   528  			yVal = int(v.Args[1].Reg() - mips.REG_R1)
   529  		case ssa.OpMIPS64LoweredPanicBoundsRC:
   530  			xIsReg = true
   531  			xVal = int(v.Args[0].Reg() - mips.REG_R1)
   532  			c := v.Aux.(ssa.PanicBoundsC).C
   533  			if c >= 0 && c <= abi.BoundsMaxConst {
   534  				yVal = int(c)
   535  			} else {
   536  				// Move constant to a register
   537  				yIsReg = true
   538  				if yVal == xVal {
   539  					yVal = 1
   540  				}
   541  				p := s.Prog(mips.AMOVV)
   542  				p.From.Type = obj.TYPE_CONST
   543  				p.From.Offset = c
   544  				p.To.Type = obj.TYPE_REG
   545  				p.To.Reg = mips.REG_R1 + int16(yVal)
   546  			}
   547  		case ssa.OpMIPS64LoweredPanicBoundsCR:
   548  			yIsReg = true
   549  			yVal = int(v.Args[0].Reg() - mips.REG_R1)
   550  			c := v.Aux.(ssa.PanicBoundsC).C
   551  			if c >= 0 && c <= abi.BoundsMaxConst {
   552  				xVal = int(c)
   553  			} else {
   554  				// Move constant to a register
   555  				xIsReg = true
   556  				if xVal == yVal {
   557  					xVal = 1
   558  				}
   559  				p := s.Prog(mips.AMOVV)
   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(xVal)
   564  			}
   565  		case ssa.OpMIPS64LoweredPanicBoundsCC:
   566  			c := v.Aux.(ssa.PanicBoundsCC).Cx
   567  			if c >= 0 && c <= abi.BoundsMaxConst {
   568  				xVal = int(c)
   569  			} else {
   570  				// Move constant to a register
   571  				xIsReg = true
   572  				p := s.Prog(mips.AMOVV)
   573  				p.From.Type = obj.TYPE_CONST
   574  				p.From.Offset = c
   575  				p.To.Type = obj.TYPE_REG
   576  				p.To.Reg = mips.REG_R1 + int16(xVal)
   577  			}
   578  			c = v.Aux.(ssa.PanicBoundsCC).Cy
   579  			if c >= 0 && c <= abi.BoundsMaxConst {
   580  				yVal = int(c)
   581  			} else {
   582  				// Move constant to a register
   583  				yIsReg = true
   584  				yVal = 1
   585  				p := s.Prog(mips.AMOVV)
   586  				p.From.Type = obj.TYPE_CONST
   587  				p.From.Offset = c
   588  				p.To.Type = obj.TYPE_REG
   589  				p.To.Reg = mips.REG_R1 + int16(yVal)
   590  			}
   591  		}
   592  		c := abi.BoundsEncode(code, signed, xIsReg, yIsReg, xVal, yVal)
   593  
   594  		p := s.Prog(obj.APCDATA)
   595  		p.From.SetConst(abi.PCDATA_PanicBounds)
   596  		p.To.SetConst(int64(c))
   597  		p = s.Prog(obj.ACALL)
   598  		p.To.Type = obj.TYPE_MEM
   599  		p.To.Name = obj.NAME_EXTERN
   600  		p.To.Sym = ir.Syms.PanicBounds
   601  
   602  	case ssa.OpMIPS64LoweredAtomicLoad8, ssa.OpMIPS64LoweredAtomicLoad32, ssa.OpMIPS64LoweredAtomicLoad64:
   603  		as := mips.AMOVV
   604  		switch v.Op {
   605  		case ssa.OpMIPS64LoweredAtomicLoad8:
   606  			as = mips.AMOVB
   607  		case ssa.OpMIPS64LoweredAtomicLoad32:
   608  			as = mips.AMOVW
   609  		}
   610  		s.Prog(mips.ASYNC)
   611  		p := s.Prog(as)
   612  		p.From.Type = obj.TYPE_MEM
   613  		p.From.Reg = v.Args[0].Reg()
   614  		p.To.Type = obj.TYPE_REG
   615  		p.To.Reg = v.Reg0()
   616  		s.Prog(mips.ASYNC)
   617  	case ssa.OpMIPS64LoweredAtomicStore8, ssa.OpMIPS64LoweredAtomicStore32, ssa.OpMIPS64LoweredAtomicStore64:
   618  		as := mips.AMOVV
   619  		switch v.Op {
   620  		case ssa.OpMIPS64LoweredAtomicStore8:
   621  			as = mips.AMOVB
   622  		case ssa.OpMIPS64LoweredAtomicStore32:
   623  			as = mips.AMOVW
   624  		}
   625  		s.Prog(mips.ASYNC)
   626  		p := s.Prog(as)
   627  		p.From.Type = obj.TYPE_REG
   628  		p.From.Reg = v.Args[1].Reg()
   629  		p.To.Type = obj.TYPE_MEM
   630  		p.To.Reg = v.Args[0].Reg()
   631  		s.Prog(mips.ASYNC)
   632  	case ssa.OpMIPS64LoweredAtomicStorezero32, ssa.OpMIPS64LoweredAtomicStorezero64:
   633  		as := mips.AMOVV
   634  		if v.Op == ssa.OpMIPS64LoweredAtomicStorezero32 {
   635  			as = mips.AMOVW
   636  		}
   637  		s.Prog(mips.ASYNC)
   638  		p := s.Prog(as)
   639  		p.From.Type = obj.TYPE_REG
   640  		p.From.Reg = mips.REGZERO
   641  		p.To.Type = obj.TYPE_MEM
   642  		p.To.Reg = v.Args[0].Reg()
   643  		s.Prog(mips.ASYNC)
   644  	case ssa.OpMIPS64LoweredAtomicExchange32, ssa.OpMIPS64LoweredAtomicExchange64:
   645  		// SYNC
   646  		// MOVV	Rarg1, Rtmp
   647  		// LL	(Rarg0), Rout
   648  		// SC	Rtmp, (Rarg0)
   649  		// BEQ	Rtmp, -3(PC)
   650  		// SYNC
   651  		ll := mips.ALLV
   652  		sc := mips.ASCV
   653  		if v.Op == ssa.OpMIPS64LoweredAtomicExchange32 {
   654  			ll = mips.ALL
   655  			sc = mips.ASC
   656  		}
   657  		s.Prog(mips.ASYNC)
   658  		p := s.Prog(mips.AMOVV)
   659  		p.From.Type = obj.TYPE_REG
   660  		p.From.Reg = v.Args[1].Reg()
   661  		p.To.Type = obj.TYPE_REG
   662  		p.To.Reg = mips.REGTMP
   663  		p1 := s.Prog(ll)
   664  		p1.From.Type = obj.TYPE_MEM
   665  		p1.From.Reg = v.Args[0].Reg()
   666  		p1.To.Type = obj.TYPE_REG
   667  		p1.To.Reg = v.Reg0()
   668  		p2 := s.Prog(sc)
   669  		p2.From.Type = obj.TYPE_REG
   670  		p2.From.Reg = mips.REGTMP
   671  		p2.To.Type = obj.TYPE_MEM
   672  		p2.To.Reg = v.Args[0].Reg()
   673  		p3 := s.Prog(mips.ABEQ)
   674  		p3.From.Type = obj.TYPE_REG
   675  		p3.From.Reg = mips.REGTMP
   676  		p3.To.Type = obj.TYPE_BRANCH
   677  		p3.To.SetTarget(p)
   678  		s.Prog(mips.ASYNC)
   679  	case ssa.OpMIPS64LoweredAtomicAdd32, ssa.OpMIPS64LoweredAtomicAdd64:
   680  		// SYNC
   681  		// LL	(Rarg0), Rout
   682  		// ADDV Rarg1, Rout, Rtmp
   683  		// SC	Rtmp, (Rarg0)
   684  		// BEQ	Rtmp, -3(PC)
   685  		// SYNC
   686  		// ADDV Rarg1, Rout
   687  		ll := mips.ALLV
   688  		sc := mips.ASCV
   689  		if v.Op == ssa.OpMIPS64LoweredAtomicAdd32 {
   690  			ll = mips.ALL
   691  			sc = mips.ASC
   692  		}
   693  		s.Prog(mips.ASYNC)
   694  		p := s.Prog(ll)
   695  		p.From.Type = obj.TYPE_MEM
   696  		p.From.Reg = v.Args[0].Reg()
   697  		p.To.Type = obj.TYPE_REG
   698  		p.To.Reg = v.Reg0()
   699  		p1 := s.Prog(mips.AADDVU)
   700  		p1.From.Type = obj.TYPE_REG
   701  		p1.From.Reg = v.Args[1].Reg()
   702  		p1.Reg = v.Reg0()
   703  		p1.To.Type = obj.TYPE_REG
   704  		p1.To.Reg = mips.REGTMP
   705  		p2 := s.Prog(sc)
   706  		p2.From.Type = obj.TYPE_REG
   707  		p2.From.Reg = mips.REGTMP
   708  		p2.To.Type = obj.TYPE_MEM
   709  		p2.To.Reg = v.Args[0].Reg()
   710  		p3 := s.Prog(mips.ABEQ)
   711  		p3.From.Type = obj.TYPE_REG
   712  		p3.From.Reg = mips.REGTMP
   713  		p3.To.Type = obj.TYPE_BRANCH
   714  		p3.To.SetTarget(p)
   715  		s.Prog(mips.ASYNC)
   716  		p4 := s.Prog(mips.AADDVU)
   717  		p4.From.Type = obj.TYPE_REG
   718  		p4.From.Reg = v.Args[1].Reg()
   719  		p4.Reg = v.Reg0()
   720  		p4.To.Type = obj.TYPE_REG
   721  		p4.To.Reg = v.Reg0()
   722  	case ssa.OpMIPS64LoweredAtomicAddconst32, ssa.OpMIPS64LoweredAtomicAddconst64:
   723  		// SYNC
   724  		// LL	(Rarg0), Rout
   725  		// ADDV $auxint, Rout, Rtmp
   726  		// SC	Rtmp, (Rarg0)
   727  		// BEQ	Rtmp, -3(PC)
   728  		// SYNC
   729  		// ADDV $auxint, Rout
   730  		ll := mips.ALLV
   731  		sc := mips.ASCV
   732  		if v.Op == ssa.OpMIPS64LoweredAtomicAddconst32 {
   733  			ll = mips.ALL
   734  			sc = mips.ASC
   735  		}
   736  		s.Prog(mips.ASYNC)
   737  		p := s.Prog(ll)
   738  		p.From.Type = obj.TYPE_MEM
   739  		p.From.Reg = v.Args[0].Reg()
   740  		p.To.Type = obj.TYPE_REG
   741  		p.To.Reg = v.Reg0()
   742  		p1 := s.Prog(mips.AADDVU)
   743  		p1.From.Type = obj.TYPE_CONST
   744  		p1.From.Offset = v.AuxInt
   745  		p1.Reg = v.Reg0()
   746  		p1.To.Type = obj.TYPE_REG
   747  		p1.To.Reg = mips.REGTMP
   748  		p2 := s.Prog(sc)
   749  		p2.From.Type = obj.TYPE_REG
   750  		p2.From.Reg = mips.REGTMP
   751  		p2.To.Type = obj.TYPE_MEM
   752  		p2.To.Reg = v.Args[0].Reg()
   753  		p3 := s.Prog(mips.ABEQ)
   754  		p3.From.Type = obj.TYPE_REG
   755  		p3.From.Reg = mips.REGTMP
   756  		p3.To.Type = obj.TYPE_BRANCH
   757  		p3.To.SetTarget(p)
   758  		s.Prog(mips.ASYNC)
   759  		p4 := s.Prog(mips.AADDVU)
   760  		p4.From.Type = obj.TYPE_CONST
   761  		p4.From.Offset = v.AuxInt
   762  		p4.Reg = v.Reg0()
   763  		p4.To.Type = obj.TYPE_REG
   764  		p4.To.Reg = v.Reg0()
   765  	case ssa.OpMIPS64LoweredAtomicAnd32,
   766  		ssa.OpMIPS64LoweredAtomicOr32:
   767  		// SYNC
   768  		// LL	(Rarg0), Rtmp
   769  		// AND/OR	Rarg1, Rtmp
   770  		// SC	Rtmp, (Rarg0)
   771  		// BEQ	Rtmp, -3(PC)
   772  		// SYNC
   773  		s.Prog(mips.ASYNC)
   774  
   775  		p := s.Prog(mips.ALL)
   776  		p.From.Type = obj.TYPE_MEM
   777  		p.From.Reg = v.Args[0].Reg()
   778  		p.To.Type = obj.TYPE_REG
   779  		p.To.Reg = mips.REGTMP
   780  
   781  		p1 := s.Prog(v.Op.Asm())
   782  		p1.From.Type = obj.TYPE_REG
   783  		p1.From.Reg = v.Args[1].Reg()
   784  		p1.Reg = mips.REGTMP
   785  		p1.To.Type = obj.TYPE_REG
   786  		p1.To.Reg = mips.REGTMP
   787  
   788  		p2 := s.Prog(mips.ASC)
   789  		p2.From.Type = obj.TYPE_REG
   790  		p2.From.Reg = mips.REGTMP
   791  		p2.To.Type = obj.TYPE_MEM
   792  		p2.To.Reg = v.Args[0].Reg()
   793  
   794  		p3 := s.Prog(mips.ABEQ)
   795  		p3.From.Type = obj.TYPE_REG
   796  		p3.From.Reg = mips.REGTMP
   797  		p3.To.Type = obj.TYPE_BRANCH
   798  		p3.To.SetTarget(p)
   799  
   800  		s.Prog(mips.ASYNC)
   801  
   802  	case ssa.OpMIPS64LoweredAtomicCas32, ssa.OpMIPS64LoweredAtomicCas64:
   803  		// MOVV $0, Rout
   804  		// SYNC
   805  		// LL	(Rarg0), Rtmp
   806  		// BNE	Rtmp, Rarg1, 4(PC)
   807  		// MOVV Rarg2, Rout
   808  		// SC	Rout, (Rarg0)
   809  		// BEQ	Rout, -4(PC)
   810  		// SYNC
   811  		ll := mips.ALLV
   812  		sc := mips.ASCV
   813  		if v.Op == ssa.OpMIPS64LoweredAtomicCas32 {
   814  			ll = mips.ALL
   815  			sc = mips.ASC
   816  		}
   817  		p := s.Prog(mips.AMOVV)
   818  		p.From.Type = obj.TYPE_REG
   819  		p.From.Reg = mips.REGZERO
   820  		p.To.Type = obj.TYPE_REG
   821  		p.To.Reg = v.Reg0()
   822  		s.Prog(mips.ASYNC)
   823  		p1 := s.Prog(ll)
   824  		p1.From.Type = obj.TYPE_MEM
   825  		p1.From.Reg = v.Args[0].Reg()
   826  		p1.To.Type = obj.TYPE_REG
   827  		p1.To.Reg = mips.REGTMP
   828  		p2 := s.Prog(mips.ABNE)
   829  		p2.From.Type = obj.TYPE_REG
   830  		p2.From.Reg = v.Args[1].Reg()
   831  		p2.Reg = mips.REGTMP
   832  		p2.To.Type = obj.TYPE_BRANCH
   833  		p3 := s.Prog(mips.AMOVV)
   834  		p3.From.Type = obj.TYPE_REG
   835  		p3.From.Reg = v.Args[2].Reg()
   836  		p3.To.Type = obj.TYPE_REG
   837  		p3.To.Reg = v.Reg0()
   838  		p4 := s.Prog(sc)
   839  		p4.From.Type = obj.TYPE_REG
   840  		p4.From.Reg = v.Reg0()
   841  		p4.To.Type = obj.TYPE_MEM
   842  		p4.To.Reg = v.Args[0].Reg()
   843  		p5 := s.Prog(mips.ABEQ)
   844  		p5.From.Type = obj.TYPE_REG
   845  		p5.From.Reg = v.Reg0()
   846  		p5.To.Type = obj.TYPE_BRANCH
   847  		p5.To.SetTarget(p1)
   848  		p6 := s.Prog(mips.ASYNC)
   849  		p2.To.SetTarget(p6)
   850  	case ssa.OpMIPS64LoweredNilCheck:
   851  		// Issue a load which will fault if arg is nil.
   852  		p := s.Prog(mips.AMOVB)
   853  		p.From.Type = obj.TYPE_MEM
   854  		p.From.Reg = v.Args[0].Reg()
   855  		ssagen.AddAux(&p.From, v)
   856  		p.To.Type = obj.TYPE_REG
   857  		p.To.Reg = mips.REGTMP
   858  		if logopt.Enabled() {
   859  			logopt.LogOpt(v.Pos, "nilcheck", "genssa", v.Block.Func.Name)
   860  		}
   861  		if base.Debug.Nil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
   862  			base.WarnfAt(v.Pos, "generated nil check")
   863  		}
   864  	case ssa.OpMIPS64FPFlagTrue,
   865  		ssa.OpMIPS64FPFlagFalse:
   866  		// MOVV	$0, r
   867  		// BFPF	2(PC)
   868  		// MOVV	$1, r
   869  		branch := mips.ABFPF
   870  		if v.Op == ssa.OpMIPS64FPFlagFalse {
   871  			branch = mips.ABFPT
   872  		}
   873  		p := s.Prog(mips.AMOVV)
   874  		p.From.Type = obj.TYPE_REG
   875  		p.From.Reg = mips.REGZERO
   876  		p.To.Type = obj.TYPE_REG
   877  		p.To.Reg = v.Reg()
   878  		p2 := s.Prog(branch)
   879  		p2.To.Type = obj.TYPE_BRANCH
   880  		p3 := s.Prog(mips.AMOVV)
   881  		p3.From.Type = obj.TYPE_CONST
   882  		p3.From.Offset = 1
   883  		p3.To.Type = obj.TYPE_REG
   884  		p3.To.Reg = v.Reg()
   885  		p4 := s.Prog(obj.ANOP) // not a machine instruction, for branch to land
   886  		p2.To.SetTarget(p4)
   887  	case ssa.OpMIPS64LoweredGetClosurePtr:
   888  		// Closure pointer is R22 (mips.REGCTXT).
   889  		ssagen.CheckLoweredGetClosurePtr(v)
   890  	case ssa.OpMIPS64LoweredGetCallerSP:
   891  		// caller's SP is FixedFrameSize below the address of the first arg
   892  		p := s.Prog(mips.AMOVV)
   893  		p.From.Type = obj.TYPE_ADDR
   894  		p.From.Offset = -base.Ctxt.Arch.FixedFrameSize
   895  		p.From.Name = obj.NAME_PARAM
   896  		p.To.Type = obj.TYPE_REG
   897  		p.To.Reg = v.Reg()
   898  	case ssa.OpMIPS64LoweredGetCallerPC:
   899  		p := s.Prog(obj.AGETCALLERPC)
   900  		p.To.Type = obj.TYPE_REG
   901  		p.To.Reg = v.Reg()
   902  	case ssa.OpMIPS64LoweredPubBarrier:
   903  		// SYNC
   904  		s.Prog(v.Op.Asm())
   905  	case ssa.OpClobber, ssa.OpClobberReg:
   906  		// TODO: implement for clobberdead experiment. Nop is ok for now.
   907  	default:
   908  		v.Fatalf("genValue not implemented: %s", v.LongString())
   909  	}
   910  }
   911  
   912  var blockJump = map[ssa.BlockKind]struct {
   913  	asm, invasm obj.As
   914  }{
   915  	ssa.BlockMIPS64EQ:  {mips.ABEQ, mips.ABNE},
   916  	ssa.BlockMIPS64NE:  {mips.ABNE, mips.ABEQ},
   917  	ssa.BlockMIPS64LTZ: {mips.ABLTZ, mips.ABGEZ},
   918  	ssa.BlockMIPS64GEZ: {mips.ABGEZ, mips.ABLTZ},
   919  	ssa.BlockMIPS64LEZ: {mips.ABLEZ, mips.ABGTZ},
   920  	ssa.BlockMIPS64GTZ: {mips.ABGTZ, mips.ABLEZ},
   921  	ssa.BlockMIPS64FPT: {mips.ABFPT, mips.ABFPF},
   922  	ssa.BlockMIPS64FPF: {mips.ABFPF, mips.ABFPT},
   923  }
   924  
   925  func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
   926  	switch b.Kind {
   927  	case ssa.BlockPlain, ssa.BlockDefer:
   928  		if b.Succs[0].Block() != next {
   929  			p := s.Prog(obj.AJMP)
   930  			p.To.Type = obj.TYPE_BRANCH
   931  			s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
   932  		}
   933  	case ssa.BlockExit, ssa.BlockRetJmp:
   934  	case ssa.BlockRet:
   935  		s.Prog(obj.ARET)
   936  	case ssa.BlockMIPS64EQ, ssa.BlockMIPS64NE,
   937  		ssa.BlockMIPS64LTZ, ssa.BlockMIPS64GEZ,
   938  		ssa.BlockMIPS64LEZ, ssa.BlockMIPS64GTZ,
   939  		ssa.BlockMIPS64FPT, ssa.BlockMIPS64FPF:
   940  		jmp := blockJump[b.Kind]
   941  		var p *obj.Prog
   942  		switch next {
   943  		case b.Succs[0].Block():
   944  			p = s.Br(jmp.invasm, b.Succs[1].Block())
   945  		case b.Succs[1].Block():
   946  			p = s.Br(jmp.asm, b.Succs[0].Block())
   947  		default:
   948  			if b.Likely != ssa.BranchUnlikely {
   949  				p = s.Br(jmp.asm, b.Succs[0].Block())
   950  				s.Br(obj.AJMP, b.Succs[1].Block())
   951  			} else {
   952  				p = s.Br(jmp.invasm, b.Succs[1].Block())
   953  				s.Br(obj.AJMP, b.Succs[0].Block())
   954  			}
   955  		}
   956  		if !b.Controls[0].Type.IsFlags() {
   957  			p.From.Type = obj.TYPE_REG
   958  			p.From.Reg = b.Controls[0].Reg()
   959  		}
   960  	default:
   961  		b.Fatalf("branch not implemented: %s", b.LongString())
   962  	}
   963  }
   964  

View as plain text