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

View as plain text