Source file src/cmd/compile/internal/riscv64/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 riscv64
     6  
     7  import (
     8  	"cmd/compile/internal/base"
     9  	"cmd/compile/internal/ir"
    10  	"cmd/compile/internal/logopt"
    11  	"cmd/compile/internal/objw"
    12  	"cmd/compile/internal/ssa"
    13  	"cmd/compile/internal/ssagen"
    14  	"cmd/compile/internal/types"
    15  	"cmd/internal/obj"
    16  	"cmd/internal/obj/riscv"
    17  )
    18  
    19  // ssaRegToReg maps ssa register numbers to obj register numbers.
    20  var ssaRegToReg = []int16{
    21  	riscv.REG_X0,
    22  	// X1 (LR): unused
    23  	riscv.REG_X2,
    24  	riscv.REG_X3,
    25  	riscv.REG_X4,
    26  	riscv.REG_X5,
    27  	riscv.REG_X6,
    28  	riscv.REG_X7,
    29  	riscv.REG_X8,
    30  	riscv.REG_X9,
    31  	riscv.REG_X10,
    32  	riscv.REG_X11,
    33  	riscv.REG_X12,
    34  	riscv.REG_X13,
    35  	riscv.REG_X14,
    36  	riscv.REG_X15,
    37  	riscv.REG_X16,
    38  	riscv.REG_X17,
    39  	riscv.REG_X18,
    40  	riscv.REG_X19,
    41  	riscv.REG_X20,
    42  	riscv.REG_X21,
    43  	riscv.REG_X22,
    44  	riscv.REG_X23,
    45  	riscv.REG_X24,
    46  	riscv.REG_X25,
    47  	riscv.REG_X26,
    48  	riscv.REG_X27,
    49  	riscv.REG_X28,
    50  	riscv.REG_X29,
    51  	riscv.REG_X30,
    52  	riscv.REG_X31,
    53  	riscv.REG_F0,
    54  	riscv.REG_F1,
    55  	riscv.REG_F2,
    56  	riscv.REG_F3,
    57  	riscv.REG_F4,
    58  	riscv.REG_F5,
    59  	riscv.REG_F6,
    60  	riscv.REG_F7,
    61  	riscv.REG_F8,
    62  	riscv.REG_F9,
    63  	riscv.REG_F10,
    64  	riscv.REG_F11,
    65  	riscv.REG_F12,
    66  	riscv.REG_F13,
    67  	riscv.REG_F14,
    68  	riscv.REG_F15,
    69  	riscv.REG_F16,
    70  	riscv.REG_F17,
    71  	riscv.REG_F18,
    72  	riscv.REG_F19,
    73  	riscv.REG_F20,
    74  	riscv.REG_F21,
    75  	riscv.REG_F22,
    76  	riscv.REG_F23,
    77  	riscv.REG_F24,
    78  	riscv.REG_F25,
    79  	riscv.REG_F26,
    80  	riscv.REG_F27,
    81  	riscv.REG_F28,
    82  	riscv.REG_F29,
    83  	riscv.REG_F30,
    84  	riscv.REG_F31,
    85  	0, // SB isn't a real register.  We fill an Addr.Reg field with 0 in this case.
    86  }
    87  
    88  func loadByType(t *types.Type) obj.As {
    89  	width := t.Size()
    90  
    91  	if t.IsFloat() {
    92  		switch width {
    93  		case 4:
    94  			return riscv.AMOVF
    95  		case 8:
    96  			return riscv.AMOVD
    97  		default:
    98  			base.Fatalf("unknown float width for load %d in type %v", width, t)
    99  			return 0
   100  		}
   101  	}
   102  
   103  	switch width {
   104  	case 1:
   105  		if t.IsSigned() {
   106  			return riscv.AMOVB
   107  		} else {
   108  			return riscv.AMOVBU
   109  		}
   110  	case 2:
   111  		if t.IsSigned() {
   112  			return riscv.AMOVH
   113  		} else {
   114  			return riscv.AMOVHU
   115  		}
   116  	case 4:
   117  		if t.IsSigned() {
   118  			return riscv.AMOVW
   119  		} else {
   120  			return riscv.AMOVWU
   121  		}
   122  	case 8:
   123  		return riscv.AMOV
   124  	default:
   125  		base.Fatalf("unknown width for load %d in type %v", width, t)
   126  		return 0
   127  	}
   128  }
   129  
   130  // storeByType returns the store instruction of the given type.
   131  func storeByType(t *types.Type) obj.As {
   132  	width := t.Size()
   133  
   134  	if t.IsFloat() {
   135  		switch width {
   136  		case 4:
   137  			return riscv.AMOVF
   138  		case 8:
   139  			return riscv.AMOVD
   140  		default:
   141  			base.Fatalf("unknown float width for store %d in type %v", width, t)
   142  			return 0
   143  		}
   144  	}
   145  
   146  	switch width {
   147  	case 1:
   148  		return riscv.AMOVB
   149  	case 2:
   150  		return riscv.AMOVH
   151  	case 4:
   152  		return riscv.AMOVW
   153  	case 8:
   154  		return riscv.AMOV
   155  	default:
   156  		base.Fatalf("unknown width for store %d in type %v", width, t)
   157  		return 0
   158  	}
   159  }
   160  
   161  // largestMove returns the largest move instruction possible and its size,
   162  // given the alignment of the total size of the move.
   163  //
   164  // e.g., a 16-byte move may use MOV, but an 11-byte move must use MOVB.
   165  //
   166  // Note that the moves may not be on naturally aligned addresses depending on
   167  // the source and destination.
   168  //
   169  // This matches the calculation in ssa.moveSize.
   170  func largestMove(alignment int64) (obj.As, int64) {
   171  	switch {
   172  	case alignment%8 == 0:
   173  		return riscv.AMOV, 8
   174  	case alignment%4 == 0:
   175  		return riscv.AMOVW, 4
   176  	case alignment%2 == 0:
   177  		return riscv.AMOVH, 2
   178  	default:
   179  		return riscv.AMOVB, 1
   180  	}
   181  }
   182  
   183  // ssaMarkMoves marks any MOVXconst ops that need to avoid clobbering flags.
   184  // RISC-V has no flags, so this is a no-op.
   185  func ssaMarkMoves(s *ssagen.State, b *ssa.Block) {}
   186  
   187  func ssaGenValue(s *ssagen.State, v *ssa.Value) {
   188  	s.SetPos(v.Pos)
   189  
   190  	switch v.Op {
   191  	case ssa.OpInitMem:
   192  		// memory arg needs no code
   193  	case ssa.OpArg:
   194  		// input args need no code
   195  	case ssa.OpPhi:
   196  		ssagen.CheckLoweredPhi(v)
   197  	case ssa.OpCopy, ssa.OpRISCV64MOVDreg:
   198  		if v.Type.IsMemory() {
   199  			return
   200  		}
   201  		rs := v.Args[0].Reg()
   202  		rd := v.Reg()
   203  		if rs == rd {
   204  			return
   205  		}
   206  		as := riscv.AMOV
   207  		if v.Type.IsFloat() {
   208  			as = riscv.AMOVD
   209  		}
   210  		p := s.Prog(as)
   211  		p.From.Type = obj.TYPE_REG
   212  		p.From.Reg = rs
   213  		p.To.Type = obj.TYPE_REG
   214  		p.To.Reg = rd
   215  	case ssa.OpRISCV64MOVDnop:
   216  		// nothing to do
   217  	case ssa.OpLoadReg:
   218  		if v.Type.IsFlags() {
   219  			v.Fatalf("load flags not implemented: %v", v.LongString())
   220  			return
   221  		}
   222  		p := s.Prog(loadByType(v.Type))
   223  		ssagen.AddrAuto(&p.From, v.Args[0])
   224  		p.To.Type = obj.TYPE_REG
   225  		p.To.Reg = v.Reg()
   226  	case ssa.OpStoreReg:
   227  		if v.Type.IsFlags() {
   228  			v.Fatalf("store flags not implemented: %v", v.LongString())
   229  			return
   230  		}
   231  		p := s.Prog(storeByType(v.Type))
   232  		p.From.Type = obj.TYPE_REG
   233  		p.From.Reg = v.Args[0].Reg()
   234  		ssagen.AddrAuto(&p.To, v)
   235  	case ssa.OpArgIntReg, ssa.OpArgFloatReg:
   236  		// The assembler needs to wrap the entry safepoint/stack growth code with spill/unspill
   237  		// The loop only runs once.
   238  		for _, a := range v.Block.Func.RegArgs {
   239  			// Pass the spill/unspill information along to the assembler, offset by size of
   240  			// the saved LR slot.
   241  			addr := ssagen.SpillSlotAddr(a, riscv.REG_SP, base.Ctxt.Arch.FixedFrameSize)
   242  			s.FuncInfo().AddSpill(
   243  				obj.RegSpill{Reg: a.Reg, Addr: addr, Unspill: loadByType(a.Type), Spill: storeByType(a.Type)})
   244  		}
   245  		v.Block.Func.RegArgs = nil
   246  
   247  		ssagen.CheckArgReg(v)
   248  	case ssa.OpSP, ssa.OpSB, ssa.OpGetG:
   249  		// nothing to do
   250  	case ssa.OpRISCV64MOVBreg, ssa.OpRISCV64MOVHreg, ssa.OpRISCV64MOVWreg,
   251  		ssa.OpRISCV64MOVBUreg, ssa.OpRISCV64MOVHUreg, ssa.OpRISCV64MOVWUreg:
   252  		a := v.Args[0]
   253  		for a.Op == ssa.OpCopy || a.Op == ssa.OpRISCV64MOVDreg {
   254  			a = a.Args[0]
   255  		}
   256  		as := v.Op.Asm()
   257  		rs := v.Args[0].Reg()
   258  		rd := v.Reg()
   259  		if a.Op == ssa.OpLoadReg {
   260  			t := a.Type
   261  			switch {
   262  			case v.Op == ssa.OpRISCV64MOVBreg && t.Size() == 1 && t.IsSigned(),
   263  				v.Op == ssa.OpRISCV64MOVHreg && t.Size() == 2 && t.IsSigned(),
   264  				v.Op == ssa.OpRISCV64MOVWreg && t.Size() == 4 && t.IsSigned(),
   265  				v.Op == ssa.OpRISCV64MOVBUreg && t.Size() == 1 && !t.IsSigned(),
   266  				v.Op == ssa.OpRISCV64MOVHUreg && t.Size() == 2 && !t.IsSigned(),
   267  				v.Op == ssa.OpRISCV64MOVWUreg && t.Size() == 4 && !t.IsSigned():
   268  				// arg is a proper-typed load and already sign/zero-extended
   269  				if rs == rd {
   270  					return
   271  				}
   272  				as = riscv.AMOV
   273  			default:
   274  			}
   275  		}
   276  		p := s.Prog(as)
   277  		p.From.Type = obj.TYPE_REG
   278  		p.From.Reg = rs
   279  		p.To.Type = obj.TYPE_REG
   280  		p.To.Reg = rd
   281  	case ssa.OpRISCV64ADD, ssa.OpRISCV64SUB, ssa.OpRISCV64SUBW, ssa.OpRISCV64XNOR, ssa.OpRISCV64XOR,
   282  		ssa.OpRISCV64OR, ssa.OpRISCV64ORN, ssa.OpRISCV64AND, ssa.OpRISCV64ANDN,
   283  		ssa.OpRISCV64SLL, ssa.OpRISCV64SLLW, ssa.OpRISCV64SRA, ssa.OpRISCV64SRAW, ssa.OpRISCV64SRL, ssa.OpRISCV64SRLW,
   284  		ssa.OpRISCV64SLT, ssa.OpRISCV64SLTU, ssa.OpRISCV64MUL, ssa.OpRISCV64MULW, ssa.OpRISCV64MULH,
   285  		ssa.OpRISCV64MULHU, ssa.OpRISCV64DIV, ssa.OpRISCV64DIVU, ssa.OpRISCV64DIVW,
   286  		ssa.OpRISCV64DIVUW, ssa.OpRISCV64REM, ssa.OpRISCV64REMU, ssa.OpRISCV64REMW,
   287  		ssa.OpRISCV64REMUW,
   288  		ssa.OpRISCV64ROL, ssa.OpRISCV64ROLW, ssa.OpRISCV64ROR, ssa.OpRISCV64RORW,
   289  		ssa.OpRISCV64FADDS, ssa.OpRISCV64FSUBS, ssa.OpRISCV64FMULS, ssa.OpRISCV64FDIVS,
   290  		ssa.OpRISCV64FEQS, ssa.OpRISCV64FNES, ssa.OpRISCV64FLTS, ssa.OpRISCV64FLES,
   291  		ssa.OpRISCV64FADDD, ssa.OpRISCV64FSUBD, ssa.OpRISCV64FMULD, ssa.OpRISCV64FDIVD,
   292  		ssa.OpRISCV64FEQD, ssa.OpRISCV64FNED, ssa.OpRISCV64FLTD, ssa.OpRISCV64FLED, ssa.OpRISCV64FSGNJD,
   293  		ssa.OpRISCV64MIN, ssa.OpRISCV64MAX, ssa.OpRISCV64MINU, ssa.OpRISCV64MAXU,
   294  		ssa.OpRISCV64SH1ADD, ssa.OpRISCV64SH2ADD, ssa.OpRISCV64SH3ADD:
   295  		r := v.Reg()
   296  		r1 := v.Args[0].Reg()
   297  		r2 := v.Args[1].Reg()
   298  		p := s.Prog(v.Op.Asm())
   299  		p.From.Type = obj.TYPE_REG
   300  		p.From.Reg = r2
   301  		p.Reg = r1
   302  		p.To.Type = obj.TYPE_REG
   303  		p.To.Reg = r
   304  
   305  	case ssa.OpRISCV64LoweredFMAXD, ssa.OpRISCV64LoweredFMIND, ssa.OpRISCV64LoweredFMAXS, ssa.OpRISCV64LoweredFMINS:
   306  		// Most of FMIN/FMAX result match Go's required behaviour, unless one of the
   307  		// inputs is a NaN. As such, we need to explicitly test for NaN
   308  		// before using FMIN/FMAX.
   309  
   310  		// FADD Rarg0, Rarg1, Rout // FADD is used to propagate a NaN to the result in these cases.
   311  		// FEQ  Rarg0, Rarg0, Rtmp
   312  		// BEQZ Rtmp, end
   313  		// FEQ  Rarg1, Rarg1, Rtmp
   314  		// BEQZ Rtmp, end
   315  		// F(MIN | MAX)
   316  
   317  		r0 := v.Args[0].Reg()
   318  		r1 := v.Args[1].Reg()
   319  		out := v.Reg()
   320  		add, feq := riscv.AFADDD, riscv.AFEQD
   321  		if v.Op == ssa.OpRISCV64LoweredFMAXS || v.Op == ssa.OpRISCV64LoweredFMINS {
   322  			add = riscv.AFADDS
   323  			feq = riscv.AFEQS
   324  		}
   325  
   326  		p1 := s.Prog(add)
   327  		p1.From.Type = obj.TYPE_REG
   328  		p1.From.Reg = r0
   329  		p1.Reg = r1
   330  		p1.To.Type = obj.TYPE_REG
   331  		p1.To.Reg = out
   332  
   333  		p2 := s.Prog(feq)
   334  		p2.From.Type = obj.TYPE_REG
   335  		p2.From.Reg = r0
   336  		p2.Reg = r0
   337  		p2.To.Type = obj.TYPE_REG
   338  		p2.To.Reg = riscv.REG_TMP
   339  
   340  		p3 := s.Prog(riscv.ABEQ)
   341  		p3.From.Type = obj.TYPE_REG
   342  		p3.From.Reg = riscv.REG_ZERO
   343  		p3.Reg = riscv.REG_TMP
   344  		p3.To.Type = obj.TYPE_BRANCH
   345  
   346  		p4 := s.Prog(feq)
   347  		p4.From.Type = obj.TYPE_REG
   348  		p4.From.Reg = r1
   349  		p4.Reg = r1
   350  		p4.To.Type = obj.TYPE_REG
   351  		p4.To.Reg = riscv.REG_TMP
   352  
   353  		p5 := s.Prog(riscv.ABEQ)
   354  		p5.From.Type = obj.TYPE_REG
   355  		p5.From.Reg = riscv.REG_ZERO
   356  		p5.Reg = riscv.REG_TMP
   357  		p5.To.Type = obj.TYPE_BRANCH
   358  
   359  		p6 := s.Prog(v.Op.Asm())
   360  		p6.From.Type = obj.TYPE_REG
   361  		p6.From.Reg = r1
   362  		p6.Reg = r0
   363  		p6.To.Type = obj.TYPE_REG
   364  		p6.To.Reg = out
   365  
   366  		nop := s.Prog(obj.ANOP)
   367  		p3.To.SetTarget(nop)
   368  		p5.To.SetTarget(nop)
   369  
   370  	case ssa.OpRISCV64LoweredMuluhilo:
   371  		r0 := v.Args[0].Reg()
   372  		r1 := v.Args[1].Reg()
   373  		p := s.Prog(riscv.AMULHU)
   374  		p.From.Type = obj.TYPE_REG
   375  		p.From.Reg = r1
   376  		p.Reg = r0
   377  		p.To.Type = obj.TYPE_REG
   378  		p.To.Reg = v.Reg0()
   379  		p1 := s.Prog(riscv.AMUL)
   380  		p1.From.Type = obj.TYPE_REG
   381  		p1.From.Reg = r1
   382  		p1.Reg = r0
   383  		p1.To.Type = obj.TYPE_REG
   384  		p1.To.Reg = v.Reg1()
   385  	case ssa.OpRISCV64LoweredMuluover:
   386  		r0 := v.Args[0].Reg()
   387  		r1 := v.Args[1].Reg()
   388  		p := s.Prog(riscv.AMULHU)
   389  		p.From.Type = obj.TYPE_REG
   390  		p.From.Reg = r1
   391  		p.Reg = r0
   392  		p.To.Type = obj.TYPE_REG
   393  		p.To.Reg = v.Reg1()
   394  		p1 := s.Prog(riscv.AMUL)
   395  		p1.From.Type = obj.TYPE_REG
   396  		p1.From.Reg = r1
   397  		p1.Reg = r0
   398  		p1.To.Type = obj.TYPE_REG
   399  		p1.To.Reg = v.Reg0()
   400  		p2 := s.Prog(riscv.ASNEZ)
   401  		p2.From.Type = obj.TYPE_REG
   402  		p2.From.Reg = v.Reg1()
   403  		p2.To.Type = obj.TYPE_REG
   404  		p2.To.Reg = v.Reg1()
   405  	case ssa.OpRISCV64FMADDD, ssa.OpRISCV64FMSUBD, ssa.OpRISCV64FNMADDD, ssa.OpRISCV64FNMSUBD,
   406  		ssa.OpRISCV64FMADDS, ssa.OpRISCV64FMSUBS, ssa.OpRISCV64FNMADDS, ssa.OpRISCV64FNMSUBS:
   407  		r := v.Reg()
   408  		r1 := v.Args[0].Reg()
   409  		r2 := v.Args[1].Reg()
   410  		r3 := v.Args[2].Reg()
   411  		p := s.Prog(v.Op.Asm())
   412  		p.From.Type = obj.TYPE_REG
   413  		p.From.Reg = r2
   414  		p.Reg = r1
   415  		p.AddRestSource(obj.Addr{Type: obj.TYPE_REG, Reg: r3})
   416  		p.To.Type = obj.TYPE_REG
   417  		p.To.Reg = r
   418  	case ssa.OpRISCV64FSQRTS, ssa.OpRISCV64FNEGS, ssa.OpRISCV64FABSD, ssa.OpRISCV64FSQRTD, ssa.OpRISCV64FNEGD,
   419  		ssa.OpRISCV64FMVSX, ssa.OpRISCV64FMVDX,
   420  		ssa.OpRISCV64FCVTSW, ssa.OpRISCV64FCVTSL, ssa.OpRISCV64FCVTWS, ssa.OpRISCV64FCVTLS,
   421  		ssa.OpRISCV64FCVTDW, ssa.OpRISCV64FCVTDL, ssa.OpRISCV64FCVTWD, ssa.OpRISCV64FCVTLD, ssa.OpRISCV64FCVTDS, ssa.OpRISCV64FCVTSD,
   422  		ssa.OpRISCV64NOT, ssa.OpRISCV64NEG, ssa.OpRISCV64NEGW:
   423  		p := s.Prog(v.Op.Asm())
   424  		p.From.Type = obj.TYPE_REG
   425  		p.From.Reg = v.Args[0].Reg()
   426  		p.To.Type = obj.TYPE_REG
   427  		p.To.Reg = v.Reg()
   428  	case ssa.OpRISCV64ADDI, ssa.OpRISCV64ADDIW, ssa.OpRISCV64XORI, ssa.OpRISCV64ORI, ssa.OpRISCV64ANDI,
   429  		ssa.OpRISCV64SLLI, ssa.OpRISCV64SLLIW, ssa.OpRISCV64SRAI, ssa.OpRISCV64SRAIW,
   430  		ssa.OpRISCV64SRLI, ssa.OpRISCV64SRLIW, ssa.OpRISCV64SLTI, ssa.OpRISCV64SLTIU,
   431  		ssa.OpRISCV64RORI, ssa.OpRISCV64RORIW:
   432  		p := s.Prog(v.Op.Asm())
   433  		p.From.Type = obj.TYPE_CONST
   434  		p.From.Offset = v.AuxInt
   435  		p.Reg = v.Args[0].Reg()
   436  		p.To.Type = obj.TYPE_REG
   437  		p.To.Reg = v.Reg()
   438  	case ssa.OpRISCV64MOVDconst:
   439  		p := s.Prog(v.Op.Asm())
   440  		p.From.Type = obj.TYPE_CONST
   441  		p.From.Offset = v.AuxInt
   442  		p.To.Type = obj.TYPE_REG
   443  		p.To.Reg = v.Reg()
   444  	case ssa.OpRISCV64MOVaddr:
   445  		p := s.Prog(v.Op.Asm())
   446  		p.From.Type = obj.TYPE_ADDR
   447  		p.To.Type = obj.TYPE_REG
   448  		p.To.Reg = v.Reg()
   449  
   450  		var wantreg string
   451  		// MOVW $sym+off(base), R
   452  		switch v.Aux.(type) {
   453  		default:
   454  			v.Fatalf("aux is of unknown type %T", v.Aux)
   455  		case *obj.LSym:
   456  			wantreg = "SB"
   457  			ssagen.AddAux(&p.From, v)
   458  		case *ir.Name:
   459  			wantreg = "SP"
   460  			ssagen.AddAux(&p.From, v)
   461  		case nil:
   462  			// No sym, just MOVW $off(SP), R
   463  			wantreg = "SP"
   464  			p.From.Reg = riscv.REG_SP
   465  			p.From.Offset = v.AuxInt
   466  		}
   467  		if reg := v.Args[0].RegName(); reg != wantreg {
   468  			v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
   469  		}
   470  	case ssa.OpRISCV64MOVBload, ssa.OpRISCV64MOVHload, ssa.OpRISCV64MOVWload, ssa.OpRISCV64MOVDload,
   471  		ssa.OpRISCV64MOVBUload, ssa.OpRISCV64MOVHUload, ssa.OpRISCV64MOVWUload,
   472  		ssa.OpRISCV64FMOVWload, ssa.OpRISCV64FMOVDload:
   473  		p := s.Prog(v.Op.Asm())
   474  		p.From.Type = obj.TYPE_MEM
   475  		p.From.Reg = v.Args[0].Reg()
   476  		ssagen.AddAux(&p.From, v)
   477  		p.To.Type = obj.TYPE_REG
   478  		p.To.Reg = v.Reg()
   479  	case ssa.OpRISCV64MOVBstore, ssa.OpRISCV64MOVHstore, ssa.OpRISCV64MOVWstore, ssa.OpRISCV64MOVDstore,
   480  		ssa.OpRISCV64FMOVWstore, ssa.OpRISCV64FMOVDstore:
   481  		p := s.Prog(v.Op.Asm())
   482  		p.From.Type = obj.TYPE_REG
   483  		p.From.Reg = v.Args[1].Reg()
   484  		p.To.Type = obj.TYPE_MEM
   485  		p.To.Reg = v.Args[0].Reg()
   486  		ssagen.AddAux(&p.To, v)
   487  	case ssa.OpRISCV64MOVBstorezero, ssa.OpRISCV64MOVHstorezero, ssa.OpRISCV64MOVWstorezero, ssa.OpRISCV64MOVDstorezero:
   488  		p := s.Prog(v.Op.Asm())
   489  		p.From.Type = obj.TYPE_REG
   490  		p.From.Reg = riscv.REG_ZERO
   491  		p.To.Type = obj.TYPE_MEM
   492  		p.To.Reg = v.Args[0].Reg()
   493  		ssagen.AddAux(&p.To, v)
   494  	case ssa.OpRISCV64SEQZ, ssa.OpRISCV64SNEZ:
   495  		p := s.Prog(v.Op.Asm())
   496  		p.From.Type = obj.TYPE_REG
   497  		p.From.Reg = v.Args[0].Reg()
   498  		p.To.Type = obj.TYPE_REG
   499  		p.To.Reg = v.Reg()
   500  	case ssa.OpRISCV64CALLstatic, ssa.OpRISCV64CALLclosure, ssa.OpRISCV64CALLinter:
   501  		s.Call(v)
   502  	case ssa.OpRISCV64CALLtail:
   503  		s.TailCall(v)
   504  	case ssa.OpRISCV64LoweredWB:
   505  		p := s.Prog(obj.ACALL)
   506  		p.To.Type = obj.TYPE_MEM
   507  		p.To.Name = obj.NAME_EXTERN
   508  		// AuxInt encodes how many buffer entries we need.
   509  		p.To.Sym = ir.Syms.GCWriteBarrier[v.AuxInt-1]
   510  	case ssa.OpRISCV64LoweredPanicBoundsA, ssa.OpRISCV64LoweredPanicBoundsB, ssa.OpRISCV64LoweredPanicBoundsC:
   511  		p := s.Prog(obj.ACALL)
   512  		p.To.Type = obj.TYPE_MEM
   513  		p.To.Name = obj.NAME_EXTERN
   514  		p.To.Sym = ssagen.BoundsCheckFunc[v.AuxInt]
   515  		s.UseArgs(16) // space used in callee args area by assembly stubs
   516  
   517  	case ssa.OpRISCV64LoweredAtomicLoad8:
   518  		s.Prog(riscv.AFENCE)
   519  		p := s.Prog(riscv.AMOVBU)
   520  		p.From.Type = obj.TYPE_MEM
   521  		p.From.Reg = v.Args[0].Reg()
   522  		p.To.Type = obj.TYPE_REG
   523  		p.To.Reg = v.Reg0()
   524  		s.Prog(riscv.AFENCE)
   525  
   526  	case ssa.OpRISCV64LoweredAtomicLoad32, ssa.OpRISCV64LoweredAtomicLoad64:
   527  		as := riscv.ALRW
   528  		if v.Op == ssa.OpRISCV64LoweredAtomicLoad64 {
   529  			as = riscv.ALRD
   530  		}
   531  		p := s.Prog(as)
   532  		p.From.Type = obj.TYPE_MEM
   533  		p.From.Reg = v.Args[0].Reg()
   534  		p.To.Type = obj.TYPE_REG
   535  		p.To.Reg = v.Reg0()
   536  
   537  	case ssa.OpRISCV64LoweredAtomicStore8:
   538  		s.Prog(riscv.AFENCE)
   539  		p := s.Prog(riscv.AMOVB)
   540  		p.From.Type = obj.TYPE_REG
   541  		p.From.Reg = v.Args[1].Reg()
   542  		p.To.Type = obj.TYPE_MEM
   543  		p.To.Reg = v.Args[0].Reg()
   544  		s.Prog(riscv.AFENCE)
   545  
   546  	case ssa.OpRISCV64LoweredAtomicStore32, ssa.OpRISCV64LoweredAtomicStore64:
   547  		as := riscv.AAMOSWAPW
   548  		if v.Op == ssa.OpRISCV64LoweredAtomicStore64 {
   549  			as = riscv.AAMOSWAPD
   550  		}
   551  		p := s.Prog(as)
   552  		p.From.Type = obj.TYPE_REG
   553  		p.From.Reg = v.Args[1].Reg()
   554  		p.To.Type = obj.TYPE_MEM
   555  		p.To.Reg = v.Args[0].Reg()
   556  		p.RegTo2 = riscv.REG_ZERO
   557  
   558  	case ssa.OpRISCV64LoweredAtomicAdd32, ssa.OpRISCV64LoweredAtomicAdd64:
   559  		as := riscv.AAMOADDW
   560  		if v.Op == ssa.OpRISCV64LoweredAtomicAdd64 {
   561  			as = riscv.AAMOADDD
   562  		}
   563  		p := s.Prog(as)
   564  		p.From.Type = obj.TYPE_REG
   565  		p.From.Reg = v.Args[1].Reg()
   566  		p.To.Type = obj.TYPE_MEM
   567  		p.To.Reg = v.Args[0].Reg()
   568  		p.RegTo2 = riscv.REG_TMP
   569  
   570  		p2 := s.Prog(riscv.AADD)
   571  		p2.From.Type = obj.TYPE_REG
   572  		p2.From.Reg = riscv.REG_TMP
   573  		p2.Reg = v.Args[1].Reg()
   574  		p2.To.Type = obj.TYPE_REG
   575  		p2.To.Reg = v.Reg0()
   576  
   577  	case ssa.OpRISCV64LoweredAtomicExchange32, ssa.OpRISCV64LoweredAtomicExchange64:
   578  		as := riscv.AAMOSWAPW
   579  		if v.Op == ssa.OpRISCV64LoweredAtomicExchange64 {
   580  			as = riscv.AAMOSWAPD
   581  		}
   582  		p := s.Prog(as)
   583  		p.From.Type = obj.TYPE_REG
   584  		p.From.Reg = v.Args[1].Reg()
   585  		p.To.Type = obj.TYPE_MEM
   586  		p.To.Reg = v.Args[0].Reg()
   587  		p.RegTo2 = v.Reg0()
   588  
   589  	case ssa.OpRISCV64LoweredAtomicCas32, ssa.OpRISCV64LoweredAtomicCas64:
   590  		// MOV  ZERO, Rout
   591  		// LR	(Rarg0), Rtmp
   592  		// BNE	Rtmp, Rarg1, 3(PC)
   593  		// SC	Rarg2, (Rarg0), Rtmp
   594  		// BNE	Rtmp, ZERO, -3(PC)
   595  		// MOV	$1, Rout
   596  
   597  		lr := riscv.ALRW
   598  		sc := riscv.ASCW
   599  		if v.Op == ssa.OpRISCV64LoweredAtomicCas64 {
   600  			lr = riscv.ALRD
   601  			sc = riscv.ASCD
   602  		}
   603  
   604  		r0 := v.Args[0].Reg()
   605  		r1 := v.Args[1].Reg()
   606  		r2 := v.Args[2].Reg()
   607  		out := v.Reg0()
   608  
   609  		p := s.Prog(riscv.AMOV)
   610  		p.From.Type = obj.TYPE_REG
   611  		p.From.Reg = riscv.REG_ZERO
   612  		p.To.Type = obj.TYPE_REG
   613  		p.To.Reg = out
   614  
   615  		p1 := s.Prog(lr)
   616  		p1.From.Type = obj.TYPE_MEM
   617  		p1.From.Reg = r0
   618  		p1.To.Type = obj.TYPE_REG
   619  		p1.To.Reg = riscv.REG_TMP
   620  
   621  		p2 := s.Prog(riscv.ABNE)
   622  		p2.From.Type = obj.TYPE_REG
   623  		p2.From.Reg = r1
   624  		p2.Reg = riscv.REG_TMP
   625  		p2.To.Type = obj.TYPE_BRANCH
   626  
   627  		p3 := s.Prog(sc)
   628  		p3.From.Type = obj.TYPE_REG
   629  		p3.From.Reg = r2
   630  		p3.To.Type = obj.TYPE_MEM
   631  		p3.To.Reg = r0
   632  		p3.RegTo2 = riscv.REG_TMP
   633  
   634  		p4 := s.Prog(riscv.ABNE)
   635  		p4.From.Type = obj.TYPE_REG
   636  		p4.From.Reg = riscv.REG_TMP
   637  		p4.Reg = riscv.REG_ZERO
   638  		p4.To.Type = obj.TYPE_BRANCH
   639  		p4.To.SetTarget(p1)
   640  
   641  		p5 := s.Prog(riscv.AMOV)
   642  		p5.From.Type = obj.TYPE_CONST
   643  		p5.From.Offset = 1
   644  		p5.To.Type = obj.TYPE_REG
   645  		p5.To.Reg = out
   646  
   647  		p6 := s.Prog(obj.ANOP)
   648  		p2.To.SetTarget(p6)
   649  
   650  	case ssa.OpRISCV64LoweredAtomicAnd32, ssa.OpRISCV64LoweredAtomicOr32:
   651  		p := s.Prog(v.Op.Asm())
   652  		p.From.Type = obj.TYPE_REG
   653  		p.From.Reg = v.Args[1].Reg()
   654  		p.To.Type = obj.TYPE_MEM
   655  		p.To.Reg = v.Args[0].Reg()
   656  		p.RegTo2 = riscv.REG_ZERO
   657  
   658  	case ssa.OpRISCV64LoweredZero:
   659  		mov, sz := largestMove(v.AuxInt)
   660  
   661  		//	mov	ZERO, (Rarg0)
   662  		//	ADD	$sz, Rarg0
   663  		//	BGEU	Rarg1, Rarg0, -2(PC)
   664  
   665  		p := s.Prog(mov)
   666  		p.From.Type = obj.TYPE_REG
   667  		p.From.Reg = riscv.REG_ZERO
   668  		p.To.Type = obj.TYPE_MEM
   669  		p.To.Reg = v.Args[0].Reg()
   670  
   671  		p2 := s.Prog(riscv.AADD)
   672  		p2.From.Type = obj.TYPE_CONST
   673  		p2.From.Offset = sz
   674  		p2.To.Type = obj.TYPE_REG
   675  		p2.To.Reg = v.Args[0].Reg()
   676  
   677  		p3 := s.Prog(riscv.ABGEU)
   678  		p3.To.Type = obj.TYPE_BRANCH
   679  		p3.Reg = v.Args[0].Reg()
   680  		p3.From.Type = obj.TYPE_REG
   681  		p3.From.Reg = v.Args[1].Reg()
   682  		p3.To.SetTarget(p)
   683  
   684  	case ssa.OpRISCV64LoweredMove:
   685  		mov, sz := largestMove(v.AuxInt)
   686  
   687  		//	mov	(Rarg1), T2
   688  		//	mov	T2, (Rarg0)
   689  		//	ADD	$sz, Rarg0
   690  		//	ADD	$sz, Rarg1
   691  		//	BGEU	Rarg2, Rarg0, -4(PC)
   692  
   693  		p := s.Prog(mov)
   694  		p.From.Type = obj.TYPE_MEM
   695  		p.From.Reg = v.Args[1].Reg()
   696  		p.To.Type = obj.TYPE_REG
   697  		p.To.Reg = riscv.REG_T2
   698  
   699  		p2 := s.Prog(mov)
   700  		p2.From.Type = obj.TYPE_REG
   701  		p2.From.Reg = riscv.REG_T2
   702  		p2.To.Type = obj.TYPE_MEM
   703  		p2.To.Reg = v.Args[0].Reg()
   704  
   705  		p3 := s.Prog(riscv.AADD)
   706  		p3.From.Type = obj.TYPE_CONST
   707  		p3.From.Offset = sz
   708  		p3.To.Type = obj.TYPE_REG
   709  		p3.To.Reg = v.Args[0].Reg()
   710  
   711  		p4 := s.Prog(riscv.AADD)
   712  		p4.From.Type = obj.TYPE_CONST
   713  		p4.From.Offset = sz
   714  		p4.To.Type = obj.TYPE_REG
   715  		p4.To.Reg = v.Args[1].Reg()
   716  
   717  		p5 := s.Prog(riscv.ABGEU)
   718  		p5.To.Type = obj.TYPE_BRANCH
   719  		p5.Reg = v.Args[1].Reg()
   720  		p5.From.Type = obj.TYPE_REG
   721  		p5.From.Reg = v.Args[2].Reg()
   722  		p5.To.SetTarget(p)
   723  
   724  	case ssa.OpRISCV64LoweredNilCheck:
   725  		// Issue a load which will fault if arg is nil.
   726  		p := s.Prog(riscv.AMOVB)
   727  		p.From.Type = obj.TYPE_MEM
   728  		p.From.Reg = v.Args[0].Reg()
   729  		ssagen.AddAux(&p.From, v)
   730  		p.To.Type = obj.TYPE_REG
   731  		p.To.Reg = riscv.REG_ZERO
   732  		if logopt.Enabled() {
   733  			logopt.LogOpt(v.Pos, "nilcheck", "genssa", v.Block.Func.Name)
   734  		}
   735  		if base.Debug.Nil != 0 && v.Pos.Line() > 1 { // v.Pos == 1 in generated wrappers
   736  			base.WarnfAt(v.Pos, "generated nil check")
   737  		}
   738  
   739  	case ssa.OpRISCV64LoweredGetClosurePtr:
   740  		// Closure pointer is S10 (riscv.REG_CTXT).
   741  		ssagen.CheckLoweredGetClosurePtr(v)
   742  
   743  	case ssa.OpRISCV64LoweredGetCallerSP:
   744  		// caller's SP is FixedFrameSize below the address of the first arg
   745  		p := s.Prog(riscv.AMOV)
   746  		p.From.Type = obj.TYPE_ADDR
   747  		p.From.Offset = -base.Ctxt.Arch.FixedFrameSize
   748  		p.From.Name = obj.NAME_PARAM
   749  		p.To.Type = obj.TYPE_REG
   750  		p.To.Reg = v.Reg()
   751  
   752  	case ssa.OpRISCV64LoweredGetCallerPC:
   753  		p := s.Prog(obj.AGETCALLERPC)
   754  		p.To.Type = obj.TYPE_REG
   755  		p.To.Reg = v.Reg()
   756  
   757  	case ssa.OpRISCV64DUFFZERO:
   758  		p := s.Prog(obj.ADUFFZERO)
   759  		p.To.Type = obj.TYPE_MEM
   760  		p.To.Name = obj.NAME_EXTERN
   761  		p.To.Sym = ir.Syms.Duffzero
   762  		p.To.Offset = v.AuxInt
   763  
   764  	case ssa.OpRISCV64DUFFCOPY:
   765  		p := s.Prog(obj.ADUFFCOPY)
   766  		p.To.Type = obj.TYPE_MEM
   767  		p.To.Name = obj.NAME_EXTERN
   768  		p.To.Sym = ir.Syms.Duffcopy
   769  		p.To.Offset = v.AuxInt
   770  
   771  	case ssa.OpRISCV64LoweredPubBarrier:
   772  		// FENCE
   773  		s.Prog(v.Op.Asm())
   774  
   775  	case ssa.OpRISCV64LoweredRound32F, ssa.OpRISCV64LoweredRound64F:
   776  		// input is already rounded
   777  
   778  	case ssa.OpClobber, ssa.OpClobberReg:
   779  		// TODO: implement for clobberdead experiment. Nop is ok for now.
   780  
   781  	default:
   782  		v.Fatalf("Unhandled op %v", v.Op)
   783  	}
   784  }
   785  
   786  var blockBranch = [...]obj.As{
   787  	ssa.BlockRISCV64BEQ:  riscv.ABEQ,
   788  	ssa.BlockRISCV64BEQZ: riscv.ABEQZ,
   789  	ssa.BlockRISCV64BGE:  riscv.ABGE,
   790  	ssa.BlockRISCV64BGEU: riscv.ABGEU,
   791  	ssa.BlockRISCV64BGEZ: riscv.ABGEZ,
   792  	ssa.BlockRISCV64BGTZ: riscv.ABGTZ,
   793  	ssa.BlockRISCV64BLEZ: riscv.ABLEZ,
   794  	ssa.BlockRISCV64BLT:  riscv.ABLT,
   795  	ssa.BlockRISCV64BLTU: riscv.ABLTU,
   796  	ssa.BlockRISCV64BLTZ: riscv.ABLTZ,
   797  	ssa.BlockRISCV64BNE:  riscv.ABNE,
   798  	ssa.BlockRISCV64BNEZ: riscv.ABNEZ,
   799  }
   800  
   801  func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
   802  	s.SetPos(b.Pos)
   803  
   804  	switch b.Kind {
   805  	case ssa.BlockDefer:
   806  		// defer returns in A0:
   807  		// 0 if we should continue executing
   808  		// 1 if we should jump to deferreturn call
   809  		p := s.Prog(riscv.ABNE)
   810  		p.To.Type = obj.TYPE_BRANCH
   811  		p.From.Type = obj.TYPE_REG
   812  		p.From.Reg = riscv.REG_ZERO
   813  		p.Reg = riscv.REG_A0
   814  		s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[1].Block()})
   815  		if b.Succs[0].Block() != next {
   816  			p := s.Prog(obj.AJMP)
   817  			p.To.Type = obj.TYPE_BRANCH
   818  			s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
   819  		}
   820  	case ssa.BlockPlain:
   821  		if b.Succs[0].Block() != next {
   822  			p := s.Prog(obj.AJMP)
   823  			p.To.Type = obj.TYPE_BRANCH
   824  			s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
   825  		}
   826  	case ssa.BlockExit, ssa.BlockRetJmp:
   827  	case ssa.BlockRet:
   828  		s.Prog(obj.ARET)
   829  	case ssa.BlockRISCV64BEQ, ssa.BlockRISCV64BEQZ, ssa.BlockRISCV64BNE, ssa.BlockRISCV64BNEZ,
   830  		ssa.BlockRISCV64BLT, ssa.BlockRISCV64BLEZ, ssa.BlockRISCV64BGE, ssa.BlockRISCV64BGEZ,
   831  		ssa.BlockRISCV64BLTZ, ssa.BlockRISCV64BGTZ, ssa.BlockRISCV64BLTU, ssa.BlockRISCV64BGEU:
   832  
   833  		as := blockBranch[b.Kind]
   834  		invAs := riscv.InvertBranch(as)
   835  
   836  		var p *obj.Prog
   837  		switch next {
   838  		case b.Succs[0].Block():
   839  			p = s.Br(invAs, b.Succs[1].Block())
   840  		case b.Succs[1].Block():
   841  			p = s.Br(as, b.Succs[0].Block())
   842  		default:
   843  			if b.Likely != ssa.BranchUnlikely {
   844  				p = s.Br(as, b.Succs[0].Block())
   845  				s.Br(obj.AJMP, b.Succs[1].Block())
   846  			} else {
   847  				p = s.Br(invAs, b.Succs[1].Block())
   848  				s.Br(obj.AJMP, b.Succs[0].Block())
   849  			}
   850  		}
   851  
   852  		p.From.Type = obj.TYPE_REG
   853  		switch b.Kind {
   854  		case ssa.BlockRISCV64BEQ, ssa.BlockRISCV64BNE, ssa.BlockRISCV64BLT, ssa.BlockRISCV64BGE, ssa.BlockRISCV64BLTU, ssa.BlockRISCV64BGEU:
   855  			if b.NumControls() != 2 {
   856  				b.Fatalf("Unexpected number of controls (%d != 2): %s", b.NumControls(), b.LongString())
   857  			}
   858  			p.From.Reg = b.Controls[0].Reg()
   859  			p.Reg = b.Controls[1].Reg()
   860  
   861  		case ssa.BlockRISCV64BEQZ, ssa.BlockRISCV64BNEZ, ssa.BlockRISCV64BGEZ, ssa.BlockRISCV64BLEZ, ssa.BlockRISCV64BLTZ, ssa.BlockRISCV64BGTZ:
   862  			if b.NumControls() != 1 {
   863  				b.Fatalf("Unexpected number of controls (%d != 1): %s", b.NumControls(), b.LongString())
   864  			}
   865  			p.From.Reg = b.Controls[0].Reg()
   866  		}
   867  
   868  	default:
   869  		b.Fatalf("Unhandled block: %s", b.LongString())
   870  	}
   871  }
   872  
   873  func loadRegResult(s *ssagen.State, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog {
   874  	p := s.Prog(loadByType(t))
   875  	p.From.Type = obj.TYPE_MEM
   876  	p.From.Name = obj.NAME_AUTO
   877  	p.From.Sym = n.Linksym()
   878  	p.From.Offset = n.FrameOffset() + off
   879  	p.To.Type = obj.TYPE_REG
   880  	p.To.Reg = reg
   881  	return p
   882  }
   883  
   884  func spillArgReg(pp *objw.Progs, p *obj.Prog, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog {
   885  	p = pp.Append(p, storeByType(t), obj.TYPE_REG, reg, 0, obj.TYPE_MEM, 0, n.FrameOffset()+off)
   886  	p.To.Name = obj.NAME_PARAM
   887  	p.To.Sym = n.Linksym()
   888  	p.Pos = p.Pos.WithNotStmt()
   889  	return p
   890  }
   891  

View as plain text