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