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, ssa.OpRISCV64CLZ, ssa.OpRISCV64CLZW, ssa.OpRISCV64CTZ, ssa.OpRISCV64CTZW,
   423  		ssa.OpRISCV64REV8, ssa.OpRISCV64CPOP, ssa.OpRISCV64CPOPW:
   424  		p := s.Prog(v.Op.Asm())
   425  		p.From.Type = obj.TYPE_REG
   426  		p.From.Reg = v.Args[0].Reg()
   427  		p.To.Type = obj.TYPE_REG
   428  		p.To.Reg = v.Reg()
   429  	case ssa.OpRISCV64ADDI, ssa.OpRISCV64ADDIW, ssa.OpRISCV64XORI, ssa.OpRISCV64ORI, ssa.OpRISCV64ANDI,
   430  		ssa.OpRISCV64SLLI, ssa.OpRISCV64SLLIW, ssa.OpRISCV64SRAI, ssa.OpRISCV64SRAIW,
   431  		ssa.OpRISCV64SRLI, ssa.OpRISCV64SRLIW, ssa.OpRISCV64SLTI, ssa.OpRISCV64SLTIU,
   432  		ssa.OpRISCV64RORI, ssa.OpRISCV64RORIW:
   433  		p := s.Prog(v.Op.Asm())
   434  		p.From.Type = obj.TYPE_CONST
   435  		p.From.Offset = v.AuxInt
   436  		p.Reg = v.Args[0].Reg()
   437  		p.To.Type = obj.TYPE_REG
   438  		p.To.Reg = v.Reg()
   439  	case ssa.OpRISCV64MOVDconst:
   440  		p := s.Prog(v.Op.Asm())
   441  		p.From.Type = obj.TYPE_CONST
   442  		p.From.Offset = v.AuxInt
   443  		p.To.Type = obj.TYPE_REG
   444  		p.To.Reg = v.Reg()
   445  	case ssa.OpRISCV64MOVaddr:
   446  		p := s.Prog(v.Op.Asm())
   447  		p.From.Type = obj.TYPE_ADDR
   448  		p.To.Type = obj.TYPE_REG
   449  		p.To.Reg = v.Reg()
   450  
   451  		var wantreg string
   452  		// MOVW $sym+off(base), R
   453  		switch v.Aux.(type) {
   454  		default:
   455  			v.Fatalf("aux is of unknown type %T", v.Aux)
   456  		case *obj.LSym:
   457  			wantreg = "SB"
   458  			ssagen.AddAux(&p.From, v)
   459  		case *ir.Name:
   460  			wantreg = "SP"
   461  			ssagen.AddAux(&p.From, v)
   462  		case nil:
   463  			// No sym, just MOVW $off(SP), R
   464  			wantreg = "SP"
   465  			p.From.Reg = riscv.REG_SP
   466  			p.From.Offset = v.AuxInt
   467  		}
   468  		if reg := v.Args[0].RegName(); reg != wantreg {
   469  			v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
   470  		}
   471  	case ssa.OpRISCV64MOVBload, ssa.OpRISCV64MOVHload, ssa.OpRISCV64MOVWload, ssa.OpRISCV64MOVDload,
   472  		ssa.OpRISCV64MOVBUload, ssa.OpRISCV64MOVHUload, ssa.OpRISCV64MOVWUload,
   473  		ssa.OpRISCV64FMOVWload, ssa.OpRISCV64FMOVDload:
   474  		p := s.Prog(v.Op.Asm())
   475  		p.From.Type = obj.TYPE_MEM
   476  		p.From.Reg = v.Args[0].Reg()
   477  		ssagen.AddAux(&p.From, v)
   478  		p.To.Type = obj.TYPE_REG
   479  		p.To.Reg = v.Reg()
   480  	case ssa.OpRISCV64MOVBstore, ssa.OpRISCV64MOVHstore, ssa.OpRISCV64MOVWstore, ssa.OpRISCV64MOVDstore,
   481  		ssa.OpRISCV64FMOVWstore, ssa.OpRISCV64FMOVDstore:
   482  		p := s.Prog(v.Op.Asm())
   483  		p.From.Type = obj.TYPE_REG
   484  		p.From.Reg = v.Args[1].Reg()
   485  		p.To.Type = obj.TYPE_MEM
   486  		p.To.Reg = v.Args[0].Reg()
   487  		ssagen.AddAux(&p.To, v)
   488  	case ssa.OpRISCV64MOVBstorezero, ssa.OpRISCV64MOVHstorezero, ssa.OpRISCV64MOVWstorezero, ssa.OpRISCV64MOVDstorezero:
   489  		p := s.Prog(v.Op.Asm())
   490  		p.From.Type = obj.TYPE_REG
   491  		p.From.Reg = riscv.REG_ZERO
   492  		p.To.Type = obj.TYPE_MEM
   493  		p.To.Reg = v.Args[0].Reg()
   494  		ssagen.AddAux(&p.To, v)
   495  	case ssa.OpRISCV64SEQZ, ssa.OpRISCV64SNEZ:
   496  		p := s.Prog(v.Op.Asm())
   497  		p.From.Type = obj.TYPE_REG
   498  		p.From.Reg = v.Args[0].Reg()
   499  		p.To.Type = obj.TYPE_REG
   500  		p.To.Reg = v.Reg()
   501  	case ssa.OpRISCV64CALLstatic, ssa.OpRISCV64CALLclosure, ssa.OpRISCV64CALLinter:
   502  		s.Call(v)
   503  	case ssa.OpRISCV64CALLtail:
   504  		s.TailCall(v)
   505  	case ssa.OpRISCV64LoweredWB:
   506  		p := s.Prog(obj.ACALL)
   507  		p.To.Type = obj.TYPE_MEM
   508  		p.To.Name = obj.NAME_EXTERN
   509  		// AuxInt encodes how many buffer entries we need.
   510  		p.To.Sym = ir.Syms.GCWriteBarrier[v.AuxInt-1]
   511  	case ssa.OpRISCV64LoweredPanicBoundsA, ssa.OpRISCV64LoweredPanicBoundsB, ssa.OpRISCV64LoweredPanicBoundsC:
   512  		p := s.Prog(obj.ACALL)
   513  		p.To.Type = obj.TYPE_MEM
   514  		p.To.Name = obj.NAME_EXTERN
   515  		p.To.Sym = ssagen.BoundsCheckFunc[v.AuxInt]
   516  		s.UseArgs(16) // space used in callee args area by assembly stubs
   517  
   518  	case ssa.OpRISCV64LoweredAtomicLoad8:
   519  		s.Prog(riscv.AFENCE)
   520  		p := s.Prog(riscv.AMOVBU)
   521  		p.From.Type = obj.TYPE_MEM
   522  		p.From.Reg = v.Args[0].Reg()
   523  		p.To.Type = obj.TYPE_REG
   524  		p.To.Reg = v.Reg0()
   525  		s.Prog(riscv.AFENCE)
   526  
   527  	case ssa.OpRISCV64LoweredAtomicLoad32, ssa.OpRISCV64LoweredAtomicLoad64:
   528  		as := riscv.ALRW
   529  		if v.Op == ssa.OpRISCV64LoweredAtomicLoad64 {
   530  			as = riscv.ALRD
   531  		}
   532  		p := s.Prog(as)
   533  		p.From.Type = obj.TYPE_MEM
   534  		p.From.Reg = v.Args[0].Reg()
   535  		p.To.Type = obj.TYPE_REG
   536  		p.To.Reg = v.Reg0()
   537  
   538  	case ssa.OpRISCV64LoweredAtomicStore8:
   539  		s.Prog(riscv.AFENCE)
   540  		p := s.Prog(riscv.AMOVB)
   541  		p.From.Type = obj.TYPE_REG
   542  		p.From.Reg = v.Args[1].Reg()
   543  		p.To.Type = obj.TYPE_MEM
   544  		p.To.Reg = v.Args[0].Reg()
   545  		s.Prog(riscv.AFENCE)
   546  
   547  	case ssa.OpRISCV64LoweredAtomicStore32, ssa.OpRISCV64LoweredAtomicStore64:
   548  		as := riscv.AAMOSWAPW
   549  		if v.Op == ssa.OpRISCV64LoweredAtomicStore64 {
   550  			as = riscv.AAMOSWAPD
   551  		}
   552  		p := s.Prog(as)
   553  		p.From.Type = obj.TYPE_REG
   554  		p.From.Reg = v.Args[1].Reg()
   555  		p.To.Type = obj.TYPE_MEM
   556  		p.To.Reg = v.Args[0].Reg()
   557  		p.RegTo2 = riscv.REG_ZERO
   558  
   559  	case ssa.OpRISCV64LoweredAtomicAdd32, ssa.OpRISCV64LoweredAtomicAdd64:
   560  		as := riscv.AAMOADDW
   561  		if v.Op == ssa.OpRISCV64LoweredAtomicAdd64 {
   562  			as = riscv.AAMOADDD
   563  		}
   564  		p := s.Prog(as)
   565  		p.From.Type = obj.TYPE_REG
   566  		p.From.Reg = v.Args[1].Reg()
   567  		p.To.Type = obj.TYPE_MEM
   568  		p.To.Reg = v.Args[0].Reg()
   569  		p.RegTo2 = riscv.REG_TMP
   570  
   571  		p2 := s.Prog(riscv.AADD)
   572  		p2.From.Type = obj.TYPE_REG
   573  		p2.From.Reg = riscv.REG_TMP
   574  		p2.Reg = v.Args[1].Reg()
   575  		p2.To.Type = obj.TYPE_REG
   576  		p2.To.Reg = v.Reg0()
   577  
   578  	case ssa.OpRISCV64LoweredAtomicExchange32, ssa.OpRISCV64LoweredAtomicExchange64:
   579  		as := riscv.AAMOSWAPW
   580  		if v.Op == ssa.OpRISCV64LoweredAtomicExchange64 {
   581  			as = riscv.AAMOSWAPD
   582  		}
   583  		p := s.Prog(as)
   584  		p.From.Type = obj.TYPE_REG
   585  		p.From.Reg = v.Args[1].Reg()
   586  		p.To.Type = obj.TYPE_MEM
   587  		p.To.Reg = v.Args[0].Reg()
   588  		p.RegTo2 = v.Reg0()
   589  
   590  	case ssa.OpRISCV64LoweredAtomicCas32, ssa.OpRISCV64LoweredAtomicCas64:
   591  		// MOV  ZERO, Rout
   592  		// LR	(Rarg0), Rtmp
   593  		// BNE	Rtmp, Rarg1, 3(PC)
   594  		// SC	Rarg2, (Rarg0), Rtmp
   595  		// BNE	Rtmp, ZERO, -3(PC)
   596  		// MOV	$1, Rout
   597  
   598  		lr := riscv.ALRW
   599  		sc := riscv.ASCW
   600  		if v.Op == ssa.OpRISCV64LoweredAtomicCas64 {
   601  			lr = riscv.ALRD
   602  			sc = riscv.ASCD
   603  		}
   604  
   605  		r0 := v.Args[0].Reg()
   606  		r1 := v.Args[1].Reg()
   607  		r2 := v.Args[2].Reg()
   608  		out := v.Reg0()
   609  
   610  		p := s.Prog(riscv.AMOV)
   611  		p.From.Type = obj.TYPE_REG
   612  		p.From.Reg = riscv.REG_ZERO
   613  		p.To.Type = obj.TYPE_REG
   614  		p.To.Reg = out
   615  
   616  		p1 := s.Prog(lr)
   617  		p1.From.Type = obj.TYPE_MEM
   618  		p1.From.Reg = r0
   619  		p1.To.Type = obj.TYPE_REG
   620  		p1.To.Reg = riscv.REG_TMP
   621  
   622  		p2 := s.Prog(riscv.ABNE)
   623  		p2.From.Type = obj.TYPE_REG
   624  		p2.From.Reg = r1
   625  		p2.Reg = riscv.REG_TMP
   626  		p2.To.Type = obj.TYPE_BRANCH
   627  
   628  		p3 := s.Prog(sc)
   629  		p3.From.Type = obj.TYPE_REG
   630  		p3.From.Reg = r2
   631  		p3.To.Type = obj.TYPE_MEM
   632  		p3.To.Reg = r0
   633  		p3.RegTo2 = riscv.REG_TMP
   634  
   635  		p4 := s.Prog(riscv.ABNE)
   636  		p4.From.Type = obj.TYPE_REG
   637  		p4.From.Reg = riscv.REG_TMP
   638  		p4.Reg = riscv.REG_ZERO
   639  		p4.To.Type = obj.TYPE_BRANCH
   640  		p4.To.SetTarget(p1)
   641  
   642  		p5 := s.Prog(riscv.AMOV)
   643  		p5.From.Type = obj.TYPE_CONST
   644  		p5.From.Offset = 1
   645  		p5.To.Type = obj.TYPE_REG
   646  		p5.To.Reg = out
   647  
   648  		p6 := s.Prog(obj.ANOP)
   649  		p2.To.SetTarget(p6)
   650  
   651  	case ssa.OpRISCV64LoweredAtomicAnd32, ssa.OpRISCV64LoweredAtomicOr32:
   652  		p := s.Prog(v.Op.Asm())
   653  		p.From.Type = obj.TYPE_REG
   654  		p.From.Reg = v.Args[1].Reg()
   655  		p.To.Type = obj.TYPE_MEM
   656  		p.To.Reg = v.Args[0].Reg()
   657  		p.RegTo2 = riscv.REG_ZERO
   658  
   659  	case ssa.OpRISCV64LoweredZero:
   660  		mov, sz := largestMove(v.AuxInt)
   661  
   662  		//	mov	ZERO, (Rarg0)
   663  		//	ADD	$sz, Rarg0
   664  		//	BGEU	Rarg1, Rarg0, -2(PC)
   665  
   666  		p := s.Prog(mov)
   667  		p.From.Type = obj.TYPE_REG
   668  		p.From.Reg = riscv.REG_ZERO
   669  		p.To.Type = obj.TYPE_MEM
   670  		p.To.Reg = v.Args[0].Reg()
   671  
   672  		p2 := s.Prog(riscv.AADD)
   673  		p2.From.Type = obj.TYPE_CONST
   674  		p2.From.Offset = sz
   675  		p2.To.Type = obj.TYPE_REG
   676  		p2.To.Reg = v.Args[0].Reg()
   677  
   678  		p3 := s.Prog(riscv.ABGEU)
   679  		p3.To.Type = obj.TYPE_BRANCH
   680  		p3.Reg = v.Args[0].Reg()
   681  		p3.From.Type = obj.TYPE_REG
   682  		p3.From.Reg = v.Args[1].Reg()
   683  		p3.To.SetTarget(p)
   684  
   685  	case ssa.OpRISCV64LoweredMove:
   686  		mov, sz := largestMove(v.AuxInt)
   687  
   688  		//	mov	(Rarg1), T2
   689  		//	mov	T2, (Rarg0)
   690  		//	ADD	$sz, Rarg0
   691  		//	ADD	$sz, Rarg1
   692  		//	BGEU	Rarg2, Rarg0, -4(PC)
   693  
   694  		p := s.Prog(mov)
   695  		p.From.Type = obj.TYPE_MEM
   696  		p.From.Reg = v.Args[1].Reg()
   697  		p.To.Type = obj.TYPE_REG
   698  		p.To.Reg = riscv.REG_T2
   699  
   700  		p2 := s.Prog(mov)
   701  		p2.From.Type = obj.TYPE_REG
   702  		p2.From.Reg = riscv.REG_T2
   703  		p2.To.Type = obj.TYPE_MEM
   704  		p2.To.Reg = v.Args[0].Reg()
   705  
   706  		p3 := s.Prog(riscv.AADD)
   707  		p3.From.Type = obj.TYPE_CONST
   708  		p3.From.Offset = sz
   709  		p3.To.Type = obj.TYPE_REG
   710  		p3.To.Reg = v.Args[0].Reg()
   711  
   712  		p4 := s.Prog(riscv.AADD)
   713  		p4.From.Type = obj.TYPE_CONST
   714  		p4.From.Offset = sz
   715  		p4.To.Type = obj.TYPE_REG
   716  		p4.To.Reg = v.Args[1].Reg()
   717  
   718  		p5 := s.Prog(riscv.ABGEU)
   719  		p5.To.Type = obj.TYPE_BRANCH
   720  		p5.Reg = v.Args[1].Reg()
   721  		p5.From.Type = obj.TYPE_REG
   722  		p5.From.Reg = v.Args[2].Reg()
   723  		p5.To.SetTarget(p)
   724  
   725  	case ssa.OpRISCV64LoweredNilCheck:
   726  		// Issue a load which will fault if arg is nil.
   727  		p := s.Prog(riscv.AMOVB)
   728  		p.From.Type = obj.TYPE_MEM
   729  		p.From.Reg = v.Args[0].Reg()
   730  		ssagen.AddAux(&p.From, v)
   731  		p.To.Type = obj.TYPE_REG
   732  		p.To.Reg = riscv.REG_ZERO
   733  		if logopt.Enabled() {
   734  			logopt.LogOpt(v.Pos, "nilcheck", "genssa", v.Block.Func.Name)
   735  		}
   736  		if base.Debug.Nil != 0 && v.Pos.Line() > 1 { // v.Pos == 1 in generated wrappers
   737  			base.WarnfAt(v.Pos, "generated nil check")
   738  		}
   739  
   740  	case ssa.OpRISCV64LoweredGetClosurePtr:
   741  		// Closure pointer is S10 (riscv.REG_CTXT).
   742  		ssagen.CheckLoweredGetClosurePtr(v)
   743  
   744  	case ssa.OpRISCV64LoweredGetCallerSP:
   745  		// caller's SP is FixedFrameSize below the address of the first arg
   746  		p := s.Prog(riscv.AMOV)
   747  		p.From.Type = obj.TYPE_ADDR
   748  		p.From.Offset = -base.Ctxt.Arch.FixedFrameSize
   749  		p.From.Name = obj.NAME_PARAM
   750  		p.To.Type = obj.TYPE_REG
   751  		p.To.Reg = v.Reg()
   752  
   753  	case ssa.OpRISCV64LoweredGetCallerPC:
   754  		p := s.Prog(obj.AGETCALLERPC)
   755  		p.To.Type = obj.TYPE_REG
   756  		p.To.Reg = v.Reg()
   757  
   758  	case ssa.OpRISCV64DUFFZERO:
   759  		p := s.Prog(obj.ADUFFZERO)
   760  		p.To.Type = obj.TYPE_MEM
   761  		p.To.Name = obj.NAME_EXTERN
   762  		p.To.Sym = ir.Syms.Duffzero
   763  		p.To.Offset = v.AuxInt
   764  
   765  	case ssa.OpRISCV64DUFFCOPY:
   766  		p := s.Prog(obj.ADUFFCOPY)
   767  		p.To.Type = obj.TYPE_MEM
   768  		p.To.Name = obj.NAME_EXTERN
   769  		p.To.Sym = ir.Syms.Duffcopy
   770  		p.To.Offset = v.AuxInt
   771  
   772  	case ssa.OpRISCV64LoweredPubBarrier:
   773  		// FENCE
   774  		s.Prog(v.Op.Asm())
   775  
   776  	case ssa.OpRISCV64LoweredRound32F, ssa.OpRISCV64LoweredRound64F:
   777  		// input is already rounded
   778  
   779  	case ssa.OpClobber, ssa.OpClobberReg:
   780  		// TODO: implement for clobberdead experiment. Nop is ok for now.
   781  
   782  	default:
   783  		v.Fatalf("Unhandled op %v", v.Op)
   784  	}
   785  }
   786  
   787  var blockBranch = [...]obj.As{
   788  	ssa.BlockRISCV64BEQ:  riscv.ABEQ,
   789  	ssa.BlockRISCV64BEQZ: riscv.ABEQZ,
   790  	ssa.BlockRISCV64BGE:  riscv.ABGE,
   791  	ssa.BlockRISCV64BGEU: riscv.ABGEU,
   792  	ssa.BlockRISCV64BGEZ: riscv.ABGEZ,
   793  	ssa.BlockRISCV64BGTZ: riscv.ABGTZ,
   794  	ssa.BlockRISCV64BLEZ: riscv.ABLEZ,
   795  	ssa.BlockRISCV64BLT:  riscv.ABLT,
   796  	ssa.BlockRISCV64BLTU: riscv.ABLTU,
   797  	ssa.BlockRISCV64BLTZ: riscv.ABLTZ,
   798  	ssa.BlockRISCV64BNE:  riscv.ABNE,
   799  	ssa.BlockRISCV64BNEZ: riscv.ABNEZ,
   800  }
   801  
   802  func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
   803  	s.SetPos(b.Pos)
   804  
   805  	switch b.Kind {
   806  	case ssa.BlockPlain, ssa.BlockDefer:
   807  		if b.Succs[0].Block() != next {
   808  			p := s.Prog(obj.AJMP)
   809  			p.To.Type = obj.TYPE_BRANCH
   810  			s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
   811  		}
   812  	case ssa.BlockExit, ssa.BlockRetJmp:
   813  	case ssa.BlockRet:
   814  		s.Prog(obj.ARET)
   815  	case ssa.BlockRISCV64BEQ, ssa.BlockRISCV64BEQZ, ssa.BlockRISCV64BNE, ssa.BlockRISCV64BNEZ,
   816  		ssa.BlockRISCV64BLT, ssa.BlockRISCV64BLEZ, ssa.BlockRISCV64BGE, ssa.BlockRISCV64BGEZ,
   817  		ssa.BlockRISCV64BLTZ, ssa.BlockRISCV64BGTZ, ssa.BlockRISCV64BLTU, ssa.BlockRISCV64BGEU:
   818  
   819  		as := blockBranch[b.Kind]
   820  		invAs := riscv.InvertBranch(as)
   821  
   822  		var p *obj.Prog
   823  		switch next {
   824  		case b.Succs[0].Block():
   825  			p = s.Br(invAs, b.Succs[1].Block())
   826  		case b.Succs[1].Block():
   827  			p = s.Br(as, b.Succs[0].Block())
   828  		default:
   829  			if b.Likely != ssa.BranchUnlikely {
   830  				p = s.Br(as, b.Succs[0].Block())
   831  				s.Br(obj.AJMP, b.Succs[1].Block())
   832  			} else {
   833  				p = s.Br(invAs, b.Succs[1].Block())
   834  				s.Br(obj.AJMP, b.Succs[0].Block())
   835  			}
   836  		}
   837  
   838  		p.From.Type = obj.TYPE_REG
   839  		switch b.Kind {
   840  		case ssa.BlockRISCV64BEQ, ssa.BlockRISCV64BNE, ssa.BlockRISCV64BLT, ssa.BlockRISCV64BGE, ssa.BlockRISCV64BLTU, ssa.BlockRISCV64BGEU:
   841  			if b.NumControls() != 2 {
   842  				b.Fatalf("Unexpected number of controls (%d != 2): %s", b.NumControls(), b.LongString())
   843  			}
   844  			p.From.Reg = b.Controls[0].Reg()
   845  			p.Reg = b.Controls[1].Reg()
   846  
   847  		case ssa.BlockRISCV64BEQZ, ssa.BlockRISCV64BNEZ, ssa.BlockRISCV64BGEZ, ssa.BlockRISCV64BLEZ, ssa.BlockRISCV64BLTZ, ssa.BlockRISCV64BGTZ:
   848  			if b.NumControls() != 1 {
   849  				b.Fatalf("Unexpected number of controls (%d != 1): %s", b.NumControls(), b.LongString())
   850  			}
   851  			p.From.Reg = b.Controls[0].Reg()
   852  		}
   853  
   854  	default:
   855  		b.Fatalf("Unhandled block: %s", b.LongString())
   856  	}
   857  }
   858  
   859  func loadRegResult(s *ssagen.State, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog {
   860  	p := s.Prog(loadByType(t))
   861  	p.From.Type = obj.TYPE_MEM
   862  	p.From.Name = obj.NAME_AUTO
   863  	p.From.Sym = n.Linksym()
   864  	p.From.Offset = n.FrameOffset() + off
   865  	p.To.Type = obj.TYPE_REG
   866  	p.To.Reg = reg
   867  	return p
   868  }
   869  
   870  func spillArgReg(pp *objw.Progs, p *obj.Prog, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog {
   871  	p = pp.Append(p, storeByType(t), obj.TYPE_REG, reg, 0, obj.TYPE_MEM, 0, n.FrameOffset()+off)
   872  	p.To.Name = obj.NAME_PARAM
   873  	p.To.Sym = n.Linksym()
   874  	p.Pos = p.Pos.WithNotStmt()
   875  	return p
   876  }
   877  

View as plain text