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