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