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

View as plain text