]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/riscv64/ssa.go
cmd/compile: optimize right shifts of int32 on riscv64
[gostls13.git] / 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/objw"
11         "cmd/compile/internal/ssa"
12         "cmd/compile/internal/ssagen"
13         "cmd/compile/internal/types"
14         "cmd/internal/obj"
15         "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 }