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