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  		n, align := v.AuxSizeAndAlign()
   776  		mov, sz := largestMove(align)
   777  
   778  		// mov	ZERO, (offset)(Rarg0)
   779  		var off int64
   780  		for n >= sz {
   781  			zeroOp(s, mov, ptr, off)
   782  			off += sz
   783  			n -= sz
   784  		}
   785  
   786  		for i := len(fracMovOps) - 1; i >= 0; i-- {
   787  			tsz := int64(1 << i)
   788  			if n < tsz {
   789  				continue
   790  			}
   791  			zeroOp(s, fracMovOps[i], ptr, off)
   792  			off += tsz
   793  			n -= tsz
   794  		}
   795  
   796  	case ssa.OpRISCV64LoweredZeroLoop:
   797  		ptr := v.Args[0].Reg()
   798  		n, align := v.AuxSizeAndAlign()
   799  		mov, sz := largestMove(align)
   800  		chunk := 8 * sz
   801  
   802  		if n <= 3*chunk {
   803  			v.Fatalf("ZeroLoop too small:%d, expect:%d", n, 3*chunk)
   804  		}
   805  
   806  		tmp := v.RegTmp()
   807  
   808  		if n >= 1<<31 {
   809  			p := s.Prog(riscv.AMOV)
   810  			p.From.Type = obj.TYPE_CONST
   811  			p.From.Offset = n - n%chunk
   812  			p.To.Type = obj.TYPE_REG
   813  			p.To.Reg = tmp
   814  		}
   815  		p := s.Prog(riscv.AADD)
   816  		if n >= 1<<31 {
   817  			p.From.Type = obj.TYPE_REG
   818  			p.From.Reg = tmp
   819  		} else {
   820  			p.From.Type = obj.TYPE_CONST
   821  			p.From.Offset = n - n%chunk
   822  		}
   823  		p.Reg = ptr
   824  		p.To.Type = obj.TYPE_REG
   825  		p.To.Reg = tmp
   826  
   827  		for i := int64(0); i < 8; i++ {
   828  			zeroOp(s, mov, ptr, sz*i)
   829  		}
   830  
   831  		p2 := s.Prog(riscv.AADD)
   832  		p2.From.Type = obj.TYPE_CONST
   833  		p2.From.Offset = chunk
   834  		p2.To.Type = obj.TYPE_REG
   835  		p2.To.Reg = ptr
   836  
   837  		p3 := s.Prog(riscv.ABNE)
   838  		p3.From.Reg = tmp
   839  		p3.From.Type = obj.TYPE_REG
   840  		p3.Reg = ptr
   841  		p3.To.Type = obj.TYPE_BRANCH
   842  		p3.To.SetTarget(p.Link)
   843  
   844  		n %= chunk
   845  
   846  		// mov	ZERO, (offset)(Rarg0)
   847  		var off int64
   848  		for n >= sz {
   849  			zeroOp(s, mov, ptr, off)
   850  			off += sz
   851  			n -= sz
   852  		}
   853  
   854  		for i := len(fracMovOps) - 1; i >= 0; i-- {
   855  			tsz := int64(1 << i)
   856  			if n < tsz {
   857  				continue
   858  			}
   859  			zeroOp(s, fracMovOps[i], ptr, off)
   860  			off += tsz
   861  			n -= tsz
   862  		}
   863  
   864  	case ssa.OpRISCV64LoweredMove:
   865  		dst := v.Args[0].Reg()
   866  		src := v.Args[1].Reg()
   867  		if dst == src {
   868  			break
   869  		}
   870  
   871  		n, align := v.AuxSizeAndAlign()
   872  		mov, sz := largestMove(align)
   873  
   874  		var off int64
   875  		tmp := int16(riscv.REG_X5)
   876  		for n >= sz {
   877  			moveOp(s, mov, dst, src, tmp, off)
   878  			off += sz
   879  			n -= sz
   880  		}
   881  
   882  		for i := len(fracMovOps) - 1; i >= 0; i-- {
   883  			tsz := int64(1 << i)
   884  			if n < tsz {
   885  				continue
   886  			}
   887  			moveOp(s, fracMovOps[i], dst, src, tmp, off)
   888  			off += tsz
   889  			n -= tsz
   890  		}
   891  
   892  	case ssa.OpRISCV64LoweredMoveLoop:
   893  		dst := v.Args[0].Reg()
   894  		src := v.Args[1].Reg()
   895  		if dst == src {
   896  			break
   897  		}
   898  
   899  		n, align := v.AuxSizeAndAlign()
   900  		mov, sz := largestMove(align)
   901  		chunk := 8 * sz
   902  
   903  		if n <= 3*chunk {
   904  			v.Fatalf("MoveLoop too small:%d, expect:%d", n, 3*chunk)
   905  		}
   906  		tmp := int16(riscv.REG_X5)
   907  
   908  		if n >= 1<<31 {
   909  			p := s.Prog(riscv.AMOV)
   910  			p.From.Type = obj.TYPE_CONST
   911  			p.From.Offset = n - n%chunk
   912  			p.To.Type = obj.TYPE_REG
   913  			p.To.Reg = riscv.REG_X6
   914  		}
   915  		p := s.Prog(riscv.AADD)
   916  		if n >= 1<<31 {
   917  			p.From.Type = obj.TYPE_REG
   918  			p.From.Reg = riscv.REG_X6
   919  		} else {
   920  			p.From.Type = obj.TYPE_CONST
   921  			p.From.Offset = n - n%chunk
   922  		}
   923  		p.Reg = src
   924  		p.To.Type = obj.TYPE_REG
   925  		p.To.Reg = riscv.REG_X6
   926  
   927  		for i := int64(0); i < 8; i++ {
   928  			moveOp(s, mov, dst, src, tmp, sz*i)
   929  		}
   930  
   931  		p1 := s.Prog(riscv.AADD)
   932  		p1.From.Type = obj.TYPE_CONST
   933  		p1.From.Offset = chunk
   934  		p1.To.Type = obj.TYPE_REG
   935  		p1.To.Reg = src
   936  
   937  		p2 := s.Prog(riscv.AADD)
   938  		p2.From.Type = obj.TYPE_CONST
   939  		p2.From.Offset = chunk
   940  		p2.To.Type = obj.TYPE_REG
   941  		p2.To.Reg = dst
   942  
   943  		p3 := s.Prog(riscv.ABNE)
   944  		p3.From.Reg = riscv.REG_X6
   945  		p3.From.Type = obj.TYPE_REG
   946  		p3.Reg = src
   947  		p3.To.Type = obj.TYPE_BRANCH
   948  		p3.To.SetTarget(p.Link)
   949  
   950  		n %= chunk
   951  
   952  		var off int64
   953  		for n >= sz {
   954  			moveOp(s, mov, dst, src, tmp, off)
   955  			off += sz
   956  			n -= sz
   957  		}
   958  
   959  		for i := len(fracMovOps) - 1; i >= 0; i-- {
   960  			tsz := int64(1 << i)
   961  			if n < tsz {
   962  				continue
   963  			}
   964  			moveOp(s, fracMovOps[i], dst, src, tmp, off)
   965  			off += tsz
   966  			n -= tsz
   967  		}
   968  
   969  	case ssa.OpRISCV64LoweredNilCheck:
   970  		// Issue a load which will fault if arg is nil.
   971  		p := s.Prog(riscv.AMOVB)
   972  		p.From.Type = obj.TYPE_MEM
   973  		p.From.Reg = v.Args[0].Reg()
   974  		ssagen.AddAux(&p.From, v)
   975  		p.To.Type = obj.TYPE_REG
   976  		p.To.Reg = riscv.REG_ZERO
   977  		if logopt.Enabled() {
   978  			logopt.LogOpt(v.Pos, "nilcheck", "genssa", v.Block.Func.Name)
   979  		}
   980  		if base.Debug.Nil != 0 && v.Pos.Line() > 1 { // v.Pos == 1 in generated wrappers
   981  			base.WarnfAt(v.Pos, "generated nil check")
   982  		}
   983  
   984  	case ssa.OpRISCV64LoweredGetClosurePtr:
   985  		// Closure pointer is S10 (riscv.REG_CTXT).
   986  		ssagen.CheckLoweredGetClosurePtr(v)
   987  
   988  	case ssa.OpRISCV64LoweredGetCallerSP:
   989  		// caller's SP is FixedFrameSize below the address of the first arg
   990  		p := s.Prog(riscv.AMOV)
   991  		p.From.Type = obj.TYPE_ADDR
   992  		p.From.Offset = -base.Ctxt.Arch.FixedFrameSize
   993  		p.From.Name = obj.NAME_PARAM
   994  		p.To.Type = obj.TYPE_REG
   995  		p.To.Reg = v.Reg()
   996  
   997  	case ssa.OpRISCV64LoweredGetCallerPC:
   998  		p := s.Prog(obj.AGETCALLERPC)
   999  		p.To.Type = obj.TYPE_REG
  1000  		p.To.Reg = v.Reg()
  1001  
  1002  	case ssa.OpRISCV64LoweredPubBarrier:
  1003  		// FENCE W, W
  1004  		p := s.Prog(v.Op.Asm())
  1005  		p.From.Type = obj.TYPE_SPECIAL
  1006  		p.From.Offset = int64(riscv.SPOP_FENCE_W)
  1007  		p.To.Type = obj.TYPE_SPECIAL
  1008  		p.To.Offset = int64(riscv.SPOP_FENCE_W)
  1009  
  1010  	case ssa.OpRISCV64LoweredRound32F, ssa.OpRISCV64LoweredRound64F:
  1011  		// input is already rounded
  1012  
  1013  	case ssa.OpClobber, ssa.OpClobberReg:
  1014  		// TODO: implement for clobberdead experiment. Nop is ok for now.
  1015  
  1016  	default:
  1017  		v.Fatalf("Unhandled op %v", v.Op)
  1018  	}
  1019  }
  1020  
  1021  var blockBranch = [...]obj.As{
  1022  	ssa.BlockRISCV64BEQ:  riscv.ABEQ,
  1023  	ssa.BlockRISCV64BEQZ: riscv.ABEQZ,
  1024  	ssa.BlockRISCV64BGE:  riscv.ABGE,
  1025  	ssa.BlockRISCV64BGEU: riscv.ABGEU,
  1026  	ssa.BlockRISCV64BGEZ: riscv.ABGEZ,
  1027  	ssa.BlockRISCV64BGTZ: riscv.ABGTZ,
  1028  	ssa.BlockRISCV64BLEZ: riscv.ABLEZ,
  1029  	ssa.BlockRISCV64BLT:  riscv.ABLT,
  1030  	ssa.BlockRISCV64BLTU: riscv.ABLTU,
  1031  	ssa.BlockRISCV64BLTZ: riscv.ABLTZ,
  1032  	ssa.BlockRISCV64BNE:  riscv.ABNE,
  1033  	ssa.BlockRISCV64BNEZ: riscv.ABNEZ,
  1034  }
  1035  
  1036  func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
  1037  	s.SetPos(b.Pos)
  1038  
  1039  	switch b.Kind {
  1040  	case ssa.BlockPlain, ssa.BlockDefer:
  1041  		if b.Succs[0].Block() != next {
  1042  			p := s.Prog(obj.AJMP)
  1043  			p.To.Type = obj.TYPE_BRANCH
  1044  			s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
  1045  		}
  1046  	case ssa.BlockExit, ssa.BlockRetJmp:
  1047  	case ssa.BlockRet:
  1048  		s.Prog(obj.ARET)
  1049  	case ssa.BlockRISCV64BEQ, ssa.BlockRISCV64BEQZ, ssa.BlockRISCV64BNE, ssa.BlockRISCV64BNEZ,
  1050  		ssa.BlockRISCV64BLT, ssa.BlockRISCV64BLEZ, ssa.BlockRISCV64BGE, ssa.BlockRISCV64BGEZ,
  1051  		ssa.BlockRISCV64BLTZ, ssa.BlockRISCV64BGTZ, ssa.BlockRISCV64BLTU, ssa.BlockRISCV64BGEU:
  1052  
  1053  		as := blockBranch[b.Kind]
  1054  		invAs := riscv.InvertBranch(as)
  1055  
  1056  		var p *obj.Prog
  1057  		switch next {
  1058  		case b.Succs[0].Block():
  1059  			p = s.Br(invAs, b.Succs[1].Block())
  1060  		case b.Succs[1].Block():
  1061  			p = s.Br(as, b.Succs[0].Block())
  1062  		default:
  1063  			if b.Likely != ssa.BranchUnlikely {
  1064  				p = s.Br(as, b.Succs[0].Block())
  1065  				s.Br(obj.AJMP, b.Succs[1].Block())
  1066  			} else {
  1067  				p = s.Br(invAs, b.Succs[1].Block())
  1068  				s.Br(obj.AJMP, b.Succs[0].Block())
  1069  			}
  1070  		}
  1071  
  1072  		p.From.Type = obj.TYPE_REG
  1073  		switch b.Kind {
  1074  		case ssa.BlockRISCV64BEQ, ssa.BlockRISCV64BNE, ssa.BlockRISCV64BLT, ssa.BlockRISCV64BGE, ssa.BlockRISCV64BLTU, ssa.BlockRISCV64BGEU:
  1075  			if b.NumControls() != 2 {
  1076  				b.Fatalf("Unexpected number of controls (%d != 2): %s", b.NumControls(), b.LongString())
  1077  			}
  1078  			p.From.Reg = b.Controls[0].Reg()
  1079  			p.Reg = b.Controls[1].Reg()
  1080  
  1081  		case ssa.BlockRISCV64BEQZ, ssa.BlockRISCV64BNEZ, ssa.BlockRISCV64BGEZ, ssa.BlockRISCV64BLEZ, ssa.BlockRISCV64BLTZ, ssa.BlockRISCV64BGTZ:
  1082  			if b.NumControls() != 1 {
  1083  				b.Fatalf("Unexpected number of controls (%d != 1): %s", b.NumControls(), b.LongString())
  1084  			}
  1085  			p.From.Reg = b.Controls[0].Reg()
  1086  		}
  1087  
  1088  	default:
  1089  		b.Fatalf("Unhandled block: %s", b.LongString())
  1090  	}
  1091  }
  1092  
  1093  func loadRegResult(s *ssagen.State, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog {
  1094  	p := s.Prog(loadByType(t))
  1095  	p.From.Type = obj.TYPE_MEM
  1096  	p.From.Name = obj.NAME_AUTO
  1097  	p.From.Sym = n.Linksym()
  1098  	p.From.Offset = n.FrameOffset() + off
  1099  	p.To.Type = obj.TYPE_REG
  1100  	p.To.Reg = reg
  1101  	return p
  1102  }
  1103  
  1104  func spillArgReg(pp *objw.Progs, p *obj.Prog, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog {
  1105  	p = pp.Append(p, storeByType(t), obj.TYPE_REG, reg, 0, obj.TYPE_MEM, 0, n.FrameOffset()+off)
  1106  	p.To.Name = obj.NAME_PARAM
  1107  	p.To.Sym = n.Linksym()
  1108  	p.Pos = p.Pos.WithNotStmt()
  1109  	return p
  1110  }
  1111  
  1112  func zeroOp(s *ssagen.State, mov obj.As, reg int16, off int64) {
  1113  	p := s.Prog(mov)
  1114  	p.From.Type = obj.TYPE_REG
  1115  	p.From.Reg = riscv.REG_ZERO
  1116  	p.To.Type = obj.TYPE_MEM
  1117  	p.To.Reg = reg
  1118  	p.To.Offset = off
  1119  	return
  1120  }
  1121  
  1122  func moveOp(s *ssagen.State, mov obj.As, dst int16, src int16, tmp int16, off int64) {
  1123  	p := s.Prog(mov)
  1124  	p.From.Type = obj.TYPE_MEM
  1125  	p.From.Reg = src
  1126  	p.From.Offset = off
  1127  	p.To.Type = obj.TYPE_REG
  1128  	p.To.Reg = tmp
  1129  
  1130  	p1 := s.Prog(mov)
  1131  	p1.From.Type = obj.TYPE_REG
  1132  	p1.From.Reg = tmp
  1133  	p1.To.Type = obj.TYPE_MEM
  1134  	p1.To.Reg = dst
  1135  	p1.To.Offset = off
  1136  
  1137  	return
  1138  }
  1139  

View as plain text