1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package riscv
22
23 import (
24 "github.com/twitchyliquid64/golang-asm/obj"
25 "github.com/twitchyliquid64/golang-asm/objabi"
26 "github.com/twitchyliquid64/golang-asm/sys"
27 "fmt"
28 )
29
30 func buildop(ctxt *obj.Link) {}
31
32
33
34
35 func jalrToSym(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, lr int16) *obj.Prog {
36 if p.As != obj.ACALL && p.As != obj.AJMP && p.As != obj.ARET {
37 ctxt.Diag("unexpected Prog in jalrToSym: %v", p)
38 return p
39 }
40
41
42
43
44
45
46
47 to := p.To
48
49 p.As = AAUIPC
50 p.Mark |= NEED_PCREL_ITYPE_RELOC
51 p.RestArgs = []obj.Addr{obj.Addr{Type: obj.TYPE_CONST, Offset: to.Offset, Sym: to.Sym}}
52 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
53 p.Reg = 0
54 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
55 p = obj.Appendp(p, newprog)
56
57
58 p.As = AJALR
59 p.From.Type = obj.TYPE_REG
60 p.From.Reg = lr
61 p.Reg = 0
62 p.To.Type = obj.TYPE_REG
63 p.To.Reg = REG_TMP
64 p.To.Sym = to.Sym
65
66 return p
67 }
68
69
70
71 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
72
73
74 if p.Reg == 0 {
75 switch p.As {
76 case AADDI, ASLTI, ASLTIU, AANDI, AORI, AXORI, ASLLI, ASRLI, ASRAI,
77 AADD, AAND, AOR, AXOR, ASLL, ASRL, ASUB, ASRA,
78 AMUL, AMULH, AMULHU, AMULHSU, AMULW, ADIV, ADIVU, ADIVW, ADIVUW,
79 AREM, AREMU, AREMW, AREMUW:
80 p.Reg = p.To.Reg
81 }
82 }
83
84
85
86 if p.From.Type == obj.TYPE_CONST {
87 switch p.As {
88 case AADD:
89 p.As = AADDI
90 case ASLT:
91 p.As = ASLTI
92 case ASLTU:
93 p.As = ASLTIU
94 case AAND:
95 p.As = AANDI
96 case AOR:
97 p.As = AORI
98 case AXOR:
99 p.As = AXORI
100 case ASLL:
101 p.As = ASLLI
102 case ASRL:
103 p.As = ASRLI
104 case ASRA:
105 p.As = ASRAI
106 }
107 }
108
109 switch p.As {
110 case obj.AJMP:
111
112 p.From.Type = obj.TYPE_REG
113 p.From.Reg = REG_ZERO
114
115 switch p.To.Type {
116 case obj.TYPE_BRANCH:
117 p.As = AJAL
118 case obj.TYPE_MEM:
119 switch p.To.Name {
120 case obj.NAME_NONE:
121 p.As = AJALR
122 case obj.NAME_EXTERN:
123
124 default:
125 ctxt.Diag("unsupported name %d for %v", p.To.Name, p)
126 }
127 default:
128 panic(fmt.Sprintf("unhandled type %+v", p.To.Type))
129 }
130
131 case obj.ACALL:
132 switch p.To.Type {
133 case obj.TYPE_MEM:
134
135 case obj.TYPE_REG:
136 p.As = AJALR
137 p.From.Type = obj.TYPE_REG
138 p.From.Reg = REG_LR
139 default:
140 ctxt.Diag("unknown destination type %+v in CALL: %v", p.To.Type, p)
141 }
142
143 case obj.AUNDEF:
144 p.As = AEBREAK
145
146 case ASCALL:
147
148 p.As = AECALL
149
150 case ASBREAK:
151
152 p.As = AEBREAK
153 }
154 }
155
156
157 func addrToReg(a obj.Addr) int16 {
158 switch a.Name {
159 case obj.NAME_PARAM, obj.NAME_AUTO:
160 return REG_SP
161 }
162 return a.Reg
163 }
164
165
166 func movToLoad(mnemonic obj.As) obj.As {
167 switch mnemonic {
168 case AMOV:
169 return ALD
170 case AMOVB:
171 return ALB
172 case AMOVH:
173 return ALH
174 case AMOVW:
175 return ALW
176 case AMOVBU:
177 return ALBU
178 case AMOVHU:
179 return ALHU
180 case AMOVWU:
181 return ALWU
182 case AMOVF:
183 return AFLW
184 case AMOVD:
185 return AFLD
186 default:
187 panic(fmt.Sprintf("%+v is not a MOV", mnemonic))
188 }
189 }
190
191
192 func movToStore(mnemonic obj.As) obj.As {
193 switch mnemonic {
194 case AMOV:
195 return ASD
196 case AMOVB:
197 return ASB
198 case AMOVH:
199 return ASH
200 case AMOVW:
201 return ASW
202 case AMOVF:
203 return AFSW
204 case AMOVD:
205 return AFSD
206 default:
207 panic(fmt.Sprintf("%+v is not a MOV", mnemonic))
208 }
209 }
210
211
212 func rewriteMOV(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog) {
213 switch p.As {
214 case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
215 default:
216 panic(fmt.Sprintf("%+v is not a MOV pseudo-instruction", p.As))
217 }
218
219 switch p.From.Type {
220 case obj.TYPE_MEM:
221 switch p.From.Name {
222 case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE:
223 if p.To.Type != obj.TYPE_REG {
224 ctxt.Diag("unsupported load at %v", p)
225 }
226 p.As = movToLoad(p.As)
227 p.From.Reg = addrToReg(p.From)
228
229 case obj.NAME_EXTERN, obj.NAME_STATIC:
230
231
232 as := p.As
233 to := p.To
234
235 p.As = AAUIPC
236 p.Mark |= NEED_PCREL_ITYPE_RELOC
237 p.RestArgs = []obj.Addr{obj.Addr{Type: obj.TYPE_CONST, Offset: p.From.Offset, Sym: p.From.Sym}}
238 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
239 p.Reg = 0
240 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: to.Reg}
241 p = obj.Appendp(p, newprog)
242
243 p.As = movToLoad(as)
244 p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: to.Reg, Offset: 0}
245 p.To = to
246
247 default:
248 ctxt.Diag("unsupported name %d for %v", p.From.Name, p)
249 }
250
251 case obj.TYPE_REG:
252 switch p.To.Type {
253 case obj.TYPE_REG:
254 switch p.As {
255 case AMOV:
256 p.As = AADDI
257 p.Reg = p.From.Reg
258 p.From = obj.Addr{Type: obj.TYPE_CONST}
259
260 case AMOVF:
261 p.As = AFSGNJS
262 p.Reg = p.From.Reg
263
264 case AMOVD:
265 p.As = AFSGNJD
266 p.Reg = p.From.Reg
267
268 default:
269 ctxt.Diag("unsupported register-register move at %v", p)
270 }
271
272 case obj.TYPE_MEM:
273 switch p.As {
274 case AMOVBU, AMOVHU, AMOVWU:
275 ctxt.Diag("unsupported unsigned store at %v", p)
276 }
277 switch p.To.Name {
278 case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE:
279 p.As = movToStore(p.As)
280 p.To.Reg = addrToReg(p.To)
281
282 case obj.NAME_EXTERN:
283
284
285 as := p.As
286 from := p.From
287
288 p.As = AAUIPC
289 p.Mark |= NEED_PCREL_STYPE_RELOC
290 p.RestArgs = []obj.Addr{obj.Addr{Type: obj.TYPE_CONST, Offset: p.To.Offset, Sym: p.To.Sym}}
291 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
292 p.Reg = 0
293 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
294 p = obj.Appendp(p, newprog)
295
296 p.As = movToStore(as)
297 p.From = from
298 p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_TMP, Offset: 0}
299
300 default:
301 ctxt.Diag("unsupported name %d for %v", p.From.Name, p)
302 }
303
304 default:
305 ctxt.Diag("unsupported MOV at %v", p)
306 }
307
308 case obj.TYPE_CONST:
309
310
311
312
313
314
315 if p.As != AMOV {
316 ctxt.Diag("unsupported constant load at %v", p)
317 }
318 off := p.From.Offset
319 to := p.To
320
321 low, high, err := Split32BitImmediate(off)
322 if err != nil {
323 ctxt.Diag("%v: constant %d too large: %v", p, off, err)
324 }
325
326
327 needLUI := high != 0
328 if needLUI {
329 p.As = ALUI
330 p.To = to
331
332 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high}
333 p = obj.Appendp(p, newprog)
334 }
335 p.As = AADDIW
336 p.To = to
337 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: low}
338 p.Reg = REG_ZERO
339 if needLUI {
340 p.Reg = to.Reg
341 }
342
343 case obj.TYPE_ADDR:
344 if p.To.Type != obj.TYPE_REG || p.As != AMOV {
345 ctxt.Diag("unsupported addr MOV at %v", p)
346 }
347 switch p.From.Name {
348 case obj.NAME_EXTERN, obj.NAME_STATIC:
349
350
351 to := p.To
352
353 p.As = AAUIPC
354 p.Mark |= NEED_PCREL_ITYPE_RELOC
355 p.RestArgs = []obj.Addr{obj.Addr{Type: obj.TYPE_CONST, Offset: p.From.Offset, Sym: p.From.Sym}}
356 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
357 p.Reg = 0
358 p.To = to
359 p = obj.Appendp(p, newprog)
360
361 p.As = AADDI
362 p.From = obj.Addr{Type: obj.TYPE_CONST}
363 p.Reg = to.Reg
364 p.To = to
365
366 case obj.NAME_PARAM, obj.NAME_AUTO:
367 p.As = AADDI
368 p.Reg = REG_SP
369 p.From.Type = obj.TYPE_CONST
370
371 case obj.NAME_NONE:
372 p.As = AADDI
373 p.Reg = p.From.Reg
374 p.From.Type = obj.TYPE_CONST
375 p.From.Reg = 0
376
377 default:
378 ctxt.Diag("bad addr MOV from name %v at %v", p.From.Name, p)
379 }
380
381 default:
382 ctxt.Diag("unsupported MOV at %v", p)
383 }
384 }
385
386
387 func InvertBranch(as obj.As) obj.As {
388 switch as {
389 case ABEQ:
390 return ABNE
391 case ABEQZ:
392 return ABNEZ
393 case ABGE:
394 return ABLT
395 case ABGEU:
396 return ABLTU
397 case ABGEZ:
398 return ABLTZ
399 case ABGT:
400 return ABLE
401 case ABGTU:
402 return ABLEU
403 case ABGTZ:
404 return ABLEZ
405 case ABLE:
406 return ABGT
407 case ABLEU:
408 return ABGTU
409 case ABLEZ:
410 return ABGTZ
411 case ABLT:
412 return ABGE
413 case ABLTU:
414 return ABGEU
415 case ABLTZ:
416 return ABGEZ
417 case ABNE:
418 return ABEQ
419 case ABNEZ:
420 return ABEQZ
421 default:
422 panic("InvertBranch: not a branch")
423 }
424 }
425
426
427
428 func containsCall(sym *obj.LSym) bool {
429
430 for p := sym.Func.Text; p != nil; p = p.Link {
431 switch p.As {
432 case obj.ACALL:
433 return true
434 case AJAL, AJALR:
435 if p.From.Type == obj.TYPE_REG && p.From.Reg == REG_LR {
436 return true
437 }
438 }
439 }
440
441 return false
442 }
443
444
445
446 func setPCs(p *obj.Prog, pc int64) {
447 for ; p != nil; p = p.Link {
448 p.Pc = pc
449 for _, ins := range instructionsForProg(p) {
450 pc += int64(ins.length())
451 }
452 }
453 }
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482 func stackOffset(a *obj.Addr, stacksize int64) {
483 switch a.Name {
484 case obj.NAME_AUTO:
485
486 a.Offset += stacksize
487 case obj.NAME_PARAM:
488
489 a.Offset += stacksize + 8
490 }
491 }
492
493
494
495
496
497
498
499
500
501 func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
502 if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
503 return
504 }
505
506
507 text := cursym.Func.Text
508 if text.As != obj.ATEXT {
509 ctxt.Diag("preprocess: found symbol that does not start with TEXT directive")
510 return
511 }
512
513 stacksize := text.To.Offset
514 if stacksize == -8 {
515
516 text.From.Sym.Set(obj.AttrNoFrame, true)
517 stacksize = 0
518 }
519 if stacksize < 0 {
520 ctxt.Diag("negative frame size %d - did you mean NOFRAME?", stacksize)
521 }
522 if text.From.Sym.NoFrame() {
523 if stacksize != 0 {
524 ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", stacksize)
525 }
526 }
527
528 if !containsCall(cursym) {
529 text.From.Sym.Set(obj.AttrLeaf, true)
530 if stacksize == 0 {
531
532 text.From.Sym.Set(obj.AttrNoFrame, true)
533 }
534 }
535
536
537 if !text.From.Sym.NoFrame() {
538 stacksize += ctxt.FixedFrameSize()
539 }
540
541 cursym.Func.Args = text.To.Val.(int32)
542 cursym.Func.Locals = int32(stacksize)
543
544 prologue := text
545
546 if !cursym.Func.Text.From.Sym.NoSplit() {
547 prologue = stacksplit(ctxt, prologue, cursym, newprog, stacksize)
548 }
549
550 if stacksize != 0 {
551 prologue = ctxt.StartUnsafePoint(prologue, newprog)
552
553
554 prologue = obj.Appendp(prologue, newprog)
555 prologue.As = AMOV
556 prologue.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
557 prologue.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: -stacksize}
558
559
560 prologue = obj.Appendp(prologue, newprog)
561 prologue.As = AADDI
562 prologue.From = obj.Addr{Type: obj.TYPE_CONST, Offset: -stacksize}
563 prologue.Reg = REG_SP
564 prologue.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_SP}
565 prologue.Spadj = int32(stacksize)
566
567 prologue = ctxt.EndUnsafePoint(prologue, newprog, -1)
568 }
569
570 if cursym.Func.Text.From.Sym.Wrapper() {
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588 ldpanic := obj.Appendp(prologue, newprog)
589
590 ldpanic.As = AMOV
591 ldpanic.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REGG, Offset: 4 * int64(ctxt.Arch.PtrSize)}
592 ldpanic.Reg = 0
593 ldpanic.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X11}
594
595 bneadj := obj.Appendp(ldpanic, newprog)
596 bneadj.As = ABNE
597 bneadj.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X11}
598 bneadj.Reg = REG_ZERO
599 bneadj.To.Type = obj.TYPE_BRANCH
600
601 endadj := obj.Appendp(bneadj, newprog)
602 endadj.As = obj.ANOP
603
604 last := endadj
605 for last.Link != nil {
606 last = last.Link
607 }
608
609 getargp := obj.Appendp(last, newprog)
610 getargp.As = AMOV
611 getargp.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_X11, Offset: 0}
612 getargp.Reg = 0
613 getargp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X12}
614
615 bneadj.To.SetTarget(getargp)
616
617 calcargp := obj.Appendp(getargp, newprog)
618 calcargp.As = AADDI
619 calcargp.From = obj.Addr{Type: obj.TYPE_CONST, Offset: stacksize + ctxt.FixedFrameSize()}
620 calcargp.Reg = REG_SP
621 calcargp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X13}
622
623 testargp := obj.Appendp(calcargp, newprog)
624 testargp.As = ABNE
625 testargp.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X12}
626 testargp.Reg = REG_X13
627 testargp.To.Type = obj.TYPE_BRANCH
628 testargp.To.SetTarget(endadj)
629
630 adjargp := obj.Appendp(testargp, newprog)
631 adjargp.As = AADDI
632 adjargp.From = obj.Addr{Type: obj.TYPE_CONST, Offset: int64(ctxt.Arch.PtrSize)}
633 adjargp.Reg = REG_SP
634 adjargp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X12}
635
636 setargp := obj.Appendp(adjargp, newprog)
637 setargp.As = AMOV
638 setargp.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X12}
639 setargp.Reg = 0
640 setargp.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_X11, Offset: 0}
641
642 godone := obj.Appendp(setargp, newprog)
643 godone.As = AJAL
644 godone.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
645 godone.To.Type = obj.TYPE_BRANCH
646 godone.To.SetTarget(endadj)
647 }
648
649
650 for p := cursym.Func.Text; p != nil; p = p.Link {
651 stackOffset(&p.From, stacksize)
652 stackOffset(&p.To, stacksize)
653 }
654
655
656 for p := cursym.Func.Text; p != nil; p = p.Link {
657 switch p.As {
658 case obj.AGETCALLERPC:
659 if cursym.Leaf() {
660
661 p.As = AMOV
662 p.From.Type = obj.TYPE_REG
663 p.From.Reg = REG_LR
664 } else {
665
666 p.As = AMOV
667 p.From.Type = obj.TYPE_MEM
668 p.From.Reg = REG_SP
669 }
670
671 case obj.ACALL:
672 switch p.To.Type {
673 case obj.TYPE_MEM:
674 jalrToSym(ctxt, p, newprog, REG_LR)
675 }
676
677 case obj.AJMP:
678 switch p.To.Type {
679 case obj.TYPE_MEM:
680 switch p.To.Name {
681 case obj.NAME_EXTERN:
682
683 jalrToSym(ctxt, p, newprog, REG_ZERO)
684 }
685 }
686
687 case obj.ARET:
688
689 retJMP := p.To.Sym
690
691 if stacksize != 0 {
692
693 p.As = AMOV
694 p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 0}
695 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
696 p = obj.Appendp(p, newprog)
697
698 p.As = AADDI
699 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: stacksize}
700 p.Reg = REG_SP
701 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_SP}
702 p.Spadj = int32(-stacksize)
703 p = obj.Appendp(p, newprog)
704 }
705
706 if retJMP != nil {
707 p.As = obj.ARET
708 p.To.Sym = retJMP
709 p = jalrToSym(ctxt, p, newprog, REG_ZERO)
710 } else {
711 p.As = AJALR
712 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
713 p.Reg = 0
714 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
715 }
716
717
718
719
720
721
722
723 p.Spadj = int32(stacksize)
724
725 case AADDI:
726
727 if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_SP && p.From.Type == obj.TYPE_CONST {
728 p.Spadj = int32(-p.From.Offset)
729 }
730 }
731 }
732
733
734
735
736 for p := cursym.Func.Text; p != nil; p = p.Link {
737 switch p.As {
738 case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
739 rewriteMOV(ctxt, newprog, p)
740 }
741 }
742
743
744 for p := cursym.Func.Text; p != nil; p = p.Link {
745 switch p.As {
746
747 case AADDI, AANDI, AORI, AXORI:
748
749
750
751 q := *p
752 low, high, err := Split32BitImmediate(p.From.Offset)
753 if err != nil {
754 ctxt.Diag("%v: constant %d too large", p, p.From.Offset, err)
755 }
756 if high == 0 {
757 break
758 }
759
760 p.As = ALUI
761 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high}
762 p.Reg = 0
763 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
764 p.Spadj = 0
765 p = obj.Appendp(p, newprog)
766
767 p.As = AADDIW
768 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: low}
769 p.Reg = REG_TMP
770 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
771 p = obj.Appendp(p, newprog)
772
773 switch q.As {
774 case AADDI:
775 p.As = AADD
776 case AANDI:
777 p.As = AAND
778 case AORI:
779 p.As = AOR
780 case AXORI:
781 p.As = AXOR
782 default:
783 ctxt.Diag("unsupported instruction %v for splitting", q)
784 }
785 p.Spadj = q.Spadj
786 p.To = q.To
787 p.Reg = q.Reg
788 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
789
790
791 case ALD, ALB, ALH, ALW, ALBU, ALHU, ALWU, AFLW, AFLD:
792 low, high, err := Split32BitImmediate(p.From.Offset)
793 if err != nil {
794 ctxt.Diag("%v: constant %d too large", p, p.From.Offset)
795 }
796 if high == 0 {
797 break
798 }
799 q := *p
800
801
802
803
804 p.As = ALUI
805 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high}
806 p.Reg = 0
807 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
808 p.Spadj = 0
809 p = obj.Appendp(p, newprog)
810
811 p.As = AADD
812 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
813 p.Reg = q.From.Reg
814 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
815 p = obj.Appendp(p, newprog)
816
817 p.As = q.As
818 p.To = q.To
819 p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_TMP, Offset: low}
820 p.Reg = obj.REG_NONE
821
822
823 case ASD, ASB, ASH, ASW, AFSW, AFSD:
824 low, high, err := Split32BitImmediate(p.To.Offset)
825 if err != nil {
826 ctxt.Diag("%v: constant %d too large", p, p.To.Offset)
827 }
828 if high == 0 {
829 break
830 }
831 q := *p
832
833
834
835
836 p.As = ALUI
837 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high}
838 p.Reg = 0
839 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
840 p.Spadj = 0
841 p = obj.Appendp(p, newprog)
842
843 p.As = AADD
844 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
845 p.Reg = q.To.Reg
846 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
847 p = obj.Appendp(p, newprog)
848
849 p.As = q.As
850 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: q.From.Reg, Offset: 0}
851 p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_TMP, Offset: low}
852 }
853 }
854
855
856
857
858
859 for {
860 rescan := false
861 setPCs(cursym.Func.Text, 0)
862
863 for p := cursym.Func.Text; p != nil; p = p.Link {
864 switch p.As {
865 case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ:
866 if p.To.Type != obj.TYPE_BRANCH {
867 panic("assemble: instruction with branch-like opcode lacks destination")
868 }
869 offset := p.To.Target().Pc - p.Pc
870 if offset < -4096 || 4096 <= offset {
871
872 jmp := obj.Appendp(p, newprog)
873 jmp.As = AJAL
874 jmp.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
875 jmp.To = obj.Addr{Type: obj.TYPE_BRANCH}
876 jmp.To.SetTarget(p.To.Target())
877
878 p.As = InvertBranch(p.As)
879 p.To.SetTarget(jmp.Link)
880
881
882
883 rescan = true
884 }
885 case AJAL:
886 if p.To.Target() == nil {
887 panic("intersymbol jumps should be expressed as AUIPC+JALR")
888 }
889 offset := p.To.Target().Pc - p.Pc
890 if offset < -(1<<20) || (1<<20) <= offset {
891
892
893
894 jmp := obj.Appendp(p, newprog)
895 jmp.As = AJALR
896 jmp.From = p.From
897 jmp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
898
899
900
901 p.As = AAUIPC
902 p.From = obj.Addr{Type: obj.TYPE_BRANCH, Sym: p.From.Sym}
903 p.From.SetTarget(p.To.Target())
904 p.Reg = 0
905 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
906
907 rescan = true
908 }
909 }
910 }
911
912 if !rescan {
913 break
914 }
915 }
916
917
918
919
920 for p := cursym.Func.Text; p != nil; p = p.Link {
921 switch p.As {
922 case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ, AJAL:
923 switch p.To.Type {
924 case obj.TYPE_BRANCH:
925 p.To.Type, p.To.Offset = obj.TYPE_CONST, p.To.Target().Pc-p.Pc
926 case obj.TYPE_MEM:
927 panic("unhandled type")
928 }
929
930 case AAUIPC:
931 if p.From.Type == obj.TYPE_BRANCH {
932 low, high, err := Split32BitImmediate(p.From.Target().Pc - p.Pc)
933 if err != nil {
934 ctxt.Diag("%v: jump displacement %d too large", p, p.To.Target().Pc-p.Pc)
935 }
936 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high, Sym: cursym}
937 p.Link.From.Offset = low
938 }
939 }
940 }
941
942
943 for p := cursym.Func.Text; p != nil; p = p.Link {
944 for _, ins := range instructionsForProg(p) {
945 ins.validate(ctxt)
946 }
947 }
948 }
949
950 func stacksplit(ctxt *obj.Link, p *obj.Prog, cursym *obj.LSym, newprog obj.ProgAlloc, framesize int64) *obj.Prog {
951
952 if framesize == 0 {
953 return p
954 }
955
956
957 p = obj.Appendp(p, newprog)
958 p.As = AMOV
959 p.From.Type = obj.TYPE_MEM
960 p.From.Reg = REGG
961 p.From.Offset = 2 * int64(ctxt.Arch.PtrSize)
962 if cursym.CFunc() {
963 p.From.Offset = 3 * int64(ctxt.Arch.PtrSize)
964 }
965 p.To.Type = obj.TYPE_REG
966 p.To.Reg = REG_X10
967
968 var to_done, to_more *obj.Prog
969
970 if framesize <= objabi.StackSmall {
971
972
973 p = obj.Appendp(p, newprog)
974 p.As = ABLTU
975 p.From.Type = obj.TYPE_REG
976 p.From.Reg = REG_X10
977 p.Reg = REG_SP
978 p.To.Type = obj.TYPE_BRANCH
979 to_done = p
980 } else if framesize <= objabi.StackBig {
981
982
983
984 p = obj.Appendp(p, newprog)
985
986 p.As = AADDI
987 p.From.Type = obj.TYPE_CONST
988 p.From.Offset = -(int64(framesize) - objabi.StackSmall)
989 p.Reg = REG_SP
990 p.To.Type = obj.TYPE_REG
991 p.To.Reg = REG_X11
992
993 p = obj.Appendp(p, newprog)
994 p.As = ABLTU
995 p.From.Type = obj.TYPE_REG
996 p.From.Reg = REG_X10
997 p.Reg = REG_X11
998 p.To.Type = obj.TYPE_BRANCH
999 to_done = p
1000 } else {
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016 p = obj.Appendp(p, newprog)
1017 p.As = AMOV
1018 p.From.Type = obj.TYPE_CONST
1019 p.From.Offset = objabi.StackPreempt
1020 p.To.Type = obj.TYPE_REG
1021 p.To.Reg = REG_X11
1022
1023 p = obj.Appendp(p, newprog)
1024 to_more = p
1025 p.As = ABEQ
1026 p.From.Type = obj.TYPE_REG
1027 p.From.Reg = REG_X10
1028 p.Reg = REG_X11
1029 p.To.Type = obj.TYPE_BRANCH
1030
1031 p = obj.Appendp(p, newprog)
1032 p.As = AADDI
1033 p.From.Type = obj.TYPE_CONST
1034 p.From.Offset = int64(objabi.StackGuard)
1035 p.Reg = REG_SP
1036 p.To.Type = obj.TYPE_REG
1037 p.To.Reg = REG_X11
1038
1039 p = obj.Appendp(p, newprog)
1040 p.As = ASUB
1041 p.From.Type = obj.TYPE_REG
1042 p.From.Reg = REG_X10
1043 p.Reg = REG_X11
1044 p.To.Type = obj.TYPE_REG
1045 p.To.Reg = REG_X11
1046
1047 p = obj.Appendp(p, newprog)
1048 p.As = AMOV
1049 p.From.Type = obj.TYPE_CONST
1050 p.From.Offset = int64(framesize) + int64(objabi.StackGuard) - objabi.StackSmall
1051 p.To.Type = obj.TYPE_REG
1052 p.To.Reg = REG_X10
1053
1054 p = obj.Appendp(p, newprog)
1055 p.As = ABLTU
1056 p.From.Type = obj.TYPE_REG
1057 p.From.Reg = REG_X10
1058 p.Reg = REG_X11
1059 p.To.Type = obj.TYPE_BRANCH
1060 to_done = p
1061 }
1062
1063 p = ctxt.EmitEntryLiveness(cursym, p, newprog)
1064
1065
1066 p = obj.Appendp(p, newprog)
1067 p.As = obj.ACALL
1068 p.To.Type = obj.TYPE_BRANCH
1069 if cursym.CFunc() {
1070 p.To.Sym = ctxt.Lookup("runtime.morestackc")
1071 } else if !cursym.Func.Text.From.Sym.NeedCtxt() {
1072 p.To.Sym = ctxt.Lookup("runtime.morestack_noctxt")
1073 } else {
1074 p.To.Sym = ctxt.Lookup("runtime.morestack")
1075 }
1076 if to_more != nil {
1077 to_more.To.SetTarget(p)
1078 }
1079 p = jalrToSym(ctxt, p, newprog, REG_X5)
1080
1081
1082 p = obj.Appendp(p, newprog)
1083 p.As = AJAL
1084 p.To = obj.Addr{Type: obj.TYPE_BRANCH}
1085 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
1086 p.To.SetTarget(cursym.Func.Text.Link)
1087
1088
1089 p = obj.Appendp(p, newprog)
1090 p.As = obj.ANOP
1091 to_done.To.SetTarget(p)
1092
1093 return p
1094 }
1095
1096
1097 func signExtend(val int64, bit uint) int64 {
1098 return val << (64 - bit) >> (64 - bit)
1099 }
1100
1101
1102
1103
1104
1105 func Split32BitImmediate(imm int64) (low, high int64, err error) {
1106 if !immIFits(imm, 32) {
1107 return 0, 0, fmt.Errorf("immediate does not fit in 32-bits: %d", imm)
1108 }
1109
1110
1111 if immIFits(imm, 12) {
1112 return imm, 0, nil
1113 }
1114
1115 high = imm >> 12
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126 if imm&(1<<11) != 0 {
1127 high++
1128 }
1129
1130 low = signExtend(imm, 12)
1131 high = signExtend(high, 20)
1132
1133 return low, high, nil
1134 }
1135
1136 func regVal(r, min, max uint32) uint32 {
1137 if r < min || r > max {
1138 panic(fmt.Sprintf("register out of range, want %d < %d < %d", min, r, max))
1139 }
1140 return r - min
1141 }
1142
1143
1144 func regI(r uint32) uint32 {
1145 return regVal(r, REG_X0, REG_X31)
1146 }
1147
1148
1149 func regF(r uint32) uint32 {
1150 return regVal(r, REG_F0, REG_F31)
1151 }
1152
1153
1154 func regAddr(a obj.Addr, min, max uint32) uint32 {
1155 if a.Type != obj.TYPE_REG {
1156 panic(fmt.Sprintf("ill typed: %+v", a))
1157 }
1158 return regVal(uint32(a.Reg), min, max)
1159 }
1160
1161
1162 func regIAddr(a obj.Addr) uint32 {
1163 return regAddr(a, REG_X0, REG_X31)
1164 }
1165
1166
1167 func regFAddr(a obj.Addr) uint32 {
1168 return regAddr(a, REG_F0, REG_F31)
1169 }
1170
1171
1172
1173 func immIFits(x int64, nbits uint) bool {
1174 nbits--
1175 var min int64 = -1 << nbits
1176 var max int64 = 1<<nbits - 1
1177 return min <= x && x <= max
1178 }
1179
1180
1181 func immI(as obj.As, imm int64, nbits uint) uint32 {
1182 if !immIFits(imm, nbits) {
1183 panic(fmt.Sprintf("%v\tsigned immediate %d cannot fit in %d bits", as, imm, nbits))
1184 }
1185 return uint32(imm)
1186 }
1187
1188 func wantImmI(ctxt *obj.Link, as obj.As, imm int64, nbits uint) {
1189 if !immIFits(imm, nbits) {
1190 ctxt.Diag("%v\tsigned immediate cannot be larger than %d bits but got %d", as, nbits, imm)
1191 }
1192 }
1193
1194 func wantReg(ctxt *obj.Link, as obj.As, pos string, descr string, r, min, max uint32) {
1195 if r < min || r > max {
1196 var suffix string
1197 if r != obj.REG_NONE {
1198 suffix = fmt.Sprintf(" but got non-%s register %s", descr, RegName(int(r)))
1199 }
1200 ctxt.Diag("%v\texpected %s register in %s position%s", as, descr, pos, suffix)
1201 }
1202 }
1203
1204 func wantNoneReg(ctxt *obj.Link, as obj.As, pos string, r uint32) {
1205 if r != obj.REG_NONE {
1206 ctxt.Diag("%v\texpected no register in %s but got register %s", as, pos, RegName(int(r)))
1207 }
1208 }
1209
1210
1211 func wantIntReg(ctxt *obj.Link, as obj.As, pos string, r uint32) {
1212 wantReg(ctxt, as, pos, "integer", r, REG_X0, REG_X31)
1213 }
1214
1215
1216 func wantFloatReg(ctxt *obj.Link, as obj.As, pos string, r uint32) {
1217 wantReg(ctxt, as, pos, "float", r, REG_F0, REG_F31)
1218 }
1219
1220
1221 func wantEvenOffset(ctxt *obj.Link, as obj.As, offset int64) {
1222 if offset%1 != 0 {
1223 ctxt.Diag("%v\tjump offset %v must be even", as, offset)
1224 }
1225 }
1226
1227 func validateRIII(ctxt *obj.Link, ins *instruction) {
1228 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1229 wantIntReg(ctxt, ins.as, "rs1", ins.rs1)
1230 wantIntReg(ctxt, ins.as, "rs2", ins.rs2)
1231 }
1232
1233 func validateRFFF(ctxt *obj.Link, ins *instruction) {
1234 wantFloatReg(ctxt, ins.as, "rd", ins.rd)
1235 wantFloatReg(ctxt, ins.as, "rs1", ins.rs1)
1236 wantFloatReg(ctxt, ins.as, "rs2", ins.rs2)
1237 }
1238
1239 func validateRFFI(ctxt *obj.Link, ins *instruction) {
1240 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1241 wantFloatReg(ctxt, ins.as, "rs1", ins.rs1)
1242 wantFloatReg(ctxt, ins.as, "rs2", ins.rs2)
1243 }
1244
1245 func validateRFI(ctxt *obj.Link, ins *instruction) {
1246 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1247 wantNoneReg(ctxt, ins.as, "rs1", ins.rs1)
1248 wantFloatReg(ctxt, ins.as, "rs2", ins.rs2)
1249 }
1250
1251 func validateRIF(ctxt *obj.Link, ins *instruction) {
1252 wantFloatReg(ctxt, ins.as, "rd", ins.rd)
1253 wantNoneReg(ctxt, ins.as, "rs1", ins.rs1)
1254 wantIntReg(ctxt, ins.as, "rs2", ins.rs2)
1255 }
1256
1257 func validateRFF(ctxt *obj.Link, ins *instruction) {
1258 wantFloatReg(ctxt, ins.as, "rd", ins.rd)
1259 wantNoneReg(ctxt, ins.as, "rs1", ins.rs1)
1260 wantFloatReg(ctxt, ins.as, "rs2", ins.rs2)
1261 }
1262
1263 func validateII(ctxt *obj.Link, ins *instruction) {
1264 wantImmI(ctxt, ins.as, ins.imm, 12)
1265 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1266 wantIntReg(ctxt, ins.as, "rs1", ins.rs1)
1267 }
1268
1269 func validateIF(ctxt *obj.Link, ins *instruction) {
1270 wantImmI(ctxt, ins.as, ins.imm, 12)
1271 wantFloatReg(ctxt, ins.as, "rd", ins.rd)
1272 wantIntReg(ctxt, ins.as, "rs1", ins.rs1)
1273 }
1274
1275 func validateSI(ctxt *obj.Link, ins *instruction) {
1276 wantImmI(ctxt, ins.as, ins.imm, 12)
1277 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1278 wantIntReg(ctxt, ins.as, "rs1", ins.rs1)
1279 }
1280
1281 func validateSF(ctxt *obj.Link, ins *instruction) {
1282 wantImmI(ctxt, ins.as, ins.imm, 12)
1283 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1284 wantFloatReg(ctxt, ins.as, "rs1", ins.rs1)
1285 }
1286
1287 func validateB(ctxt *obj.Link, ins *instruction) {
1288
1289
1290 wantEvenOffset(ctxt, ins.as, ins.imm)
1291 wantImmI(ctxt, ins.as, ins.imm, 13)
1292 wantNoneReg(ctxt, ins.as, "rd", ins.rd)
1293 wantIntReg(ctxt, ins.as, "rs1", ins.rs1)
1294 wantIntReg(ctxt, ins.as, "rs2", ins.rs2)
1295 }
1296
1297 func validateU(ctxt *obj.Link, ins *instruction) {
1298 wantImmI(ctxt, ins.as, ins.imm, 20)
1299 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1300 wantNoneReg(ctxt, ins.as, "rs1", ins.rs1)
1301 wantNoneReg(ctxt, ins.as, "rs2", ins.rs2)
1302 }
1303
1304 func validateJ(ctxt *obj.Link, ins *instruction) {
1305
1306
1307 wantEvenOffset(ctxt, ins.as, ins.imm)
1308 wantImmI(ctxt, ins.as, ins.imm, 21)
1309 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1310 wantNoneReg(ctxt, ins.as, "rs1", ins.rs1)
1311 wantNoneReg(ctxt, ins.as, "rs2", ins.rs2)
1312 }
1313
1314 func validateRaw(ctxt *obj.Link, ins *instruction) {
1315
1316
1317 if ins.imm < 0 || 1<<32 <= ins.imm {
1318 ctxt.Diag("%v\timmediate in raw position cannot be larger than 32 bits but got %d", ins.as, ins.imm)
1319 }
1320 }
1321
1322
1323 func encodeR(as obj.As, rs1, rs2, rd, funct3, funct7 uint32) uint32 {
1324 enc := encode(as)
1325 if enc == nil {
1326 panic("encodeR: could not encode instruction")
1327 }
1328 if enc.rs2 != 0 && rs2 != 0 {
1329 panic("encodeR: instruction uses rs2, but rs2 was nonzero")
1330 }
1331 return funct7<<25 | enc.funct7<<25 | enc.rs2<<20 | rs2<<20 | rs1<<15 | enc.funct3<<12 | funct3<<12 | rd<<7 | enc.opcode
1332 }
1333
1334 func encodeRIII(ins *instruction) uint32 {
1335 return encodeR(ins.as, regI(ins.rs1), regI(ins.rs2), regI(ins.rd), ins.funct3, ins.funct7)
1336 }
1337
1338 func encodeRFFF(ins *instruction) uint32 {
1339 return encodeR(ins.as, regF(ins.rs1), regF(ins.rs2), regF(ins.rd), ins.funct3, ins.funct7)
1340 }
1341
1342 func encodeRFFI(ins *instruction) uint32 {
1343 return encodeR(ins.as, regF(ins.rs1), regF(ins.rs2), regI(ins.rd), ins.funct3, ins.funct7)
1344 }
1345
1346 func encodeRFI(ins *instruction) uint32 {
1347 return encodeR(ins.as, regF(ins.rs2), 0, regI(ins.rd), ins.funct3, ins.funct7)
1348 }
1349
1350 func encodeRIF(ins *instruction) uint32 {
1351 return encodeR(ins.as, regI(ins.rs2), 0, regF(ins.rd), ins.funct3, ins.funct7)
1352 }
1353
1354 func encodeRFF(ins *instruction) uint32 {
1355 return encodeR(ins.as, regF(ins.rs2), 0, regF(ins.rd), ins.funct3, ins.funct7)
1356 }
1357
1358
1359 func encodeI(as obj.As, rs1, rd, imm uint32) uint32 {
1360 enc := encode(as)
1361 if enc == nil {
1362 panic("encodeI: could not encode instruction")
1363 }
1364 imm |= uint32(enc.csr)
1365 return imm<<20 | rs1<<15 | enc.funct3<<12 | rd<<7 | enc.opcode
1366 }
1367
1368 func encodeII(ins *instruction) uint32 {
1369 return encodeI(ins.as, regI(ins.rs1), regI(ins.rd), uint32(ins.imm))
1370 }
1371
1372 func encodeIF(ins *instruction) uint32 {
1373 return encodeI(ins.as, regI(ins.rs1), regF(ins.rd), uint32(ins.imm))
1374 }
1375
1376
1377 func encodeS(as obj.As, rs1, rs2, imm uint32) uint32 {
1378 enc := encode(as)
1379 if enc == nil {
1380 panic("encodeS: could not encode instruction")
1381 }
1382 return (imm>>5)<<25 | rs2<<20 | rs1<<15 | enc.funct3<<12 | (imm&0x1f)<<7 | enc.opcode
1383 }
1384
1385 func encodeSI(ins *instruction) uint32 {
1386 return encodeS(ins.as, regI(ins.rd), regI(ins.rs1), uint32(ins.imm))
1387 }
1388
1389 func encodeSF(ins *instruction) uint32 {
1390 return encodeS(ins.as, regI(ins.rd), regF(ins.rs1), uint32(ins.imm))
1391 }
1392
1393
1394 func encodeB(ins *instruction) uint32 {
1395 imm := immI(ins.as, ins.imm, 13)
1396 rs2 := regI(ins.rs1)
1397 rs1 := regI(ins.rs2)
1398 enc := encode(ins.as)
1399 if enc == nil {
1400 panic("encodeB: could not encode instruction")
1401 }
1402 return (imm>>12)<<31 | ((imm>>5)&0x3f)<<25 | rs2<<20 | rs1<<15 | enc.funct3<<12 | ((imm>>1)&0xf)<<8 | ((imm>>11)&0x1)<<7 | enc.opcode
1403 }
1404
1405
1406 func encodeU(ins *instruction) uint32 {
1407
1408
1409
1410
1411 imm := immI(ins.as, ins.imm, 20)
1412 rd := regI(ins.rd)
1413 enc := encode(ins.as)
1414 if enc == nil {
1415 panic("encodeU: could not encode instruction")
1416 }
1417 return imm<<12 | rd<<7 | enc.opcode
1418 }
1419
1420
1421 func encodeJ(ins *instruction) uint32 {
1422 imm := immI(ins.as, ins.imm, 21)
1423 rd := regI(ins.rd)
1424 enc := encode(ins.as)
1425 if enc == nil {
1426 panic("encodeJ: could not encode instruction")
1427 }
1428 return (imm>>20)<<31 | ((imm>>1)&0x3ff)<<21 | ((imm>>11)&0x1)<<20 | ((imm>>12)&0xff)<<12 | rd<<7 | enc.opcode
1429 }
1430
1431 func encodeRawIns(ins *instruction) uint32 {
1432
1433
1434 if ins.imm < 0 || 1<<32 <= ins.imm {
1435 panic(fmt.Sprintf("immediate %d cannot fit in 32 bits", ins.imm))
1436 }
1437 return uint32(ins.imm)
1438 }
1439
1440 func EncodeIImmediate(imm int64) (int64, error) {
1441 if !immIFits(imm, 12) {
1442 return 0, fmt.Errorf("immediate %#x does not fit in 12 bits", imm)
1443 }
1444 return imm << 20, nil
1445 }
1446
1447 func EncodeSImmediate(imm int64) (int64, error) {
1448 if !immIFits(imm, 12) {
1449 return 0, fmt.Errorf("immediate %#x does not fit in 12 bits", imm)
1450 }
1451 return ((imm >> 5) << 25) | ((imm & 0x1f) << 7), nil
1452 }
1453
1454 func EncodeUImmediate(imm int64) (int64, error) {
1455 if !immIFits(imm, 20) {
1456 return 0, fmt.Errorf("immediate %#x does not fit in 20 bits", imm)
1457 }
1458 return imm << 12, nil
1459 }
1460
1461 type encoding struct {
1462 encode func(*instruction) uint32
1463 validate func(*obj.Link, *instruction)
1464 length int
1465 }
1466
1467 var (
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479 rIIIEncoding = encoding{encode: encodeRIII, validate: validateRIII, length: 4}
1480 rFFFEncoding = encoding{encode: encodeRFFF, validate: validateRFFF, length: 4}
1481 rFFIEncoding = encoding{encode: encodeRFFI, validate: validateRFFI, length: 4}
1482 rFIEncoding = encoding{encode: encodeRFI, validate: validateRFI, length: 4}
1483 rIFEncoding = encoding{encode: encodeRIF, validate: validateRIF, length: 4}
1484 rFFEncoding = encoding{encode: encodeRFF, validate: validateRFF, length: 4}
1485
1486 iIEncoding = encoding{encode: encodeII, validate: validateII, length: 4}
1487 iFEncoding = encoding{encode: encodeIF, validate: validateIF, length: 4}
1488
1489 sIEncoding = encoding{encode: encodeSI, validate: validateSI, length: 4}
1490 sFEncoding = encoding{encode: encodeSF, validate: validateSF, length: 4}
1491
1492 bEncoding = encoding{encode: encodeB, validate: validateB, length: 4}
1493 uEncoding = encoding{encode: encodeU, validate: validateU, length: 4}
1494 jEncoding = encoding{encode: encodeJ, validate: validateJ, length: 4}
1495
1496
1497 rawEncoding = encoding{encode: encodeRawIns, validate: validateRaw, length: 4}
1498
1499
1500 pseudoOpEncoding = encoding{encode: nil, validate: func(*obj.Link, *instruction) {}, length: 0}
1501
1502
1503
1504 badEncoding = encoding{encode: func(*instruction) uint32 { return 0 }, validate: func(*obj.Link, *instruction) {}, length: 0}
1505 )
1506
1507
1508
1509 var encodings = [ALAST & obj.AMask]encoding{
1510
1511
1512
1513
1514 AADDI & obj.AMask: iIEncoding,
1515 ASLTI & obj.AMask: iIEncoding,
1516 ASLTIU & obj.AMask: iIEncoding,
1517 AANDI & obj.AMask: iIEncoding,
1518 AORI & obj.AMask: iIEncoding,
1519 AXORI & obj.AMask: iIEncoding,
1520 ASLLI & obj.AMask: iIEncoding,
1521 ASRLI & obj.AMask: iIEncoding,
1522 ASRAI & obj.AMask: iIEncoding,
1523 ALUI & obj.AMask: uEncoding,
1524 AAUIPC & obj.AMask: uEncoding,
1525 AADD & obj.AMask: rIIIEncoding,
1526 ASLT & obj.AMask: rIIIEncoding,
1527 ASLTU & obj.AMask: rIIIEncoding,
1528 AAND & obj.AMask: rIIIEncoding,
1529 AOR & obj.AMask: rIIIEncoding,
1530 AXOR & obj.AMask: rIIIEncoding,
1531 ASLL & obj.AMask: rIIIEncoding,
1532 ASRL & obj.AMask: rIIIEncoding,
1533 ASUB & obj.AMask: rIIIEncoding,
1534 ASRA & obj.AMask: rIIIEncoding,
1535
1536
1537 AJAL & obj.AMask: jEncoding,
1538 AJALR & obj.AMask: iIEncoding,
1539 ABEQ & obj.AMask: bEncoding,
1540 ABNE & obj.AMask: bEncoding,
1541 ABLT & obj.AMask: bEncoding,
1542 ABLTU & obj.AMask: bEncoding,
1543 ABGE & obj.AMask: bEncoding,
1544 ABGEU & obj.AMask: bEncoding,
1545
1546
1547 ALW & obj.AMask: iIEncoding,
1548 ALWU & obj.AMask: iIEncoding,
1549 ALH & obj.AMask: iIEncoding,
1550 ALHU & obj.AMask: iIEncoding,
1551 ALB & obj.AMask: iIEncoding,
1552 ALBU & obj.AMask: iIEncoding,
1553 ASW & obj.AMask: sIEncoding,
1554 ASH & obj.AMask: sIEncoding,
1555 ASB & obj.AMask: sIEncoding,
1556
1557
1558 AFENCE & obj.AMask: iIEncoding,
1559
1560
1561 AADDIW & obj.AMask: iIEncoding,
1562 ASLLIW & obj.AMask: iIEncoding,
1563 ASRLIW & obj.AMask: iIEncoding,
1564 ASRAIW & obj.AMask: iIEncoding,
1565 AADDW & obj.AMask: rIIIEncoding,
1566 ASLLW & obj.AMask: rIIIEncoding,
1567 ASRLW & obj.AMask: rIIIEncoding,
1568 ASUBW & obj.AMask: rIIIEncoding,
1569 ASRAW & obj.AMask: rIIIEncoding,
1570
1571
1572 ALD & obj.AMask: iIEncoding,
1573 ASD & obj.AMask: sIEncoding,
1574
1575
1576 AMUL & obj.AMask: rIIIEncoding,
1577 AMULH & obj.AMask: rIIIEncoding,
1578 AMULHU & obj.AMask: rIIIEncoding,
1579 AMULHSU & obj.AMask: rIIIEncoding,
1580 AMULW & obj.AMask: rIIIEncoding,
1581 ADIV & obj.AMask: rIIIEncoding,
1582 ADIVU & obj.AMask: rIIIEncoding,
1583 AREM & obj.AMask: rIIIEncoding,
1584 AREMU & obj.AMask: rIIIEncoding,
1585 ADIVW & obj.AMask: rIIIEncoding,
1586 ADIVUW & obj.AMask: rIIIEncoding,
1587 AREMW & obj.AMask: rIIIEncoding,
1588 AREMUW & obj.AMask: rIIIEncoding,
1589
1590
1591 ALRW & obj.AMask: rIIIEncoding,
1592 ALRD & obj.AMask: rIIIEncoding,
1593 ASCW & obj.AMask: rIIIEncoding,
1594 ASCD & obj.AMask: rIIIEncoding,
1595
1596
1597 AAMOSWAPW & obj.AMask: rIIIEncoding,
1598 AAMOSWAPD & obj.AMask: rIIIEncoding,
1599 AAMOADDW & obj.AMask: rIIIEncoding,
1600 AAMOADDD & obj.AMask: rIIIEncoding,
1601 AAMOANDW & obj.AMask: rIIIEncoding,
1602 AAMOANDD & obj.AMask: rIIIEncoding,
1603 AAMOORW & obj.AMask: rIIIEncoding,
1604 AAMOORD & obj.AMask: rIIIEncoding,
1605 AAMOXORW & obj.AMask: rIIIEncoding,
1606 AAMOXORD & obj.AMask: rIIIEncoding,
1607 AAMOMAXW & obj.AMask: rIIIEncoding,
1608 AAMOMAXD & obj.AMask: rIIIEncoding,
1609 AAMOMAXUW & obj.AMask: rIIIEncoding,
1610 AAMOMAXUD & obj.AMask: rIIIEncoding,
1611 AAMOMINW & obj.AMask: rIIIEncoding,
1612 AAMOMIND & obj.AMask: rIIIEncoding,
1613 AAMOMINUW & obj.AMask: rIIIEncoding,
1614 AAMOMINUD & obj.AMask: rIIIEncoding,
1615
1616
1617 ARDCYCLE & obj.AMask: iIEncoding,
1618 ARDTIME & obj.AMask: iIEncoding,
1619 ARDINSTRET & obj.AMask: iIEncoding,
1620
1621
1622 AFLW & obj.AMask: iFEncoding,
1623 AFSW & obj.AMask: sFEncoding,
1624
1625
1626 AFADDS & obj.AMask: rFFFEncoding,
1627 AFSUBS & obj.AMask: rFFFEncoding,
1628 AFMULS & obj.AMask: rFFFEncoding,
1629 AFDIVS & obj.AMask: rFFFEncoding,
1630 AFMINS & obj.AMask: rFFFEncoding,
1631 AFMAXS & obj.AMask: rFFFEncoding,
1632 AFSQRTS & obj.AMask: rFFFEncoding,
1633
1634
1635 AFCVTWS & obj.AMask: rFIEncoding,
1636 AFCVTLS & obj.AMask: rFIEncoding,
1637 AFCVTSW & obj.AMask: rIFEncoding,
1638 AFCVTSL & obj.AMask: rIFEncoding,
1639 AFCVTWUS & obj.AMask: rFIEncoding,
1640 AFCVTLUS & obj.AMask: rFIEncoding,
1641 AFCVTSWU & obj.AMask: rIFEncoding,
1642 AFCVTSLU & obj.AMask: rIFEncoding,
1643 AFSGNJS & obj.AMask: rFFFEncoding,
1644 AFSGNJNS & obj.AMask: rFFFEncoding,
1645 AFSGNJXS & obj.AMask: rFFFEncoding,
1646 AFMVXS & obj.AMask: rFIEncoding,
1647 AFMVSX & obj.AMask: rIFEncoding,
1648 AFMVXW & obj.AMask: rFIEncoding,
1649 AFMVWX & obj.AMask: rIFEncoding,
1650
1651
1652 AFEQS & obj.AMask: rFFIEncoding,
1653 AFLTS & obj.AMask: rFFIEncoding,
1654 AFLES & obj.AMask: rFFIEncoding,
1655
1656
1657 AFCLASSS & obj.AMask: rFIEncoding,
1658
1659
1660 AFLD & obj.AMask: iFEncoding,
1661 AFSD & obj.AMask: sFEncoding,
1662
1663
1664 AFADDD & obj.AMask: rFFFEncoding,
1665 AFSUBD & obj.AMask: rFFFEncoding,
1666 AFMULD & obj.AMask: rFFFEncoding,
1667 AFDIVD & obj.AMask: rFFFEncoding,
1668 AFMIND & obj.AMask: rFFFEncoding,
1669 AFMAXD & obj.AMask: rFFFEncoding,
1670 AFSQRTD & obj.AMask: rFFFEncoding,
1671
1672
1673 AFCVTWD & obj.AMask: rFIEncoding,
1674 AFCVTLD & obj.AMask: rFIEncoding,
1675 AFCVTDW & obj.AMask: rIFEncoding,
1676 AFCVTDL & obj.AMask: rIFEncoding,
1677 AFCVTWUD & obj.AMask: rFIEncoding,
1678 AFCVTLUD & obj.AMask: rFIEncoding,
1679 AFCVTDWU & obj.AMask: rIFEncoding,
1680 AFCVTDLU & obj.AMask: rIFEncoding,
1681 AFCVTSD & obj.AMask: rFFEncoding,
1682 AFCVTDS & obj.AMask: rFFEncoding,
1683 AFSGNJD & obj.AMask: rFFFEncoding,
1684 AFSGNJND & obj.AMask: rFFFEncoding,
1685 AFSGNJXD & obj.AMask: rFFFEncoding,
1686 AFMVXD & obj.AMask: rFIEncoding,
1687 AFMVDX & obj.AMask: rIFEncoding,
1688
1689
1690 AFEQD & obj.AMask: rFFIEncoding,
1691 AFLTD & obj.AMask: rFFIEncoding,
1692 AFLED & obj.AMask: rFFIEncoding,
1693
1694
1695 AFCLASSD & obj.AMask: rFIEncoding,
1696
1697
1698
1699
1700 AECALL & obj.AMask: iIEncoding,
1701 AEBREAK & obj.AMask: iIEncoding,
1702
1703
1704 AWORD & obj.AMask: rawEncoding,
1705
1706
1707 obj.AFUNCDATA: pseudoOpEncoding,
1708 obj.APCDATA: pseudoOpEncoding,
1709 obj.ATEXT: pseudoOpEncoding,
1710 obj.ANOP: pseudoOpEncoding,
1711 }
1712
1713
1714 func encodingForAs(as obj.As) (encoding, error) {
1715 if base := as &^ obj.AMask; base != obj.ABaseRISCV && base != 0 {
1716 return badEncoding, fmt.Errorf("encodingForAs: not a RISC-V instruction %s", as)
1717 }
1718 asi := as & obj.AMask
1719 if int(asi) >= len(encodings) {
1720 return badEncoding, fmt.Errorf("encodingForAs: bad RISC-V instruction %s", as)
1721 }
1722 enc := encodings[asi]
1723 if enc.validate == nil {
1724 return badEncoding, fmt.Errorf("encodingForAs: no encoding for instruction %s", as)
1725 }
1726 return enc, nil
1727 }
1728
1729 type instruction struct {
1730 as obj.As
1731 rd uint32
1732 rs1 uint32
1733 rs2 uint32
1734 imm int64
1735 funct3 uint32
1736 funct7 uint32
1737 }
1738
1739 func (ins *instruction) encode() (uint32, error) {
1740 enc, err := encodingForAs(ins.as)
1741 if err != nil {
1742 return 0, err
1743 }
1744 if enc.length > 0 {
1745 return enc.encode(ins), nil
1746 }
1747 return 0, fmt.Errorf("fixme")
1748 }
1749
1750 func (ins *instruction) length() int {
1751 enc, err := encodingForAs(ins.as)
1752 if err != nil {
1753 return 0
1754 }
1755 return enc.length
1756 }
1757
1758 func (ins *instruction) validate(ctxt *obj.Link) {
1759 enc, err := encodingForAs(ins.as)
1760 if err != nil {
1761 ctxt.Diag(err.Error())
1762 return
1763 }
1764 enc.validate(ctxt, ins)
1765 }
1766
1767
1768 func instructionsForProg(p *obj.Prog) []*instruction {
1769 ins := &instruction{
1770 as: p.As,
1771 rd: uint32(p.To.Reg),
1772 rs1: uint32(p.Reg),
1773 rs2: uint32(p.From.Reg),
1774 imm: p.From.Offset,
1775 }
1776
1777 inss := []*instruction{ins}
1778 switch ins.as {
1779 case AJAL, AJALR:
1780 ins.rd, ins.rs1, ins.rs2 = uint32(p.From.Reg), uint32(p.To.Reg), obj.REG_NONE
1781 ins.imm = p.To.Offset
1782
1783 case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ:
1784 switch ins.as {
1785 case ABEQZ:
1786 ins.as, ins.rs1, ins.rs2 = ABEQ, REG_ZERO, uint32(p.From.Reg)
1787 case ABGEZ:
1788 ins.as, ins.rs1, ins.rs2 = ABGE, REG_ZERO, uint32(p.From.Reg)
1789 case ABGT:
1790 ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.Reg), uint32(p.From.Reg)
1791 case ABGTU:
1792 ins.as, ins.rs1, ins.rs2 = ABLTU, uint32(p.Reg), uint32(p.From.Reg)
1793 case ABGTZ:
1794 ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), REG_ZERO
1795 case ABLE:
1796 ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.Reg), uint32(p.From.Reg)
1797 case ABLEU:
1798 ins.as, ins.rs1, ins.rs2 = ABGEU, uint32(p.Reg), uint32(p.From.Reg)
1799 case ABLEZ:
1800 ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), REG_ZERO
1801 case ABLTZ:
1802 ins.as, ins.rs1, ins.rs2 = ABLT, REG_ZERO, uint32(p.From.Reg)
1803 case ABNEZ:
1804 ins.as, ins.rs1, ins.rs2 = ABNE, REG_ZERO, uint32(p.From.Reg)
1805 }
1806 ins.imm = p.To.Offset
1807
1808 case ALW, ALWU, ALH, ALHU, ALB, ALBU, ALD, AFLW, AFLD:
1809 if p.From.Type != obj.TYPE_MEM {
1810 p.Ctxt.Diag("%v requires memory for source", p)
1811 return nil
1812 }
1813 ins.rs1, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE
1814 ins.imm = p.From.Offset
1815
1816 case ASW, ASH, ASB, ASD, AFSW, AFSD:
1817 if p.To.Type != obj.TYPE_MEM {
1818 p.Ctxt.Diag("%v requires memory for destination", p)
1819 return nil
1820 }
1821 ins.rs1, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE
1822 ins.imm = p.To.Offset
1823
1824 case ALRW, ALRD:
1825
1826 ins.funct7 = 2
1827 ins.rs1, ins.rs2 = uint32(p.From.Reg), REG_ZERO
1828
1829 case ASCW, ASCD, AAMOSWAPW, AAMOSWAPD, AAMOADDW, AAMOADDD, AAMOANDW, AAMOANDD, AAMOORW, AAMOORD,
1830 AAMOXORW, AAMOXORD, AAMOMINW, AAMOMIND, AAMOMINUW, AAMOMINUD, AAMOMAXW, AAMOMAXD, AAMOMAXUW, AAMOMAXUD:
1831
1832 ins.funct7 = 2
1833 ins.rd, ins.rs1, ins.rs2 = uint32(p.RegTo2), uint32(p.To.Reg), uint32(p.From.Reg)
1834
1835 case AECALL, AEBREAK, ARDCYCLE, ARDTIME, ARDINSTRET:
1836 insEnc := encode(p.As)
1837 if p.To.Type == obj.TYPE_NONE {
1838 ins.rd = REG_ZERO
1839 }
1840 ins.rs1 = REG_ZERO
1841 ins.imm = insEnc.csr
1842
1843 case AFENCE:
1844 ins.rd, ins.rs1, ins.rs2 = REG_ZERO, REG_ZERO, obj.REG_NONE
1845 ins.imm = 0x0ff
1846
1847 case AFCVTWS, AFCVTLS, AFCVTWUS, AFCVTLUS, AFCVTWD, AFCVTLD, AFCVTWUD, AFCVTLUD:
1848
1849 ins.funct3 = 1
1850
1851 case AFNES, AFNED:
1852
1853 if p.To.Type != obj.TYPE_REG {
1854 p.Ctxt.Diag("%v needs an integer register output", ins.as)
1855 return nil
1856 }
1857 if ins.as == AFNES {
1858 ins.as = AFEQS
1859 } else {
1860 ins.as = AFEQD
1861 }
1862 ins = &instruction{
1863 as: AXORI,
1864 rd: ins.rd,
1865 rs1: ins.rd,
1866 imm: 1,
1867 }
1868 inss = append(inss, ins)
1869
1870 case AFSQRTS, AFSQRTD:
1871
1872
1873 ins.rs1 = uint32(p.From.Reg)
1874 ins.rs2 = REG_F0
1875
1876 case ANEG, ANEGW:
1877
1878 ins.as = ASUB
1879 if p.As == ANEGW {
1880 ins.as = ASUBW
1881 }
1882 ins.rs1 = REG_ZERO
1883 if ins.rd == obj.REG_NONE {
1884 ins.rd = ins.rs2
1885 }
1886
1887 case ANOT:
1888
1889 ins.as = AXORI
1890 ins.rs1, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE
1891 if ins.rd == obj.REG_NONE {
1892 ins.rd = ins.rs1
1893 }
1894 ins.imm = -1
1895
1896 case ASEQZ:
1897
1898 ins.as = ASLTIU
1899 ins.rs1 = uint32(p.From.Reg)
1900 ins.imm = 1
1901
1902 case ASNEZ:
1903
1904 ins.as = ASLTU
1905 ins.rs1 = REG_ZERO
1906
1907 case AFNEGS:
1908
1909 ins.as = AFSGNJNS
1910 ins.rs1 = uint32(p.From.Reg)
1911
1912 case AFNEGD:
1913
1914 ins.as = AFSGNJND
1915 ins.rs1 = uint32(p.From.Reg)
1916 }
1917 return inss
1918 }
1919
1920
1921
1922 func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
1923 if ctxt.Retpoline {
1924 ctxt.Diag("-spectre=ret not supported on riscv")
1925 ctxt.Retpoline = false
1926 }
1927
1928 var symcode []uint32
1929 for p := cursym.Func.Text; p != nil; p = p.Link {
1930 switch p.As {
1931 case AJALR:
1932 if p.To.Sym != nil {
1933
1934
1935
1936 rel := obj.Addrel(cursym)
1937 rel.Off = int32(p.Pc)
1938 rel.Siz = 4
1939 rel.Sym = p.To.Sym
1940 rel.Add = p.To.Offset
1941 rel.Type = objabi.R_CALLRISCV
1942 }
1943 case AAUIPC:
1944 var rt objabi.RelocType
1945 if p.Mark&NEED_PCREL_ITYPE_RELOC == NEED_PCREL_ITYPE_RELOC {
1946 rt = objabi.R_RISCV_PCREL_ITYPE
1947 } else if p.Mark&NEED_PCREL_STYPE_RELOC == NEED_PCREL_STYPE_RELOC {
1948 rt = objabi.R_RISCV_PCREL_STYPE
1949 } else {
1950 break
1951 }
1952 if p.Link == nil {
1953 ctxt.Diag("AUIPC needing PC-relative reloc missing following instruction")
1954 break
1955 }
1956 addr := p.RestArgs[0]
1957 if addr.Sym == nil {
1958 ctxt.Diag("AUIPC needing PC-relative reloc missing symbol")
1959 break
1960 }
1961
1962 rel := obj.Addrel(cursym)
1963 rel.Off = int32(p.Pc)
1964 rel.Siz = 8
1965 rel.Sym = addr.Sym
1966 rel.Add = addr.Offset
1967 rel.Type = rt
1968 }
1969
1970 for _, ins := range instructionsForProg(p) {
1971 ic, err := ins.encode()
1972 if err == nil {
1973 symcode = append(symcode, ic)
1974 }
1975 }
1976 }
1977 cursym.Size = int64(4 * len(symcode))
1978
1979 cursym.Grow(cursym.Size)
1980 for p, i := cursym.P, 0; i < len(symcode); p, i = p[4:], i+1 {
1981 ctxt.Arch.ByteOrder.PutUint32(p, symcode[i])
1982 }
1983
1984 obj.MarkUnsafePoints(ctxt, cursym.Func.Text, newprog, isUnsafePoint, nil)
1985 }
1986
1987 func isUnsafePoint(p *obj.Prog) bool {
1988 return p.From.Reg == REG_TMP || p.To.Reg == REG_TMP || p.Reg == REG_TMP
1989 }
1990
1991 var LinkRISCV64 = obj.LinkArch{
1992 Arch: sys.ArchRISCV64,
1993 Init: buildop,
1994 Preprocess: preprocess,
1995 Assemble: assemble,
1996 Progedit: progedit,
1997 UnaryDst: unaryDst,
1998 DWARFRegisters: RISCV64DWARFRegisters,
1999 }
2000
View as plain text