github.com/bir3/gocompiler@v0.9.2202/src/cmd/compile/internal/riscv64/ssa.go (about)

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