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/src"
27 "cmd/internal/sys"
28 "fmt"
29 "internal/abi"
30 "internal/buildcfg"
31 "log"
32 "math/bits"
33 "strings"
34 )
35
36 func buildop(ctxt *obj.Link) {}
37
38 func jalToSym(ctxt *obj.Link, p *obj.Prog, lr int16) {
39 switch p.As {
40 case obj.ACALL, obj.AJMP, obj.ARET, obj.ADUFFZERO, obj.ADUFFCOPY:
41 default:
42 ctxt.Diag("unexpected Prog in jalToSym: %v", p)
43 return
44 }
45
46 p.As = AJAL
47 p.Mark |= NEED_JAL_RELOC
48 p.From.Type = obj.TYPE_REG
49 p.From.Reg = lr
50 p.Reg = obj.REG_NONE
51 }
52
53
54
55 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
56
57
58 if p.Reg == obj.REG_NONE {
59 switch p.As {
60 case AADDI, ASLTI, ASLTIU, AANDI, AORI, AXORI, ASLLI, ASRLI, ASRAI,
61 AADDIW, ASLLIW, ASRLIW, ASRAIW, AADDW, ASUBW, ASLLW, ASRLW, ASRAW,
62 AADD, AAND, AOR, AXOR, ASLL, ASRL, ASUB, ASRA,
63 AMUL, AMULH, AMULHU, AMULHSU, AMULW, ADIV, ADIVU, ADIVW, ADIVUW,
64 AREM, AREMU, AREMW, AREMUW,
65 AADDUW, ASH1ADD, ASH1ADDUW, ASH2ADD, ASH2ADDUW, ASH3ADD, ASH3ADDUW, ASLLIUW,
66 AANDN, AORN, AXNOR, AMAX, AMAXU, AMIN, AMINU, AROL, AROLW, AROR, ARORW, ARORI, ARORIW,
67 ABCLR, ABCLRI, ABEXT, ABEXTI, ABINV, ABINVI, ABSET, ABSETI:
68 p.Reg = p.To.Reg
69 }
70 }
71
72
73
74 if p.From.Type == obj.TYPE_CONST {
75 switch p.As {
76 case AADD:
77 p.As = AADDI
78 case ASUB:
79 p.As, p.From.Offset = AADDI, -p.From.Offset
80 case ASLT:
81 p.As = ASLTI
82 case ASLTU:
83 p.As = ASLTIU
84 case AAND:
85 p.As = AANDI
86 case AOR:
87 p.As = AORI
88 case AXOR:
89 p.As = AXORI
90 case ASLL:
91 p.As = ASLLI
92 case ASRL:
93 p.As = ASRLI
94 case ASRA:
95 p.As = ASRAI
96 case AADDW:
97 p.As = AADDIW
98 case ASUBW:
99 p.As, p.From.Offset = AADDIW, -p.From.Offset
100 case ASLLW:
101 p.As = ASLLIW
102 case ASRLW:
103 p.As = ASRLIW
104 case ASRAW:
105 p.As = ASRAIW
106 case AROR:
107 p.As = ARORI
108 case ARORW:
109 p.As = ARORIW
110 case ABCLR:
111 p.As = ABCLRI
112 case ABEXT:
113 p.As = ABEXTI
114 case ABINV:
115 p.As = ABINVI
116 case ABSET:
117 p.As = ABSETI
118 }
119 }
120
121 switch p.As {
122 case obj.AJMP:
123
124 p.From.Type = obj.TYPE_REG
125 p.From.Reg = REG_ZERO
126
127 switch p.To.Type {
128 case obj.TYPE_BRANCH:
129 p.As = AJAL
130 case obj.TYPE_MEM:
131 switch p.To.Name {
132 case obj.NAME_NONE:
133 p.As = AJALR
134 case obj.NAME_EXTERN, obj.NAME_STATIC:
135
136 default:
137 ctxt.Diag("unsupported name %d for %v", p.To.Name, p)
138 }
139 default:
140 panic(fmt.Sprintf("unhandled type %+v", p.To.Type))
141 }
142
143 case obj.ACALL:
144 switch p.To.Type {
145 case obj.TYPE_MEM:
146
147 case obj.TYPE_REG:
148 p.As = AJALR
149 p.From.Type = obj.TYPE_REG
150 p.From.Reg = REG_LR
151 default:
152 ctxt.Diag("unknown destination type %+v in CALL: %v", p.To.Type, p)
153 }
154
155 case obj.AUNDEF:
156 p.As = AEBREAK
157
158 case AFMVXS:
159
160 p.As = AFMVXW
161
162 case AFMVSX:
163
164 p.As = AFMVWX
165
166 case ASCALL:
167
168 p.As = AECALL
169
170 case ASBREAK:
171
172 p.As = AEBREAK
173
174 case AMOV:
175 if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == obj.REG_NONE && int64(int32(p.From.Offset)) != p.From.Offset {
176 ctz := bits.TrailingZeros64(uint64(p.From.Offset))
177 val := p.From.Offset >> ctz
178 if int64(int32(val)) == val {
179
180 break
181 }
182
183 p.From.Type = obj.TYPE_MEM
184 p.From.Sym = ctxt.Int64Sym(p.From.Offset)
185 p.From.Name = obj.NAME_EXTERN
186 p.From.Offset = 0
187 }
188 }
189 }
190
191
192 func addrToReg(a obj.Addr) int16 {
193 switch a.Name {
194 case obj.NAME_PARAM, obj.NAME_AUTO:
195 return REG_SP
196 }
197 return a.Reg
198 }
199
200
201 func movToLoad(mnemonic obj.As) obj.As {
202 switch mnemonic {
203 case AMOV:
204 return ALD
205 case AMOVB:
206 return ALB
207 case AMOVH:
208 return ALH
209 case AMOVW:
210 return ALW
211 case AMOVBU:
212 return ALBU
213 case AMOVHU:
214 return ALHU
215 case AMOVWU:
216 return ALWU
217 case AMOVF:
218 return AFLW
219 case AMOVD:
220 return AFLD
221 default:
222 panic(fmt.Sprintf("%+v is not a MOV", mnemonic))
223 }
224 }
225
226
227 func movToStore(mnemonic obj.As) obj.As {
228 switch mnemonic {
229 case AMOV:
230 return ASD
231 case AMOVB:
232 return ASB
233 case AMOVH:
234 return ASH
235 case AMOVW:
236 return ASW
237 case AMOVF:
238 return AFSW
239 case AMOVD:
240 return AFSD
241 default:
242 panic(fmt.Sprintf("%+v is not a MOV", mnemonic))
243 }
244 }
245
246
247
248 func markRelocs(p *obj.Prog) {
249 switch p.As {
250 case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
251 switch {
252 case p.From.Type == obj.TYPE_ADDR && p.To.Type == obj.TYPE_REG:
253 switch p.From.Name {
254 case obj.NAME_EXTERN, obj.NAME_STATIC:
255 p.Mark |= NEED_PCREL_ITYPE_RELOC
256 }
257 case p.From.Type == obj.TYPE_MEM && p.To.Type == obj.TYPE_REG:
258 switch p.From.Name {
259 case obj.NAME_EXTERN, obj.NAME_STATIC:
260 p.Mark |= NEED_PCREL_ITYPE_RELOC
261 }
262 case p.From.Type == obj.TYPE_REG && p.To.Type == obj.TYPE_MEM:
263 switch p.To.Name {
264 case obj.NAME_EXTERN, obj.NAME_STATIC:
265 p.Mark |= NEED_PCREL_STYPE_RELOC
266 }
267 }
268 }
269 }
270
271
272 func InvertBranch(as obj.As) obj.As {
273 switch as {
274 case ABEQ:
275 return ABNE
276 case ABEQZ:
277 return ABNEZ
278 case ABGE:
279 return ABLT
280 case ABGEU:
281 return ABLTU
282 case ABGEZ:
283 return ABLTZ
284 case ABGT:
285 return ABLE
286 case ABGTU:
287 return ABLEU
288 case ABGTZ:
289 return ABLEZ
290 case ABLE:
291 return ABGT
292 case ABLEU:
293 return ABGTU
294 case ABLEZ:
295 return ABGTZ
296 case ABLT:
297 return ABGE
298 case ABLTU:
299 return ABGEU
300 case ABLTZ:
301 return ABGEZ
302 case ABNE:
303 return ABEQ
304 case ABNEZ:
305 return ABEQZ
306 default:
307 panic("InvertBranch: not a branch")
308 }
309 }
310
311
312
313 func containsCall(sym *obj.LSym) bool {
314
315 for p := sym.Func().Text; p != nil; p = p.Link {
316 switch p.As {
317 case obj.ACALL, obj.ADUFFZERO, obj.ADUFFCOPY:
318 return true
319 case AJAL, AJALR:
320 if p.From.Type == obj.TYPE_REG && p.From.Reg == REG_LR {
321 return true
322 }
323 }
324 }
325
326 return false
327 }
328
329
330
331 func setPCs(p *obj.Prog, pc int64) int64 {
332 for ; p != nil; p = p.Link {
333 p.Pc = pc
334 for _, ins := range instructionsForProg(p) {
335 pc += int64(ins.length())
336 }
337
338 if p.As == obj.APCALIGN {
339 alignedValue := p.From.Offset
340 v := pcAlignPadLength(pc, alignedValue)
341 pc += int64(v)
342 }
343 }
344 return pc
345 }
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371 func stackOffset(a *obj.Addr, stacksize int64) {
372 switch a.Name {
373 case obj.NAME_AUTO:
374
375 a.Offset += stacksize
376 case obj.NAME_PARAM:
377
378 a.Offset += stacksize + 8
379 }
380 }
381
382
383
384
385
386
387
388
389
390 func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
391 if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
392 return
393 }
394
395
396 text := cursym.Func().Text
397 if text.As != obj.ATEXT {
398 ctxt.Diag("preprocess: found symbol that does not start with TEXT directive")
399 return
400 }
401
402 stacksize := text.To.Offset
403 if stacksize == -8 {
404
405 text.From.Sym.Set(obj.AttrNoFrame, true)
406 stacksize = 0
407 }
408 if stacksize < 0 {
409 ctxt.Diag("negative frame size %d - did you mean NOFRAME?", stacksize)
410 }
411 if text.From.Sym.NoFrame() {
412 if stacksize != 0 {
413 ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", stacksize)
414 }
415 }
416
417 if !containsCall(cursym) {
418 text.From.Sym.Set(obj.AttrLeaf, true)
419 if stacksize == 0 {
420
421 text.From.Sym.Set(obj.AttrNoFrame, true)
422 }
423 }
424
425
426 if !text.From.Sym.NoFrame() {
427 stacksize += ctxt.Arch.FixedFrameSize
428 }
429
430 cursym.Func().Args = text.To.Val.(int32)
431 cursym.Func().Locals = int32(stacksize)
432
433 prologue := text
434
435 if !cursym.Func().Text.From.Sym.NoSplit() {
436 prologue = stacksplit(ctxt, prologue, cursym, newprog, stacksize)
437 }
438
439 q := prologue
440
441 if stacksize != 0 {
442 prologue = ctxt.StartUnsafePoint(prologue, newprog)
443
444
445 prologue = obj.Appendp(prologue, newprog)
446 prologue.As = AMOV
447 prologue.Pos = q.Pos
448 prologue.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
449 prologue.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: -stacksize}
450
451
452 prologue = obj.Appendp(prologue, newprog)
453 prologue.As = AADDI
454 prologue.Pos = q.Pos
455 prologue.Pos = prologue.Pos.WithXlogue(src.PosPrologueEnd)
456 prologue.From = obj.Addr{Type: obj.TYPE_CONST, Offset: -stacksize}
457 prologue.Reg = REG_SP
458 prologue.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_SP}
459 prologue.Spadj = int32(stacksize)
460
461 prologue = ctxt.EndUnsafePoint(prologue, newprog, -1)
462
463
464
465
466
467
468 prologue = obj.Appendp(prologue, newprog)
469 prologue.As = AMOV
470 prologue.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
471 prologue.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 0}
472 }
473
474 if cursym.Func().Text.From.Sym.Wrapper() {
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492 ldpanic := obj.Appendp(prologue, newprog)
493
494 ldpanic.As = AMOV
495 ldpanic.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REGG, Offset: 4 * int64(ctxt.Arch.PtrSize)}
496 ldpanic.Reg = obj.REG_NONE
497 ldpanic.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X5}
498
499 bneadj := obj.Appendp(ldpanic, newprog)
500 bneadj.As = ABNE
501 bneadj.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X5}
502 bneadj.Reg = REG_ZERO
503 bneadj.To.Type = obj.TYPE_BRANCH
504
505 endadj := obj.Appendp(bneadj, newprog)
506 endadj.As = obj.ANOP
507
508 last := endadj
509 for last.Link != nil {
510 last = last.Link
511 }
512
513 getargp := obj.Appendp(last, newprog)
514 getargp.As = AMOV
515 getargp.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_X5, Offset: 0}
516 getargp.Reg = obj.REG_NONE
517 getargp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X6}
518
519 bneadj.To.SetTarget(getargp)
520
521 calcargp := obj.Appendp(getargp, newprog)
522 calcargp.As = AADDI
523 calcargp.From = obj.Addr{Type: obj.TYPE_CONST, Offset: stacksize + ctxt.Arch.FixedFrameSize}
524 calcargp.Reg = REG_SP
525 calcargp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X7}
526
527 testargp := obj.Appendp(calcargp, newprog)
528 testargp.As = ABNE
529 testargp.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X6}
530 testargp.Reg = REG_X7
531 testargp.To.Type = obj.TYPE_BRANCH
532 testargp.To.SetTarget(endadj)
533
534 adjargp := obj.Appendp(testargp, newprog)
535 adjargp.As = AADDI
536 adjargp.From = obj.Addr{Type: obj.TYPE_CONST, Offset: int64(ctxt.Arch.PtrSize)}
537 adjargp.Reg = REG_SP
538 adjargp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X6}
539
540 setargp := obj.Appendp(adjargp, newprog)
541 setargp.As = AMOV
542 setargp.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X6}
543 setargp.Reg = obj.REG_NONE
544 setargp.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_X5, Offset: 0}
545
546 godone := obj.Appendp(setargp, newprog)
547 godone.As = AJAL
548 godone.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
549 godone.To.Type = obj.TYPE_BRANCH
550 godone.To.SetTarget(endadj)
551 }
552
553
554 for p := cursym.Func().Text; p != nil; p = p.Link {
555 stackOffset(&p.From, stacksize)
556 stackOffset(&p.To, stacksize)
557 }
558
559
560 for p := cursym.Func().Text; p != nil; p = p.Link {
561 switch p.As {
562 case obj.AGETCALLERPC:
563 if cursym.Leaf() {
564
565 p.As = AMOV
566 p.From.Type = obj.TYPE_REG
567 p.From.Reg = REG_LR
568 } else {
569
570 p.As = AMOV
571 p.From.Type = obj.TYPE_MEM
572 p.From.Reg = REG_SP
573 }
574
575 case obj.ACALL, obj.ADUFFZERO, obj.ADUFFCOPY:
576 switch p.To.Type {
577 case obj.TYPE_MEM:
578 jalToSym(ctxt, p, REG_LR)
579 }
580
581 case obj.AJMP:
582 switch p.To.Type {
583 case obj.TYPE_MEM:
584 switch p.To.Name {
585 case obj.NAME_EXTERN, obj.NAME_STATIC:
586 jalToSym(ctxt, p, REG_ZERO)
587 }
588 }
589
590 case obj.ARET:
591
592 retJMP := p.To.Sym
593
594 if stacksize != 0 {
595
596 p.As = AMOV
597 p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 0}
598 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
599 p = obj.Appendp(p, newprog)
600
601 p.As = AADDI
602 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: stacksize}
603 p.Reg = REG_SP
604 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_SP}
605 p.Spadj = int32(-stacksize)
606 p = obj.Appendp(p, newprog)
607 }
608
609 if retJMP != nil {
610 p.As = obj.ARET
611 p.To.Sym = retJMP
612 jalToSym(ctxt, p, REG_ZERO)
613 } else {
614 p.As = AJALR
615 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
616 p.Reg = obj.REG_NONE
617 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
618 }
619
620
621
622
623
624
625
626 p.Spadj = int32(stacksize)
627
628 case AADDI:
629
630 if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_SP && p.From.Type == obj.TYPE_CONST {
631 p.Spadj = int32(-p.From.Offset)
632 }
633 }
634
635 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
636 f := cursym.Func()
637 if f.FuncFlag&abi.FuncFlagSPWrite == 0 {
638 f.FuncFlag |= abi.FuncFlagSPWrite
639 if ctxt.Debugvlog || !ctxt.IsAsm {
640 ctxt.Logf("auto-SPWRITE: %s %v\n", cursym.Name, p)
641 if !ctxt.IsAsm {
642 ctxt.Diag("invalid auto-SPWRITE in non-assembly")
643 ctxt.DiagFlush()
644 log.Fatalf("bad SPWRITE")
645 }
646 }
647 }
648 }
649 }
650
651 var callCount int
652 for p := cursym.Func().Text; p != nil; p = p.Link {
653 markRelocs(p)
654 if p.Mark&NEED_JAL_RELOC == NEED_JAL_RELOC {
655 callCount++
656 }
657 }
658 const callTrampSize = 8
659 maxTrampSize := int64(callCount * callTrampSize)
660
661
662
663
664
665 for {
666 big, rescan := false, false
667 maxPC := setPCs(cursym.Func().Text, 0)
668 if maxPC+maxTrampSize > (1 << 20) {
669 big = true
670 }
671
672 for p := cursym.Func().Text; p != nil; p = p.Link {
673 switch p.As {
674 case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ:
675 if p.To.Type != obj.TYPE_BRANCH {
676 panic("assemble: instruction with branch-like opcode lacks destination")
677 }
678 offset := p.To.Target().Pc - p.Pc
679 if offset < -4096 || 4096 <= offset {
680
681 jmp := obj.Appendp(p, newprog)
682 jmp.As = AJAL
683 jmp.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
684 jmp.To = obj.Addr{Type: obj.TYPE_BRANCH}
685 jmp.To.SetTarget(p.To.Target())
686
687 p.As = InvertBranch(p.As)
688 p.To.SetTarget(jmp.Link)
689
690
691
692 rescan = true
693 }
694 case AJAL:
695
696 if p.To.Target() == nil {
697 if !big {
698 break
699 }
700
701
702 jmp := obj.Appendp(p, newprog)
703 jmp.As = AJALR
704 jmp.From = p.From
705 jmp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
706
707 p.As = AAUIPC
708 p.Mark = (p.Mark &^ NEED_JAL_RELOC) | NEED_CALL_RELOC
709 p.AddRestSource(obj.Addr{Type: obj.TYPE_CONST, Offset: p.To.Offset, Sym: p.To.Sym})
710 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
711 p.Reg = obj.REG_NONE
712 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
713
714 rescan = true
715 break
716 }
717 offset := p.To.Target().Pc - p.Pc
718 if offset < -(1<<20) || (1<<20) <= offset {
719
720
721
722 jmp := obj.Appendp(p, newprog)
723 jmp.As = AJALR
724 jmp.From = p.From
725 jmp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
726
727
728
729 p.As = AAUIPC
730 p.From = obj.Addr{Type: obj.TYPE_BRANCH, Sym: p.From.Sym}
731 p.From.SetTarget(p.To.Target())
732 p.Reg = obj.REG_NONE
733 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
734
735 rescan = true
736 }
737 }
738 }
739
740 if !rescan {
741 break
742 }
743 }
744
745
746
747
748 for p := cursym.Func().Text; p != nil; p = p.Link {
749 switch p.As {
750 case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ:
751 switch p.To.Type {
752 case obj.TYPE_BRANCH:
753 p.To.Type, p.To.Offset = obj.TYPE_CONST, p.To.Target().Pc-p.Pc
754 case obj.TYPE_MEM:
755 panic("unhandled type")
756 }
757
758 case AJAL:
759
760 if p.To.Target() != nil {
761 p.To.Type, p.To.Offset = obj.TYPE_CONST, p.To.Target().Pc-p.Pc
762 }
763
764 case AAUIPC:
765 if p.From.Type == obj.TYPE_BRANCH {
766 low, high, err := Split32BitImmediate(p.From.Target().Pc - p.Pc)
767 if err != nil {
768 ctxt.Diag("%v: jump displacement %d too large", p, p.To.Target().Pc-p.Pc)
769 }
770 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high, Sym: cursym}
771 p.Link.To.Offset = low
772 }
773
774 case obj.APCALIGN:
775 alignedValue := p.From.Offset
776 if (alignedValue&(alignedValue-1) != 0) || 4 > alignedValue || alignedValue > 2048 {
777 ctxt.Diag("alignment value of an instruction must be a power of two and in the range [4, 2048], got %d\n", alignedValue)
778 }
779
780 if int32(alignedValue) > cursym.Func().Align {
781 cursym.Func().Align = int32(alignedValue)
782 }
783 }
784 }
785
786
787 for p := cursym.Func().Text; p != nil; p = p.Link {
788 for _, ins := range instructionsForProg(p) {
789 ins.validate(ctxt)
790 }
791 }
792 }
793
794 func pcAlignPadLength(pc int64, alignedValue int64) int {
795 return int(-pc & (alignedValue - 1))
796 }
797
798 func stacksplit(ctxt *obj.Link, p *obj.Prog, cursym *obj.LSym, newprog obj.ProgAlloc, framesize int64) *obj.Prog {
799
800 if framesize == 0 {
801 return p
802 }
803
804 if ctxt.Flag_maymorestack != "" {
805
806 const frameSize = 16
807 p = ctxt.StartUnsafePoint(p, newprog)
808
809
810
811 p = cursym.Func().SpillRegisterArgs(p, newprog)
812
813
814 p = obj.Appendp(p, newprog)
815 p.As = AMOV
816 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
817 p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: -frameSize}
818
819 p = obj.Appendp(p, newprog)
820 p.As = AADDI
821 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: -frameSize}
822 p.Reg = REG_SP
823 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_SP}
824 p.Spadj = frameSize
825
826 p = obj.Appendp(p, newprog)
827 p.As = AMOV
828 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_CTXT}
829 p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 8}
830
831
832 p = obj.Appendp(p, newprog)
833 p.As = obj.ACALL
834 p.To.Type = obj.TYPE_BRANCH
835
836 p.To.Sym = ctxt.LookupABI(ctxt.Flag_maymorestack, cursym.ABI())
837 jalToSym(ctxt, p, REG_X5)
838
839
840
841
842 p = obj.Appendp(p, newprog)
843 p.As = AMOV
844 p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 8}
845 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_CTXT}
846
847 p = obj.Appendp(p, newprog)
848 p.As = AMOV
849 p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 0}
850 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
851
852 p = obj.Appendp(p, newprog)
853 p.As = AADDI
854 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: frameSize}
855 p.Reg = REG_SP
856 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_SP}
857 p.Spadj = -frameSize
858
859
860 p = cursym.Func().UnspillRegisterArgs(p, newprog)
861 p = ctxt.EndUnsafePoint(p, newprog, -1)
862 }
863
864
865 startPred := p
866
867
868 p = obj.Appendp(p, newprog)
869 p.As = AMOV
870 p.From.Type = obj.TYPE_MEM
871 p.From.Reg = REGG
872 p.From.Offset = 2 * int64(ctxt.Arch.PtrSize)
873 if cursym.CFunc() {
874 p.From.Offset = 3 * int64(ctxt.Arch.PtrSize)
875 }
876 p.To.Type = obj.TYPE_REG
877 p.To.Reg = REG_X6
878
879
880
881
882
883 p = ctxt.StartUnsafePoint(p, newprog)
884
885 var to_done, to_more *obj.Prog
886
887 if framesize <= abi.StackSmall {
888
889
890
891 p = obj.Appendp(p, newprog)
892 p.As = ABLTU
893 p.From.Type = obj.TYPE_REG
894 p.From.Reg = REG_X6
895 p.Reg = REG_SP
896 p.To.Type = obj.TYPE_BRANCH
897 to_done = p
898 } else {
899
900 offset := int64(framesize) - abi.StackSmall
901 if framesize > abi.StackBig {
902
903
904
905
906
907
908
909
910
911
912 p = obj.Appendp(p, newprog)
913 p.As = AMOV
914 p.From.Type = obj.TYPE_CONST
915 p.From.Offset = offset
916 p.To.Type = obj.TYPE_REG
917 p.To.Reg = REG_X7
918
919 p = obj.Appendp(p, newprog)
920 p.As = ABLTU
921 p.From.Type = obj.TYPE_REG
922 p.From.Reg = REG_SP
923 p.Reg = REG_X7
924 p.To.Type = obj.TYPE_BRANCH
925 to_more = p
926 }
927
928
929
930
931
932 p = obj.Appendp(p, newprog)
933 p.As = AADDI
934 p.From.Type = obj.TYPE_CONST
935 p.From.Offset = -offset
936 p.Reg = REG_SP
937 p.To.Type = obj.TYPE_REG
938 p.To.Reg = REG_X7
939
940 p = obj.Appendp(p, newprog)
941 p.As = ABLTU
942 p.From.Type = obj.TYPE_REG
943 p.From.Reg = REG_X6
944 p.Reg = REG_X7
945 p.To.Type = obj.TYPE_BRANCH
946 to_done = p
947 }
948
949
950
951 p = ctxt.EmitEntryStackMap(cursym, p, newprog)
952 p = cursym.Func().SpillRegisterArgs(p, newprog)
953
954
955 p = obj.Appendp(p, newprog)
956 p.As = obj.ACALL
957 p.To.Type = obj.TYPE_BRANCH
958
959 if cursym.CFunc() {
960 p.To.Sym = ctxt.Lookup("runtime.morestackc")
961 } else if !cursym.Func().Text.From.Sym.NeedCtxt() {
962 p.To.Sym = ctxt.Lookup("runtime.morestack_noctxt")
963 } else {
964 p.To.Sym = ctxt.Lookup("runtime.morestack")
965 }
966 if to_more != nil {
967 to_more.To.SetTarget(p)
968 }
969 jalToSym(ctxt, p, REG_X5)
970
971
972 p = ctxt.EndUnsafePoint(p, newprog, -1)
973 p = cursym.Func().UnspillRegisterArgs(p, newprog)
974
975
976 p = obj.Appendp(p, newprog)
977 p.As = AJAL
978 p.To = obj.Addr{Type: obj.TYPE_BRANCH}
979 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
980 p.To.SetTarget(startPred.Link)
981
982
983 p = obj.Appendp(p, newprog)
984 p.As = obj.ANOP
985 to_done.To.SetTarget(p)
986
987 return p
988 }
989
990
991 func signExtend(val int64, bit uint) int64 {
992 return val << (64 - bit) >> (64 - bit)
993 }
994
995
996
997
998
999 func Split32BitImmediate(imm int64) (low, high int64, err error) {
1000 if err := immIFits(imm, 32); err != nil {
1001 return 0, 0, err
1002 }
1003
1004
1005 if err := immIFits(imm, 12); err == nil {
1006 return imm, 0, nil
1007 }
1008
1009 high = imm >> 12
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020 if imm&(1<<11) != 0 {
1021 high++
1022 }
1023
1024 low = signExtend(imm, 12)
1025 high = signExtend(high, 20)
1026
1027 return low, high, nil
1028 }
1029
1030 func regVal(r, min, max uint32) uint32 {
1031 if r < min || r > max {
1032 panic(fmt.Sprintf("register out of range, want %d <= %d <= %d", min, r, max))
1033 }
1034 return r - min
1035 }
1036
1037
1038 func regI(r uint32) uint32 {
1039 return regVal(r, REG_X0, REG_X31)
1040 }
1041
1042
1043 func regF(r uint32) uint32 {
1044 return regVal(r, REG_F0, REG_F31)
1045 }
1046
1047
1048 func regV(r uint32) uint32 {
1049 return regVal(r, REG_V0, REG_V31)
1050 }
1051
1052
1053 func regAddr(a obj.Addr, min, max uint32) uint32 {
1054 if a.Type != obj.TYPE_REG {
1055 panic(fmt.Sprintf("ill typed: %+v", a))
1056 }
1057 return regVal(uint32(a.Reg), min, max)
1058 }
1059
1060
1061 func regIAddr(a obj.Addr) uint32 {
1062 return regAddr(a, REG_X0, REG_X31)
1063 }
1064
1065
1066 func regFAddr(a obj.Addr) uint32 {
1067 return regAddr(a, REG_F0, REG_F31)
1068 }
1069
1070
1071
1072 func immEven(x int64) error {
1073 if x&1 != 0 {
1074 return fmt.Errorf("immediate %#x is not a multiple of two", x)
1075 }
1076 return nil
1077 }
1078
1079
1080
1081 func immIFits(x int64, nbits uint) error {
1082 nbits--
1083 min := int64(-1) << nbits
1084 max := int64(1)<<nbits - 1
1085 if x < min || x > max {
1086 if nbits <= 16 {
1087 return fmt.Errorf("signed immediate %d must be in range [%d, %d] (%d bits)", x, min, max, nbits)
1088 }
1089 return fmt.Errorf("signed immediate %#x must be in range [%#x, %#x] (%d bits)", x, min, max, nbits)
1090 }
1091 return nil
1092 }
1093
1094
1095 func immI(as obj.As, imm int64, nbits uint) uint32 {
1096 if err := immIFits(imm, nbits); err != nil {
1097 panic(fmt.Sprintf("%v: %v", as, err))
1098 }
1099 return uint32(imm)
1100 }
1101
1102 func wantImmI(ctxt *obj.Link, ins *instruction, imm int64, nbits uint) {
1103 if err := immIFits(imm, nbits); err != nil {
1104 ctxt.Diag("%v: %v", ins, err)
1105 }
1106 }
1107
1108 func wantReg(ctxt *obj.Link, ins *instruction, pos string, descr string, r, min, max uint32) {
1109 if r < min || r > max {
1110 var suffix string
1111 if r != obj.REG_NONE {
1112 suffix = fmt.Sprintf(" but got non-%s register %s", descr, RegName(int(r)))
1113 }
1114 ctxt.Diag("%v: expected %s register in %s position%s", ins, descr, pos, suffix)
1115 }
1116 }
1117
1118 func wantNoneReg(ctxt *obj.Link, ins *instruction, pos string, r uint32) {
1119 if r != obj.REG_NONE {
1120 ctxt.Diag("%v: expected no register in %s but got register %s", ins, pos, RegName(int(r)))
1121 }
1122 }
1123
1124
1125 func wantIntReg(ctxt *obj.Link, ins *instruction, pos string, r uint32) {
1126 wantReg(ctxt, ins, pos, "integer", r, REG_X0, REG_X31)
1127 }
1128
1129
1130 func wantFloatReg(ctxt *obj.Link, ins *instruction, pos string, r uint32) {
1131 wantReg(ctxt, ins, pos, "float", r, REG_F0, REG_F31)
1132 }
1133
1134
1135 func wantVectorReg(ctxt *obj.Link, ins *instruction, pos string, r uint32) {
1136 wantReg(ctxt, ins, pos, "vector", r, REG_V0, REG_V31)
1137 }
1138
1139
1140 func wantEvenOffset(ctxt *obj.Link, ins *instruction, offset int64) {
1141 if err := immEven(offset); err != nil {
1142 ctxt.Diag("%v: %v", ins, err)
1143 }
1144 }
1145
1146 func validateRII(ctxt *obj.Link, ins *instruction) {
1147 wantIntReg(ctxt, ins, "rd", ins.rd)
1148 wantIntReg(ctxt, ins, "rs1", ins.rs1)
1149 wantNoneReg(ctxt, ins, "rs2", ins.rs2)
1150 wantNoneReg(ctxt, ins, "rs3", ins.rs3)
1151 }
1152
1153 func validateRIII(ctxt *obj.Link, ins *instruction) {
1154 wantIntReg(ctxt, ins, "rd", ins.rd)
1155 wantIntReg(ctxt, ins, "rs1", ins.rs1)
1156 wantIntReg(ctxt, ins, "rs2", ins.rs2)
1157 wantNoneReg(ctxt, ins, "rs3", ins.rs3)
1158 }
1159
1160 func validateRFFF(ctxt *obj.Link, ins *instruction) {
1161 wantFloatReg(ctxt, ins, "rd", ins.rd)
1162 wantFloatReg(ctxt, ins, "rs1", ins.rs1)
1163 wantFloatReg(ctxt, ins, "rs2", ins.rs2)
1164 wantNoneReg(ctxt, ins, "rs3", ins.rs3)
1165 }
1166
1167 func validateRFFFF(ctxt *obj.Link, ins *instruction) {
1168 wantFloatReg(ctxt, ins, "rd", ins.rd)
1169 wantFloatReg(ctxt, ins, "rs1", ins.rs1)
1170 wantFloatReg(ctxt, ins, "rs2", ins.rs2)
1171 wantFloatReg(ctxt, ins, "rs3", ins.rs3)
1172 }
1173
1174 func validateRFFI(ctxt *obj.Link, ins *instruction) {
1175 wantIntReg(ctxt, ins, "rd", ins.rd)
1176 wantFloatReg(ctxt, ins, "rs1", ins.rs1)
1177 wantFloatReg(ctxt, ins, "rs2", ins.rs2)
1178 wantNoneReg(ctxt, ins, "rs3", ins.rs3)
1179 }
1180
1181 func validateRFI(ctxt *obj.Link, ins *instruction) {
1182 wantIntReg(ctxt, ins, "rd", ins.rd)
1183 wantNoneReg(ctxt, ins, "rs1", ins.rs1)
1184 wantFloatReg(ctxt, ins, "rs2", ins.rs2)
1185 wantNoneReg(ctxt, ins, "rs3", ins.rs3)
1186 }
1187
1188 func validateRIF(ctxt *obj.Link, ins *instruction) {
1189 wantFloatReg(ctxt, ins, "rd", ins.rd)
1190 wantNoneReg(ctxt, ins, "rs1", ins.rs1)
1191 wantIntReg(ctxt, ins, "rs2", ins.rs2)
1192 wantNoneReg(ctxt, ins, "rs3", ins.rs3)
1193 }
1194
1195 func validateRFF(ctxt *obj.Link, ins *instruction) {
1196 wantFloatReg(ctxt, ins, "rd", ins.rd)
1197 wantNoneReg(ctxt, ins, "rs1", ins.rs1)
1198 wantFloatReg(ctxt, ins, "rs2", ins.rs2)
1199 wantNoneReg(ctxt, ins, "rs3", ins.rs3)
1200 }
1201
1202 func validateIII(ctxt *obj.Link, ins *instruction) {
1203 wantImmI(ctxt, ins, ins.imm, 12)
1204 wantIntReg(ctxt, ins, "rd", ins.rd)
1205 wantIntReg(ctxt, ins, "rs1", ins.rs1)
1206 wantNoneReg(ctxt, ins, "rs2", ins.rs2)
1207 wantNoneReg(ctxt, ins, "rs3", ins.rs3)
1208 }
1209
1210 func validateIF(ctxt *obj.Link, ins *instruction) {
1211 wantImmI(ctxt, ins, ins.imm, 12)
1212 wantFloatReg(ctxt, ins, "rd", ins.rd)
1213 wantIntReg(ctxt, ins, "rs1", ins.rs1)
1214 wantNoneReg(ctxt, ins, "rs2", ins.rs2)
1215 wantNoneReg(ctxt, ins, "rs3", ins.rs3)
1216 }
1217
1218 func validateSI(ctxt *obj.Link, ins *instruction) {
1219 wantImmI(ctxt, ins, ins.imm, 12)
1220 wantIntReg(ctxt, ins, "rd", ins.rd)
1221 wantIntReg(ctxt, ins, "rs1", ins.rs1)
1222 wantNoneReg(ctxt, ins, "rs2", ins.rs2)
1223 wantNoneReg(ctxt, ins, "rs3", ins.rs3)
1224 }
1225
1226 func validateSF(ctxt *obj.Link, ins *instruction) {
1227 wantImmI(ctxt, ins, ins.imm, 12)
1228 wantIntReg(ctxt, ins, "rd", ins.rd)
1229 wantFloatReg(ctxt, ins, "rs1", ins.rs1)
1230 wantNoneReg(ctxt, ins, "rs2", ins.rs2)
1231 wantNoneReg(ctxt, ins, "rs3", ins.rs3)
1232 }
1233
1234 func validateB(ctxt *obj.Link, ins *instruction) {
1235
1236
1237 wantEvenOffset(ctxt, ins, ins.imm)
1238 wantImmI(ctxt, ins, ins.imm, 13)
1239 wantNoneReg(ctxt, ins, "rd", ins.rd)
1240 wantIntReg(ctxt, ins, "rs1", ins.rs1)
1241 wantIntReg(ctxt, ins, "rs2", ins.rs2)
1242 wantNoneReg(ctxt, ins, "rs3", ins.rs3)
1243 }
1244
1245 func validateU(ctxt *obj.Link, ins *instruction) {
1246 wantImmI(ctxt, ins, ins.imm, 20)
1247 wantIntReg(ctxt, ins, "rd", ins.rd)
1248 wantNoneReg(ctxt, ins, "rs1", ins.rs1)
1249 wantNoneReg(ctxt, ins, "rs2", ins.rs2)
1250 wantNoneReg(ctxt, ins, "rs3", ins.rs3)
1251 }
1252
1253 func validateJ(ctxt *obj.Link, ins *instruction) {
1254
1255
1256 wantEvenOffset(ctxt, ins, ins.imm)
1257 wantImmI(ctxt, ins, ins.imm, 21)
1258 wantIntReg(ctxt, ins, "rd", ins.rd)
1259 wantNoneReg(ctxt, ins, "rs1", ins.rs1)
1260 wantNoneReg(ctxt, ins, "rs2", ins.rs2)
1261 wantNoneReg(ctxt, ins, "rs3", ins.rs3)
1262 }
1263
1264 func validateRaw(ctxt *obj.Link, ins *instruction) {
1265
1266
1267 if ins.imm < 0 || 1<<32 <= ins.imm {
1268 ctxt.Diag("%v: immediate %d in raw position cannot be larger than 32 bits", ins.as, ins.imm)
1269 }
1270 }
1271
1272
1273
1274 func extractBitAndShift(imm uint32, bit, pos int) uint32 {
1275 return ((imm >> bit) & 1) << pos
1276 }
1277
1278
1279 func encodeR(as obj.As, rs1, rs2, rd, funct3, funct7 uint32) uint32 {
1280 enc := encode(as)
1281 if enc == nil {
1282 panic("encodeR: could not encode instruction")
1283 }
1284 if enc.rs2 != 0 && rs2 != 0 {
1285 panic("encodeR: instruction uses rs2, but rs2 was nonzero")
1286 }
1287 return funct7<<25 | enc.funct7<<25 | enc.rs2<<20 | rs2<<20 | rs1<<15 | enc.funct3<<12 | funct3<<12 | rd<<7 | enc.opcode
1288 }
1289
1290
1291 func encodeR4(as obj.As, rs1, rs2, rs3, rd, funct3, funct2 uint32) uint32 {
1292 enc := encode(as)
1293 if enc == nil {
1294 panic("encodeR4: could not encode instruction")
1295 }
1296 if enc.rs2 != 0 {
1297 panic("encodeR4: instruction uses rs2")
1298 }
1299 funct2 |= enc.funct7
1300 if funct2&^3 != 0 {
1301 panic("encodeR4: funct2 requires more than 2 bits")
1302 }
1303 return rs3<<27 | funct2<<25 | rs2<<20 | rs1<<15 | enc.funct3<<12 | funct3<<12 | rd<<7 | enc.opcode
1304 }
1305
1306 func encodeRII(ins *instruction) uint32 {
1307 return encodeR(ins.as, regI(ins.rs1), 0, regI(ins.rd), ins.funct3, ins.funct7)
1308 }
1309
1310 func encodeRIII(ins *instruction) uint32 {
1311 return encodeR(ins.as, regI(ins.rs1), regI(ins.rs2), regI(ins.rd), ins.funct3, ins.funct7)
1312 }
1313
1314 func encodeRFFF(ins *instruction) uint32 {
1315 return encodeR(ins.as, regF(ins.rs1), regF(ins.rs2), regF(ins.rd), ins.funct3, ins.funct7)
1316 }
1317
1318 func encodeRFFFF(ins *instruction) uint32 {
1319 return encodeR4(ins.as, regF(ins.rs1), regF(ins.rs2), regF(ins.rs3), regF(ins.rd), ins.funct3, ins.funct7)
1320 }
1321
1322 func encodeRFFI(ins *instruction) uint32 {
1323 return encodeR(ins.as, regF(ins.rs1), regF(ins.rs2), regI(ins.rd), ins.funct3, ins.funct7)
1324 }
1325
1326 func encodeRFI(ins *instruction) uint32 {
1327 return encodeR(ins.as, regF(ins.rs2), 0, regI(ins.rd), ins.funct3, ins.funct7)
1328 }
1329
1330 func encodeRIF(ins *instruction) uint32 {
1331 return encodeR(ins.as, regI(ins.rs2), 0, regF(ins.rd), ins.funct3, ins.funct7)
1332 }
1333
1334 func encodeRFF(ins *instruction) uint32 {
1335 return encodeR(ins.as, regF(ins.rs2), 0, regF(ins.rd), ins.funct3, ins.funct7)
1336 }
1337
1338
1339 func encodeI(as obj.As, rs1, rd, imm uint32) uint32 {
1340 enc := encode(as)
1341 if enc == nil {
1342 panic("encodeI: could not encode instruction")
1343 }
1344 imm |= uint32(enc.csr)
1345 return imm<<20 | rs1<<15 | enc.funct3<<12 | rd<<7 | enc.opcode
1346 }
1347
1348 func encodeIII(ins *instruction) uint32 {
1349 return encodeI(ins.as, regI(ins.rs1), regI(ins.rd), uint32(ins.imm))
1350 }
1351
1352 func encodeIF(ins *instruction) uint32 {
1353 return encodeI(ins.as, regI(ins.rs1), regF(ins.rd), uint32(ins.imm))
1354 }
1355
1356
1357 func encodeS(as obj.As, rs1, rs2, imm uint32) uint32 {
1358 enc := encode(as)
1359 if enc == nil {
1360 panic("encodeS: could not encode instruction")
1361 }
1362 return (imm>>5)<<25 | rs2<<20 | rs1<<15 | enc.funct3<<12 | (imm&0x1f)<<7 | enc.opcode
1363 }
1364
1365 func encodeSI(ins *instruction) uint32 {
1366 return encodeS(ins.as, regI(ins.rd), regI(ins.rs1), uint32(ins.imm))
1367 }
1368
1369 func encodeSF(ins *instruction) uint32 {
1370 return encodeS(ins.as, regI(ins.rd), regF(ins.rs1), uint32(ins.imm))
1371 }
1372
1373
1374 func encodeBImmediate(imm uint32) uint32 {
1375 return (imm>>12)<<31 | ((imm>>5)&0x3f)<<25 | ((imm>>1)&0xf)<<8 | ((imm>>11)&0x1)<<7
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 encodeBImmediate(imm) | rs2<<20 | rs1<<15 | enc.funct3<<12 | 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 encodeJImmediate(imm uint32) uint32 {
1407 return (imm>>20)<<31 | ((imm>>1)&0x3ff)<<21 | ((imm>>11)&0x1)<<20 | ((imm>>12)&0xff)<<12
1408 }
1409
1410
1411 func encodeJ(ins *instruction) uint32 {
1412 imm := immI(ins.as, ins.imm, 21)
1413 rd := regI(ins.rd)
1414 enc := encode(ins.as)
1415 if enc == nil {
1416 panic("encodeJ: could not encode instruction")
1417 }
1418 return encodeJImmediate(imm) | rd<<7 | enc.opcode
1419 }
1420
1421
1422 func encodeCBImmediate(imm uint32) uint32 {
1423
1424 bits := extractBitAndShift(imm, 8, 7)
1425 bits |= extractBitAndShift(imm, 4, 6)
1426 bits |= extractBitAndShift(imm, 3, 5)
1427 bits |= extractBitAndShift(imm, 7, 4)
1428 bits |= extractBitAndShift(imm, 6, 3)
1429 bits |= extractBitAndShift(imm, 2, 2)
1430 bits |= extractBitAndShift(imm, 1, 1)
1431 bits |= extractBitAndShift(imm, 5, 0)
1432 return (bits>>5)<<10 | (bits&0x1f)<<2
1433 }
1434
1435
1436 func encodeCJImmediate(imm uint32) uint32 {
1437
1438 bits := extractBitAndShift(imm, 11, 10)
1439 bits |= extractBitAndShift(imm, 4, 9)
1440 bits |= extractBitAndShift(imm, 9, 8)
1441 bits |= extractBitAndShift(imm, 8, 7)
1442 bits |= extractBitAndShift(imm, 10, 6)
1443 bits |= extractBitAndShift(imm, 6, 5)
1444 bits |= extractBitAndShift(imm, 7, 4)
1445 bits |= extractBitAndShift(imm, 3, 3)
1446 bits |= extractBitAndShift(imm, 2, 2)
1447 bits |= extractBitAndShift(imm, 1, 1)
1448 bits |= extractBitAndShift(imm, 5, 0)
1449 return bits << 2
1450 }
1451
1452 func encodeRawIns(ins *instruction) uint32 {
1453
1454
1455 if ins.imm < 0 || 1<<32 <= ins.imm {
1456 panic(fmt.Sprintf("immediate %d cannot fit in 32 bits", ins.imm))
1457 }
1458 return uint32(ins.imm)
1459 }
1460
1461 func EncodeBImmediate(imm int64) (int64, error) {
1462 if err := immIFits(imm, 13); err != nil {
1463 return 0, err
1464 }
1465 if err := immEven(imm); err != nil {
1466 return 0, err
1467 }
1468 return int64(encodeBImmediate(uint32(imm))), nil
1469 }
1470
1471 func EncodeCBImmediate(imm int64) (int64, error) {
1472 if err := immIFits(imm, 9); err != nil {
1473 return 0, err
1474 }
1475 if err := immEven(imm); err != nil {
1476 return 0, err
1477 }
1478 return int64(encodeCBImmediate(uint32(imm))), nil
1479 }
1480
1481 func EncodeCJImmediate(imm int64) (int64, error) {
1482 if err := immIFits(imm, 12); err != nil {
1483 return 0, err
1484 }
1485 if err := immEven(imm); err != nil {
1486 return 0, err
1487 }
1488 return int64(encodeCJImmediate(uint32(imm))), nil
1489 }
1490
1491 func EncodeIImmediate(imm int64) (int64, error) {
1492 if err := immIFits(imm, 12); err != nil {
1493 return 0, err
1494 }
1495 return imm << 20, nil
1496 }
1497
1498 func EncodeJImmediate(imm int64) (int64, error) {
1499 if err := immIFits(imm, 21); err != nil {
1500 return 0, err
1501 }
1502 if err := immEven(imm); err != nil {
1503 return 0, err
1504 }
1505 return int64(encodeJImmediate(uint32(imm))), nil
1506 }
1507
1508 func EncodeSImmediate(imm int64) (int64, error) {
1509 if err := immIFits(imm, 12); err != nil {
1510 return 0, err
1511 }
1512 return ((imm >> 5) << 25) | ((imm & 0x1f) << 7), nil
1513 }
1514
1515 func EncodeUImmediate(imm int64) (int64, error) {
1516 if err := immIFits(imm, 20); err != nil {
1517 return 0, err
1518 }
1519 return imm << 12, nil
1520 }
1521
1522 type encoding struct {
1523 encode func(*instruction) uint32
1524 validate func(*obj.Link, *instruction)
1525 length int
1526 }
1527
1528 var (
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540 rIIIEncoding = encoding{encode: encodeRIII, validate: validateRIII, length: 4}
1541 rIIEncoding = encoding{encode: encodeRII, validate: validateRII, length: 4}
1542 rFFFEncoding = encoding{encode: encodeRFFF, validate: validateRFFF, length: 4}
1543 rFFFFEncoding = encoding{encode: encodeRFFFF, validate: validateRFFFF, length: 4}
1544 rFFIEncoding = encoding{encode: encodeRFFI, validate: validateRFFI, length: 4}
1545 rFIEncoding = encoding{encode: encodeRFI, validate: validateRFI, length: 4}
1546 rIFEncoding = encoding{encode: encodeRIF, validate: validateRIF, length: 4}
1547 rFFEncoding = encoding{encode: encodeRFF, validate: validateRFF, length: 4}
1548
1549 iIIEncoding = encoding{encode: encodeIII, validate: validateIII, length: 4}
1550 iFEncoding = encoding{encode: encodeIF, validate: validateIF, length: 4}
1551
1552 sIEncoding = encoding{encode: encodeSI, validate: validateSI, length: 4}
1553 sFEncoding = encoding{encode: encodeSF, validate: validateSF, length: 4}
1554
1555 bEncoding = encoding{encode: encodeB, validate: validateB, length: 4}
1556 uEncoding = encoding{encode: encodeU, validate: validateU, length: 4}
1557 jEncoding = encoding{encode: encodeJ, validate: validateJ, length: 4}
1558
1559
1560 rawEncoding = encoding{encode: encodeRawIns, validate: validateRaw, length: 4}
1561
1562
1563 pseudoOpEncoding = encoding{encode: nil, validate: func(*obj.Link, *instruction) {}, length: 0}
1564
1565
1566
1567 badEncoding = encoding{encode: func(*instruction) uint32 { return 0 }, validate: func(*obj.Link, *instruction) {}, length: 0}
1568 )
1569
1570
1571
1572 var encodings = [ALAST & obj.AMask]encoding{
1573
1574
1575
1576
1577 AADDI & obj.AMask: iIIEncoding,
1578 ASLTI & obj.AMask: iIIEncoding,
1579 ASLTIU & obj.AMask: iIIEncoding,
1580 AANDI & obj.AMask: iIIEncoding,
1581 AORI & obj.AMask: iIIEncoding,
1582 AXORI & obj.AMask: iIIEncoding,
1583 ASLLI & obj.AMask: iIIEncoding,
1584 ASRLI & obj.AMask: iIIEncoding,
1585 ASRAI & obj.AMask: iIIEncoding,
1586 ALUI & obj.AMask: uEncoding,
1587 AAUIPC & obj.AMask: uEncoding,
1588 AADD & obj.AMask: rIIIEncoding,
1589 ASLT & obj.AMask: rIIIEncoding,
1590 ASLTU & obj.AMask: rIIIEncoding,
1591 AAND & obj.AMask: rIIIEncoding,
1592 AOR & obj.AMask: rIIIEncoding,
1593 AXOR & obj.AMask: rIIIEncoding,
1594 ASLL & obj.AMask: rIIIEncoding,
1595 ASRL & obj.AMask: rIIIEncoding,
1596 ASUB & obj.AMask: rIIIEncoding,
1597 ASRA & obj.AMask: rIIIEncoding,
1598
1599
1600 AJAL & obj.AMask: jEncoding,
1601 AJALR & obj.AMask: iIIEncoding,
1602 ABEQ & obj.AMask: bEncoding,
1603 ABNE & obj.AMask: bEncoding,
1604 ABLT & obj.AMask: bEncoding,
1605 ABLTU & obj.AMask: bEncoding,
1606 ABGE & obj.AMask: bEncoding,
1607 ABGEU & obj.AMask: bEncoding,
1608
1609
1610 ALW & obj.AMask: iIIEncoding,
1611 ALWU & obj.AMask: iIIEncoding,
1612 ALH & obj.AMask: iIIEncoding,
1613 ALHU & obj.AMask: iIIEncoding,
1614 ALB & obj.AMask: iIIEncoding,
1615 ALBU & obj.AMask: iIIEncoding,
1616 ASW & obj.AMask: sIEncoding,
1617 ASH & obj.AMask: sIEncoding,
1618 ASB & obj.AMask: sIEncoding,
1619
1620
1621 AFENCE & obj.AMask: iIIEncoding,
1622
1623
1624 AADDIW & obj.AMask: iIIEncoding,
1625 ASLLIW & obj.AMask: iIIEncoding,
1626 ASRLIW & obj.AMask: iIIEncoding,
1627 ASRAIW & obj.AMask: iIIEncoding,
1628 AADDW & obj.AMask: rIIIEncoding,
1629 ASLLW & obj.AMask: rIIIEncoding,
1630 ASRLW & obj.AMask: rIIIEncoding,
1631 ASUBW & obj.AMask: rIIIEncoding,
1632 ASRAW & obj.AMask: rIIIEncoding,
1633
1634
1635 ALD & obj.AMask: iIIEncoding,
1636 ASD & obj.AMask: sIEncoding,
1637
1638
1639 ACSRRS & obj.AMask: iIIEncoding,
1640
1641
1642 AMUL & obj.AMask: rIIIEncoding,
1643 AMULH & obj.AMask: rIIIEncoding,
1644 AMULHU & obj.AMask: rIIIEncoding,
1645 AMULHSU & obj.AMask: rIIIEncoding,
1646 AMULW & obj.AMask: rIIIEncoding,
1647 ADIV & obj.AMask: rIIIEncoding,
1648 ADIVU & obj.AMask: rIIIEncoding,
1649 AREM & obj.AMask: rIIIEncoding,
1650 AREMU & obj.AMask: rIIIEncoding,
1651 ADIVW & obj.AMask: rIIIEncoding,
1652 ADIVUW & obj.AMask: rIIIEncoding,
1653 AREMW & obj.AMask: rIIIEncoding,
1654 AREMUW & obj.AMask: rIIIEncoding,
1655
1656
1657 ALRW & obj.AMask: rIIIEncoding,
1658 ALRD & obj.AMask: rIIIEncoding,
1659 ASCW & obj.AMask: rIIIEncoding,
1660 ASCD & obj.AMask: rIIIEncoding,
1661
1662
1663 AAMOSWAPW & obj.AMask: rIIIEncoding,
1664 AAMOSWAPD & obj.AMask: rIIIEncoding,
1665 AAMOADDW & obj.AMask: rIIIEncoding,
1666 AAMOADDD & obj.AMask: rIIIEncoding,
1667 AAMOANDW & obj.AMask: rIIIEncoding,
1668 AAMOANDD & obj.AMask: rIIIEncoding,
1669 AAMOORW & obj.AMask: rIIIEncoding,
1670 AAMOORD & obj.AMask: rIIIEncoding,
1671 AAMOXORW & obj.AMask: rIIIEncoding,
1672 AAMOXORD & obj.AMask: rIIIEncoding,
1673 AAMOMAXW & obj.AMask: rIIIEncoding,
1674 AAMOMAXD & obj.AMask: rIIIEncoding,
1675 AAMOMAXUW & obj.AMask: rIIIEncoding,
1676 AAMOMAXUD & obj.AMask: rIIIEncoding,
1677 AAMOMINW & obj.AMask: rIIIEncoding,
1678 AAMOMIND & obj.AMask: rIIIEncoding,
1679 AAMOMINUW & obj.AMask: rIIIEncoding,
1680 AAMOMINUD & obj.AMask: rIIIEncoding,
1681
1682
1683 AFLW & obj.AMask: iFEncoding,
1684 AFSW & obj.AMask: sFEncoding,
1685
1686
1687 AFADDS & obj.AMask: rFFFEncoding,
1688 AFSUBS & obj.AMask: rFFFEncoding,
1689 AFMULS & obj.AMask: rFFFEncoding,
1690 AFDIVS & obj.AMask: rFFFEncoding,
1691 AFMINS & obj.AMask: rFFFEncoding,
1692 AFMAXS & obj.AMask: rFFFEncoding,
1693 AFSQRTS & obj.AMask: rFFFEncoding,
1694 AFMADDS & obj.AMask: rFFFFEncoding,
1695 AFMSUBS & obj.AMask: rFFFFEncoding,
1696 AFNMSUBS & obj.AMask: rFFFFEncoding,
1697 AFNMADDS & obj.AMask: rFFFFEncoding,
1698
1699
1700 AFCVTWS & obj.AMask: rFIEncoding,
1701 AFCVTLS & obj.AMask: rFIEncoding,
1702 AFCVTSW & obj.AMask: rIFEncoding,
1703 AFCVTSL & obj.AMask: rIFEncoding,
1704 AFCVTWUS & obj.AMask: rFIEncoding,
1705 AFCVTLUS & obj.AMask: rFIEncoding,
1706 AFCVTSWU & obj.AMask: rIFEncoding,
1707 AFCVTSLU & obj.AMask: rIFEncoding,
1708 AFSGNJS & obj.AMask: rFFFEncoding,
1709 AFSGNJNS & obj.AMask: rFFFEncoding,
1710 AFSGNJXS & obj.AMask: rFFFEncoding,
1711 AFMVXW & obj.AMask: rFIEncoding,
1712 AFMVWX & obj.AMask: rIFEncoding,
1713
1714
1715 AFEQS & obj.AMask: rFFIEncoding,
1716 AFLTS & obj.AMask: rFFIEncoding,
1717 AFLES & obj.AMask: rFFIEncoding,
1718
1719
1720 AFCLASSS & obj.AMask: rFIEncoding,
1721
1722
1723 AFLD & obj.AMask: iFEncoding,
1724 AFSD & obj.AMask: sFEncoding,
1725
1726
1727 AFADDD & obj.AMask: rFFFEncoding,
1728 AFSUBD & obj.AMask: rFFFEncoding,
1729 AFMULD & obj.AMask: rFFFEncoding,
1730 AFDIVD & obj.AMask: rFFFEncoding,
1731 AFMIND & obj.AMask: rFFFEncoding,
1732 AFMAXD & obj.AMask: rFFFEncoding,
1733 AFSQRTD & obj.AMask: rFFFEncoding,
1734 AFMADDD & obj.AMask: rFFFFEncoding,
1735 AFMSUBD & obj.AMask: rFFFFEncoding,
1736 AFNMSUBD & obj.AMask: rFFFFEncoding,
1737 AFNMADDD & obj.AMask: rFFFFEncoding,
1738
1739
1740 AFCVTWD & obj.AMask: rFIEncoding,
1741 AFCVTLD & obj.AMask: rFIEncoding,
1742 AFCVTDW & obj.AMask: rIFEncoding,
1743 AFCVTDL & obj.AMask: rIFEncoding,
1744 AFCVTWUD & obj.AMask: rFIEncoding,
1745 AFCVTLUD & obj.AMask: rFIEncoding,
1746 AFCVTDWU & obj.AMask: rIFEncoding,
1747 AFCVTDLU & obj.AMask: rIFEncoding,
1748 AFCVTSD & obj.AMask: rFFEncoding,
1749 AFCVTDS & obj.AMask: rFFEncoding,
1750 AFSGNJD & obj.AMask: rFFFEncoding,
1751 AFSGNJND & obj.AMask: rFFFEncoding,
1752 AFSGNJXD & obj.AMask: rFFFEncoding,
1753 AFMVXD & obj.AMask: rFIEncoding,
1754 AFMVDX & obj.AMask: rIFEncoding,
1755
1756
1757 AFEQD & obj.AMask: rFFIEncoding,
1758 AFLTD & obj.AMask: rFFIEncoding,
1759 AFLED & obj.AMask: rFFIEncoding,
1760
1761
1762 AFCLASSD & obj.AMask: rFIEncoding,
1763
1764
1765
1766
1767 AECALL & obj.AMask: iIIEncoding,
1768 AEBREAK & obj.AMask: iIIEncoding,
1769
1770
1771
1772
1773
1774
1775 AADDUW & obj.AMask: rIIIEncoding,
1776 ASH1ADD & obj.AMask: rIIIEncoding,
1777 ASH1ADDUW & obj.AMask: rIIIEncoding,
1778 ASH2ADD & obj.AMask: rIIIEncoding,
1779 ASH2ADDUW & obj.AMask: rIIIEncoding,
1780 ASH3ADD & obj.AMask: rIIIEncoding,
1781 ASH3ADDUW & obj.AMask: rIIIEncoding,
1782 ASLLIUW & obj.AMask: iIIEncoding,
1783
1784
1785 AANDN & obj.AMask: rIIIEncoding,
1786 ACLZ & obj.AMask: rIIEncoding,
1787 ACLZW & obj.AMask: rIIEncoding,
1788 ACPOP & obj.AMask: rIIEncoding,
1789 ACPOPW & obj.AMask: rIIEncoding,
1790 ACTZ & obj.AMask: rIIEncoding,
1791 ACTZW & obj.AMask: rIIEncoding,
1792 AMAX & obj.AMask: rIIIEncoding,
1793 AMAXU & obj.AMask: rIIIEncoding,
1794 AMIN & obj.AMask: rIIIEncoding,
1795 AMINU & obj.AMask: rIIIEncoding,
1796 AORN & obj.AMask: rIIIEncoding,
1797 ASEXTB & obj.AMask: rIIEncoding,
1798 ASEXTH & obj.AMask: rIIEncoding,
1799 AXNOR & obj.AMask: rIIIEncoding,
1800 AZEXTH & obj.AMask: rIIEncoding,
1801
1802
1803 AROL & obj.AMask: rIIIEncoding,
1804 AROLW & obj.AMask: rIIIEncoding,
1805 AROR & obj.AMask: rIIIEncoding,
1806 ARORI & obj.AMask: iIIEncoding,
1807 ARORIW & obj.AMask: iIIEncoding,
1808 ARORW & obj.AMask: rIIIEncoding,
1809 AORCB & obj.AMask: iIIEncoding,
1810 AREV8 & obj.AMask: iIIEncoding,
1811
1812
1813 ABCLR & obj.AMask: rIIIEncoding,
1814 ABCLRI & obj.AMask: iIIEncoding,
1815 ABEXT & obj.AMask: rIIIEncoding,
1816 ABEXTI & obj.AMask: iIIEncoding,
1817 ABINV & obj.AMask: rIIIEncoding,
1818 ABINVI & obj.AMask: iIIEncoding,
1819 ABSET & obj.AMask: rIIIEncoding,
1820 ABSETI & obj.AMask: iIIEncoding,
1821
1822
1823 AWORD & obj.AMask: rawEncoding,
1824
1825
1826 obj.AFUNCDATA: pseudoOpEncoding,
1827 obj.APCDATA: pseudoOpEncoding,
1828 obj.ATEXT: pseudoOpEncoding,
1829 obj.ANOP: pseudoOpEncoding,
1830 obj.ADUFFZERO: pseudoOpEncoding,
1831 obj.ADUFFCOPY: pseudoOpEncoding,
1832 obj.APCALIGN: pseudoOpEncoding,
1833 }
1834
1835
1836 func encodingForAs(as obj.As) (encoding, error) {
1837 if base := as &^ obj.AMask; base != obj.ABaseRISCV && base != 0 {
1838 return badEncoding, fmt.Errorf("encodingForAs: not a RISC-V instruction %s", as)
1839 }
1840 asi := as & obj.AMask
1841 if int(asi) >= len(encodings) {
1842 return badEncoding, fmt.Errorf("encodingForAs: bad RISC-V instruction %s", as)
1843 }
1844 enc := encodings[asi]
1845 if enc.validate == nil {
1846 return badEncoding, fmt.Errorf("encodingForAs: no encoding for instruction %s", as)
1847 }
1848 return enc, nil
1849 }
1850
1851 type instruction struct {
1852 p *obj.Prog
1853 as obj.As
1854 rd uint32
1855 rs1 uint32
1856 rs2 uint32
1857 rs3 uint32
1858 imm int64
1859 funct3 uint32
1860 funct7 uint32
1861 }
1862
1863 func (ins *instruction) String() string {
1864 if ins.p == nil {
1865 return ins.as.String()
1866 }
1867 var suffix string
1868 if ins.p.As != ins.as {
1869 suffix = fmt.Sprintf(" (%v)", ins.as)
1870 }
1871 return fmt.Sprintf("%v%v", ins.p, suffix)
1872 }
1873
1874 func (ins *instruction) encode() (uint32, error) {
1875 enc, err := encodingForAs(ins.as)
1876 if err != nil {
1877 return 0, err
1878 }
1879 if enc.length <= 0 {
1880 return 0, fmt.Errorf("%v: encoding called for a pseudo instruction", ins.as)
1881 }
1882 return enc.encode(ins), nil
1883 }
1884
1885 func (ins *instruction) length() int {
1886 enc, err := encodingForAs(ins.as)
1887 if err != nil {
1888 return 0
1889 }
1890 return enc.length
1891 }
1892
1893 func (ins *instruction) validate(ctxt *obj.Link) {
1894 enc, err := encodingForAs(ins.as)
1895 if err != nil {
1896 ctxt.Diag(err.Error())
1897 return
1898 }
1899 enc.validate(ctxt, ins)
1900 }
1901
1902 func (ins *instruction) usesRegTmp() bool {
1903 return ins.rd == REG_TMP || ins.rs1 == REG_TMP || ins.rs2 == REG_TMP
1904 }
1905
1906
1907 func instructionForProg(p *obj.Prog) *instruction {
1908 ins := &instruction{
1909 as: p.As,
1910 rd: uint32(p.To.Reg),
1911 rs1: uint32(p.Reg),
1912 rs2: uint32(p.From.Reg),
1913 imm: p.From.Offset,
1914 }
1915 if len(p.RestArgs) == 1 {
1916 ins.rs3 = uint32(p.RestArgs[0].Reg)
1917 }
1918 return ins
1919 }
1920
1921
1922
1923
1924 func instructionsForOpImmediate(p *obj.Prog, as obj.As, rs int16) []*instruction {
1925
1926 ins := instructionForProg(p)
1927 ins.as, ins.rs1, ins.rs2 = as, uint32(rs), obj.REG_NONE
1928
1929 low, high, err := Split32BitImmediate(ins.imm)
1930 if err != nil {
1931 p.Ctxt.Diag("%v: constant %d too large", p, ins.imm, err)
1932 return nil
1933 }
1934 if high == 0 {
1935 return []*instruction{ins}
1936 }
1937
1938
1939
1940 if p.Spadj == 0 && ins.as == AADDI && ins.imm >= -(1<<12) && ins.imm < 1<<12-1 {
1941 imm0 := ins.imm / 2
1942 imm1 := ins.imm - imm0
1943
1944
1945
1946 ins.imm = imm0
1947 insADDI := &instruction{as: AADDI, rd: ins.rd, rs1: ins.rd, imm: imm1}
1948 return []*instruction{ins, insADDI}
1949 }
1950
1951
1952
1953
1954 insLUI := &instruction{as: ALUI, rd: REG_TMP, imm: high}
1955 insADDIW := &instruction{as: AADDIW, rd: REG_TMP, rs1: REG_TMP, imm: low}
1956 switch ins.as {
1957 case AADDI:
1958 ins.as = AADD
1959 case AANDI:
1960 ins.as = AAND
1961 case AORI:
1962 ins.as = AOR
1963 case AXORI:
1964 ins.as = AXOR
1965 default:
1966 p.Ctxt.Diag("unsupported immediate instruction %v for splitting", p)
1967 return nil
1968 }
1969 ins.rs2 = REG_TMP
1970 if low == 0 {
1971 return []*instruction{insLUI, ins}
1972 }
1973 return []*instruction{insLUI, insADDIW, ins}
1974 }
1975
1976
1977
1978
1979 func instructionsForLoad(p *obj.Prog, as obj.As, rs int16) []*instruction {
1980 if p.From.Type != obj.TYPE_MEM {
1981 p.Ctxt.Diag("%v requires memory for source", p)
1982 return nil
1983 }
1984
1985 switch as {
1986 case ALD, ALB, ALH, ALW, ALBU, ALHU, ALWU, AFLW, AFLD:
1987 default:
1988 p.Ctxt.Diag("%v: unknown load instruction %v", p, as)
1989 return nil
1990 }
1991
1992
1993 ins := instructionForProg(p)
1994 ins.as, ins.rs1, ins.rs2 = as, uint32(rs), obj.REG_NONE
1995 ins.imm = p.From.Offset
1996
1997 low, high, err := Split32BitImmediate(ins.imm)
1998 if err != nil {
1999 p.Ctxt.Diag("%v: constant %d too large", p, ins.imm)
2000 return nil
2001 }
2002 if high == 0 {
2003 return []*instruction{ins}
2004 }
2005
2006
2007
2008
2009 insLUI := &instruction{as: ALUI, rd: REG_TMP, imm: high}
2010 insADD := &instruction{as: AADD, rd: REG_TMP, rs1: REG_TMP, rs2: ins.rs1}
2011 ins.rs1, ins.imm = REG_TMP, low
2012
2013 return []*instruction{insLUI, insADD, ins}
2014 }
2015
2016
2017
2018
2019 func instructionsForStore(p *obj.Prog, as obj.As, rd int16) []*instruction {
2020 if p.To.Type != obj.TYPE_MEM {
2021 p.Ctxt.Diag("%v requires memory for destination", p)
2022 return nil
2023 }
2024
2025 switch as {
2026 case ASW, ASH, ASB, ASD, AFSW, AFSD:
2027 default:
2028 p.Ctxt.Diag("%v: unknown store instruction %v", p, as)
2029 return nil
2030 }
2031
2032
2033 ins := instructionForProg(p)
2034 ins.as, ins.rd, ins.rs1, ins.rs2 = as, uint32(rd), uint32(p.From.Reg), obj.REG_NONE
2035 ins.imm = p.To.Offset
2036
2037 low, high, err := Split32BitImmediate(ins.imm)
2038 if err != nil {
2039 p.Ctxt.Diag("%v: constant %d too large", p, ins.imm)
2040 return nil
2041 }
2042 if high == 0 {
2043 return []*instruction{ins}
2044 }
2045
2046
2047
2048
2049 insLUI := &instruction{as: ALUI, rd: REG_TMP, imm: high}
2050 insADD := &instruction{as: AADD, rd: REG_TMP, rs1: REG_TMP, rs2: ins.rd}
2051 ins.rd, ins.imm = REG_TMP, low
2052
2053 return []*instruction{insLUI, insADD, ins}
2054 }
2055
2056 func instructionsForTLS(p *obj.Prog, ins *instruction) []*instruction {
2057 insAddTP := &instruction{as: AADD, rd: REG_TMP, rs1: REG_TMP, rs2: REG_TP}
2058
2059 var inss []*instruction
2060 if p.Ctxt.Flag_shared {
2061
2062
2063 insAUIPC := &instruction{as: AAUIPC, rd: REG_TMP}
2064 insLoadTLSOffset := &instruction{as: ALD, rd: REG_TMP, rs1: REG_TMP}
2065 inss = []*instruction{insAUIPC, insLoadTLSOffset, insAddTP, ins}
2066 } else {
2067
2068
2069
2070
2071
2072 insLUI := &instruction{as: ALUI, rd: REG_TMP}
2073 insADDIW := &instruction{as: AADDIW, rd: REG_TMP, rs1: REG_TMP}
2074 inss = []*instruction{insLUI, insADDIW, insAddTP, ins}
2075 }
2076 return inss
2077 }
2078
2079 func instructionsForTLSLoad(p *obj.Prog) []*instruction {
2080 if p.From.Sym.Type != objabi.STLSBSS {
2081 p.Ctxt.Diag("%v: %v is not a TLS symbol", p, p.From.Sym)
2082 return nil
2083 }
2084
2085 ins := instructionForProg(p)
2086 ins.as, ins.rs1, ins.rs2, ins.imm = movToLoad(p.As), REG_TMP, obj.REG_NONE, 0
2087
2088 return instructionsForTLS(p, ins)
2089 }
2090
2091 func instructionsForTLSStore(p *obj.Prog) []*instruction {
2092 if p.To.Sym.Type != objabi.STLSBSS {
2093 p.Ctxt.Diag("%v: %v is not a TLS symbol", p, p.To.Sym)
2094 return nil
2095 }
2096
2097 ins := instructionForProg(p)
2098 ins.as, ins.rd, ins.rs1, ins.rs2, ins.imm = movToStore(p.As), REG_TMP, uint32(p.From.Reg), obj.REG_NONE, 0
2099
2100 return instructionsForTLS(p, ins)
2101 }
2102
2103
2104
2105 func instructionsForMOV(p *obj.Prog) []*instruction {
2106 ins := instructionForProg(p)
2107 inss := []*instruction{ins}
2108
2109 if p.Reg != 0 {
2110 p.Ctxt.Diag("%v: illegal MOV instruction", p)
2111 return nil
2112 }
2113
2114 switch {
2115 case p.From.Type == obj.TYPE_CONST && p.To.Type == obj.TYPE_REG:
2116
2117 if p.As != AMOV {
2118 p.Ctxt.Diag("%v: unsupported constant load", p)
2119 return nil
2120 }
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130 var insSLLI *instruction
2131 if err := immIFits(ins.imm, 32); err != nil {
2132 ctz := bits.TrailingZeros64(uint64(ins.imm))
2133 if err := immIFits(ins.imm>>ctz, 32); err == nil {
2134 ins.imm = ins.imm >> ctz
2135 insSLLI = &instruction{as: ASLLI, rd: ins.rd, rs1: ins.rd, imm: int64(ctz)}
2136 }
2137 }
2138
2139 low, high, err := Split32BitImmediate(ins.imm)
2140 if err != nil {
2141 p.Ctxt.Diag("%v: constant %d too large: %v", p, ins.imm, err)
2142 return nil
2143 }
2144
2145
2146 ins.as, ins.rs1, ins.rs2, ins.imm = AADDI, REG_ZERO, obj.REG_NONE, low
2147
2148
2149 if high != 0 {
2150
2151
2152 insLUI := &instruction{as: ALUI, rd: ins.rd, imm: high}
2153 inss = []*instruction{insLUI}
2154 if low != 0 {
2155 ins.as, ins.rs1 = AADDIW, ins.rd
2156 inss = append(inss, ins)
2157 }
2158 }
2159 if insSLLI != nil {
2160 inss = append(inss, insSLLI)
2161 }
2162
2163 case p.From.Type == obj.TYPE_CONST && p.To.Type != obj.TYPE_REG:
2164 p.Ctxt.Diag("%v: constant load must target register", p)
2165 return nil
2166
2167 case p.From.Type == obj.TYPE_REG && p.To.Type == obj.TYPE_REG:
2168
2169 switch p.As {
2170 case AMOV:
2171 ins.as, ins.rs1, ins.rs2, ins.imm = AADDI, uint32(p.From.Reg), obj.REG_NONE, 0
2172 case AMOVW:
2173 ins.as, ins.rs1, ins.rs2, ins.imm = AADDIW, uint32(p.From.Reg), obj.REG_NONE, 0
2174 case AMOVBU:
2175 ins.as, ins.rs1, ins.rs2, ins.imm = AANDI, uint32(p.From.Reg), obj.REG_NONE, 255
2176 case AMOVF:
2177 ins.as, ins.rs1 = AFSGNJS, uint32(p.From.Reg)
2178 case AMOVD:
2179 ins.as, ins.rs1 = AFSGNJD, uint32(p.From.Reg)
2180 case AMOVB, AMOVH:
2181 if buildcfg.GORISCV64 >= 22 {
2182
2183 ins.as, ins.rs1, ins.rs2 = ASEXTB, uint32(p.From.Reg), obj.REG_NONE
2184 if p.As == AMOVH {
2185 ins.as = ASEXTH
2186 }
2187 } else {
2188
2189 ins.as, ins.rs1, ins.rs2 = ASLLI, uint32(p.From.Reg), obj.REG_NONE
2190 if p.As == AMOVB {
2191 ins.imm = 56
2192 } else if p.As == AMOVH {
2193 ins.imm = 48
2194 }
2195 ins2 := &instruction{as: ASRAI, rd: ins.rd, rs1: ins.rd, imm: ins.imm}
2196 inss = append(inss, ins2)
2197 }
2198 case AMOVHU, AMOVWU:
2199 if buildcfg.GORISCV64 >= 22 {
2200
2201 ins.as, ins.rs1, ins.rs2, ins.imm = AZEXTH, uint32(p.From.Reg), obj.REG_NONE, 0
2202 if p.As == AMOVWU {
2203 ins.as, ins.rs2 = AADDUW, REG_ZERO
2204 }
2205 } else {
2206
2207 ins.as, ins.rs1, ins.rs2 = ASLLI, uint32(p.From.Reg), obj.REG_NONE
2208 if p.As == AMOVHU {
2209 ins.imm = 48
2210 } else if p.As == AMOVWU {
2211 ins.imm = 32
2212 }
2213 ins2 := &instruction{as: ASRLI, rd: ins.rd, rs1: ins.rd, imm: ins.imm}
2214 inss = append(inss, ins2)
2215 }
2216 }
2217
2218 case p.From.Type == obj.TYPE_MEM && p.To.Type == obj.TYPE_REG:
2219
2220 switch p.From.Name {
2221 case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE:
2222
2223 inss = instructionsForLoad(p, movToLoad(p.As), addrToReg(p.From))
2224
2225 case obj.NAME_EXTERN, obj.NAME_STATIC:
2226 if p.From.Sym.Type == objabi.STLSBSS {
2227 return instructionsForTLSLoad(p)
2228 }
2229
2230
2231
2232
2233
2234
2235 insAUIPC := &instruction{as: AAUIPC, rd: ins.rd}
2236 ins.as, ins.rs1, ins.rs2, ins.imm = movToLoad(p.As), ins.rd, obj.REG_NONE, 0
2237 inss = []*instruction{insAUIPC, ins}
2238
2239 default:
2240 p.Ctxt.Diag("unsupported name %d for %v", p.From.Name, p)
2241 return nil
2242 }
2243
2244 case p.From.Type == obj.TYPE_REG && p.To.Type == obj.TYPE_MEM:
2245
2246 switch p.As {
2247 case AMOVBU, AMOVHU, AMOVWU:
2248 p.Ctxt.Diag("%v: unsupported unsigned store", p)
2249 return nil
2250 }
2251 switch p.To.Name {
2252 case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE:
2253
2254 inss = instructionsForStore(p, movToStore(p.As), addrToReg(p.To))
2255
2256 case obj.NAME_EXTERN, obj.NAME_STATIC:
2257 if p.To.Sym.Type == objabi.STLSBSS {
2258 return instructionsForTLSStore(p)
2259 }
2260
2261
2262
2263
2264
2265
2266 insAUIPC := &instruction{as: AAUIPC, rd: REG_TMP}
2267 ins.as, ins.rd, ins.rs1, ins.rs2, ins.imm = movToStore(p.As), REG_TMP, uint32(p.From.Reg), obj.REG_NONE, 0
2268 inss = []*instruction{insAUIPC, ins}
2269
2270 default:
2271 p.Ctxt.Diag("unsupported name %d for %v", p.From.Name, p)
2272 return nil
2273 }
2274
2275 case p.From.Type == obj.TYPE_ADDR && p.To.Type == obj.TYPE_REG:
2276
2277 if p.As != AMOV {
2278 p.Ctxt.Diag("%v: unsupported address load", p)
2279 return nil
2280 }
2281 switch p.From.Name {
2282 case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE:
2283 inss = instructionsForOpImmediate(p, AADDI, addrToReg(p.From))
2284
2285 case obj.NAME_EXTERN, obj.NAME_STATIC:
2286
2287
2288
2289
2290
2291 insAUIPC := &instruction{as: AAUIPC, rd: ins.rd}
2292 ins.as, ins.rs1, ins.rs2, ins.imm = AADDI, ins.rd, obj.REG_NONE, 0
2293 inss = []*instruction{insAUIPC, ins}
2294
2295 default:
2296 p.Ctxt.Diag("unsupported name %d for %v", p.From.Name, p)
2297 return nil
2298 }
2299
2300 case p.From.Type == obj.TYPE_ADDR && p.To.Type != obj.TYPE_REG:
2301 p.Ctxt.Diag("%v: address load must target register", p)
2302 return nil
2303
2304 default:
2305 p.Ctxt.Diag("%v: unsupported MOV", p)
2306 return nil
2307 }
2308
2309 return inss
2310 }
2311
2312
2313 func instructionsForRotate(p *obj.Prog, ins *instruction) []*instruction {
2314 if buildcfg.GORISCV64 >= 22 {
2315
2316 return []*instruction{ins}
2317 }
2318
2319 switch ins.as {
2320 case AROL, AROLW, AROR, ARORW:
2321
2322
2323 sllOp, srlOp := ASLL, ASRL
2324 if ins.as == AROLW || ins.as == ARORW {
2325 sllOp, srlOp = ASLLW, ASRLW
2326 }
2327 shift1, shift2 := sllOp, srlOp
2328 if ins.as == AROR || ins.as == ARORW {
2329 shift1, shift2 = shift2, shift1
2330 }
2331 return []*instruction{
2332 &instruction{as: ASUB, rs1: REG_ZERO, rs2: ins.rs2, rd: REG_TMP},
2333 &instruction{as: shift2, rs1: ins.rs1, rs2: REG_TMP, rd: REG_TMP},
2334 &instruction{as: shift1, rs1: ins.rs1, rs2: ins.rs2, rd: ins.rd},
2335 &instruction{as: AOR, rs1: REG_TMP, rs2: ins.rd, rd: ins.rd},
2336 }
2337
2338 case ARORI, ARORIW:
2339
2340 sllOp, srlOp := ASLLI, ASRLI
2341 sllImm := int64(int8(-ins.imm) & 63)
2342 if ins.as == ARORIW {
2343 sllOp, srlOp = ASLLIW, ASRLIW
2344 sllImm = int64(int8(-ins.imm) & 31)
2345 }
2346 return []*instruction{
2347 &instruction{as: srlOp, rs1: ins.rs1, rd: REG_TMP, imm: ins.imm},
2348 &instruction{as: sllOp, rs1: ins.rs1, rd: ins.rd, imm: sllImm},
2349 &instruction{as: AOR, rs1: REG_TMP, rs2: ins.rd, rd: ins.rd},
2350 }
2351
2352 default:
2353 p.Ctxt.Diag("%v: unknown rotation", p)
2354 return nil
2355 }
2356 }
2357
2358
2359 func instructionsForProg(p *obj.Prog) []*instruction {
2360 ins := instructionForProg(p)
2361 inss := []*instruction{ins}
2362
2363 if len(p.RestArgs) > 1 {
2364 p.Ctxt.Diag("too many source registers")
2365 return nil
2366 }
2367
2368 switch ins.as {
2369 case AJAL, AJALR:
2370 ins.rd, ins.rs1, ins.rs2 = uint32(p.From.Reg), uint32(p.To.Reg), obj.REG_NONE
2371 ins.imm = p.To.Offset
2372
2373 case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ:
2374 switch ins.as {
2375 case ABEQZ:
2376 ins.as, ins.rs1, ins.rs2 = ABEQ, REG_ZERO, uint32(p.From.Reg)
2377 case ABGEZ:
2378 ins.as, ins.rs1, ins.rs2 = ABGE, REG_ZERO, uint32(p.From.Reg)
2379 case ABGT:
2380 ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), uint32(p.Reg)
2381 case ABGTU:
2382 ins.as, ins.rs1, ins.rs2 = ABLTU, uint32(p.From.Reg), uint32(p.Reg)
2383 case ABGTZ:
2384 ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), REG_ZERO
2385 case ABLE:
2386 ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), uint32(p.Reg)
2387 case ABLEU:
2388 ins.as, ins.rs1, ins.rs2 = ABGEU, uint32(p.From.Reg), uint32(p.Reg)
2389 case ABLEZ:
2390 ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), REG_ZERO
2391 case ABLTZ:
2392 ins.as, ins.rs1, ins.rs2 = ABLT, REG_ZERO, uint32(p.From.Reg)
2393 case ABNEZ:
2394 ins.as, ins.rs1, ins.rs2 = ABNE, REG_ZERO, uint32(p.From.Reg)
2395 }
2396 ins.imm = p.To.Offset
2397
2398 case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
2399 inss = instructionsForMOV(p)
2400
2401 case ALW, ALWU, ALH, ALHU, ALB, ALBU, ALD, AFLW, AFLD:
2402 inss = instructionsForLoad(p, ins.as, p.From.Reg)
2403
2404 case ASW, ASH, ASB, ASD, AFSW, AFSD:
2405 inss = instructionsForStore(p, ins.as, p.To.Reg)
2406
2407 case ALRW, ALRD:
2408
2409 ins.funct7 = 2
2410 ins.rs1, ins.rs2 = uint32(p.From.Reg), REG_ZERO
2411
2412 case AADDI, AANDI, AORI, AXORI:
2413 inss = instructionsForOpImmediate(p, ins.as, p.Reg)
2414
2415 case ASCW, ASCD:
2416
2417 ins.funct7 = 1
2418 ins.rd, ins.rs1, ins.rs2 = uint32(p.RegTo2), uint32(p.To.Reg), uint32(p.From.Reg)
2419
2420 case AAMOSWAPW, AAMOSWAPD, AAMOADDW, AAMOADDD, AAMOANDW, AAMOANDD, AAMOORW, AAMOORD,
2421 AAMOXORW, AAMOXORD, AAMOMINW, AAMOMIND, AAMOMINUW, AAMOMINUD, AAMOMAXW, AAMOMAXD, AAMOMAXUW, AAMOMAXUD:
2422
2423 ins.funct7 = 3
2424 ins.rd, ins.rs1, ins.rs2 = uint32(p.RegTo2), uint32(p.To.Reg), uint32(p.From.Reg)
2425
2426 case AECALL, AEBREAK:
2427 insEnc := encode(p.As)
2428 if p.To.Type == obj.TYPE_NONE {
2429 ins.rd = REG_ZERO
2430 }
2431 ins.rs1 = REG_ZERO
2432 ins.imm = insEnc.csr
2433
2434 case ARDCYCLE, ARDTIME, ARDINSTRET:
2435 ins.as = ACSRRS
2436 if p.To.Type == obj.TYPE_NONE {
2437 ins.rd = REG_ZERO
2438 }
2439 ins.rs1 = REG_ZERO
2440 switch p.As {
2441 case ARDCYCLE:
2442 ins.imm = -1024
2443 case ARDTIME:
2444 ins.imm = -1023
2445 case ARDINSTRET:
2446 ins.imm = -1022
2447 }
2448
2449 case AFENCE:
2450 ins.rd, ins.rs1, ins.rs2 = REG_ZERO, REG_ZERO, obj.REG_NONE
2451 ins.imm = 0x0ff
2452
2453 case AFCVTWS, AFCVTLS, AFCVTWUS, AFCVTLUS, AFCVTWD, AFCVTLD, AFCVTWUD, AFCVTLUD:
2454
2455 if p.Scond&rmSuffixBit == 0 {
2456 ins.funct3 = uint32(RM_RTZ)
2457 } else {
2458 ins.funct3 = uint32(p.Scond &^ rmSuffixBit)
2459 }
2460
2461 case AFNES, AFNED:
2462
2463 if p.To.Type != obj.TYPE_REG {
2464 p.Ctxt.Diag("%v needs an integer register output", p)
2465 return nil
2466 }
2467 if ins.as == AFNES {
2468 ins.as = AFEQS
2469 } else {
2470 ins.as = AFEQD
2471 }
2472 ins2 := &instruction{
2473 as: AXORI,
2474 rd: ins.rd,
2475 rs1: ins.rd,
2476 imm: 1,
2477 }
2478 inss = append(inss, ins2)
2479
2480 case AFSQRTS, AFSQRTD:
2481
2482
2483 ins.rs1 = uint32(p.From.Reg)
2484 ins.rs2 = REG_F0
2485
2486 case AFMADDS, AFMSUBS, AFNMADDS, AFNMSUBS,
2487 AFMADDD, AFMSUBD, AFNMADDD, AFNMSUBD:
2488
2489
2490 ins.rs1, ins.rs2 = ins.rs2, ins.rs1
2491
2492 case ANEG, ANEGW:
2493
2494 ins.as = ASUB
2495 if p.As == ANEGW {
2496 ins.as = ASUBW
2497 }
2498 ins.rs1 = REG_ZERO
2499 if ins.rd == obj.REG_NONE {
2500 ins.rd = ins.rs2
2501 }
2502
2503 case ANOT:
2504
2505 ins.as = AXORI
2506 ins.rs1, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE
2507 if ins.rd == obj.REG_NONE {
2508 ins.rd = ins.rs1
2509 }
2510 ins.imm = -1
2511
2512 case ASEQZ:
2513
2514 ins.as = ASLTIU
2515 ins.rs1, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE
2516 ins.imm = 1
2517
2518 case ASNEZ:
2519
2520 ins.as = ASLTU
2521 ins.rs1 = REG_ZERO
2522
2523 case AFABSS:
2524
2525 ins.as = AFSGNJXS
2526 ins.rs1 = uint32(p.From.Reg)
2527
2528 case AFABSD:
2529
2530 ins.as = AFSGNJXD
2531 ins.rs1 = uint32(p.From.Reg)
2532
2533 case AFNEGS:
2534
2535 ins.as = AFSGNJNS
2536 ins.rs1 = uint32(p.From.Reg)
2537
2538 case AFNEGD:
2539
2540 ins.as = AFSGNJND
2541 ins.rs1 = uint32(p.From.Reg)
2542
2543 case AROL, AROLW, AROR, ARORW:
2544 inss = instructionsForRotate(p, ins)
2545
2546 case ARORI:
2547 if ins.imm < 0 || ins.imm > 63 {
2548 p.Ctxt.Diag("%v: immediate out of range 0 to 63", p)
2549 }
2550 inss = instructionsForRotate(p, ins)
2551
2552 case ARORIW:
2553 if ins.imm < 0 || ins.imm > 31 {
2554 p.Ctxt.Diag("%v: immediate out of range 0 to 31", p)
2555 }
2556 inss = instructionsForRotate(p, ins)
2557
2558 case ASLLI, ASRLI, ASRAI:
2559 if ins.imm < 0 || ins.imm > 63 {
2560 p.Ctxt.Diag("%v: immediate out of range 0 to 63", p)
2561 }
2562
2563 case ASLLIW, ASRLIW, ASRAIW:
2564 if ins.imm < 0 || ins.imm > 31 {
2565 p.Ctxt.Diag("%v: immediate out of range 0 to 31", p)
2566 }
2567
2568 case ACLZ, ACLZW, ACTZ, ACTZW, ACPOP, ACPOPW, ASEXTB, ASEXTH, AZEXTH:
2569 ins.rs1, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE
2570
2571 case AORCB, AREV8:
2572 ins.rd, ins.rs1, ins.rs2 = uint32(p.To.Reg), uint32(p.From.Reg), obj.REG_NONE
2573
2574 case AANDN, AORN:
2575 if buildcfg.GORISCV64 >= 22 {
2576
2577 break
2578 }
2579
2580
2581 bitwiseOp, notReg := AAND, ins.rd
2582 if ins.as == AORN {
2583 bitwiseOp = AOR
2584 }
2585 if ins.rs1 == notReg {
2586 notReg = REG_TMP
2587 }
2588 inss = []*instruction{
2589 &instruction{as: AXORI, rs1: ins.rs2, rs2: obj.REG_NONE, rd: notReg, imm: -1},
2590 &instruction{as: bitwiseOp, rs1: ins.rs1, rs2: notReg, rd: ins.rd},
2591 }
2592
2593 case AXNOR:
2594 if buildcfg.GORISCV64 >= 22 {
2595
2596 break
2597 }
2598
2599 ins.as = AXOR
2600 inss = append(inss, &instruction{as: AXORI, rs1: ins.rd, rs2: obj.REG_NONE, rd: ins.rd, imm: -1})
2601 }
2602
2603 for _, ins := range inss {
2604 ins.p = p
2605 }
2606
2607 return inss
2608 }
2609
2610
2611
2612 func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
2613 if ctxt.Retpoline {
2614 ctxt.Diag("-spectre=ret not supported on riscv")
2615 ctxt.Retpoline = false
2616 }
2617
2618
2619
2620 if ctxt.Errors > 0 {
2621 return
2622 }
2623
2624 for p := cursym.Func().Text; p != nil; p = p.Link {
2625 switch p.As {
2626 case AJAL:
2627 if p.Mark&NEED_JAL_RELOC == NEED_JAL_RELOC {
2628 cursym.AddRel(ctxt, obj.Reloc{
2629 Type: objabi.R_RISCV_JAL,
2630 Off: int32(p.Pc),
2631 Siz: 4,
2632 Sym: p.To.Sym,
2633 Add: p.To.Offset,
2634 })
2635 }
2636 case AJALR:
2637 if p.To.Sym != nil {
2638 ctxt.Diag("%v: unexpected AJALR with to symbol", p)
2639 }
2640
2641 case AAUIPC, AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
2642 var addr *obj.Addr
2643 var rt objabi.RelocType
2644 if p.Mark&NEED_CALL_RELOC == NEED_CALL_RELOC {
2645 rt = objabi.R_RISCV_CALL
2646 addr = &p.From
2647 } else if p.Mark&NEED_PCREL_ITYPE_RELOC == NEED_PCREL_ITYPE_RELOC {
2648 rt = objabi.R_RISCV_PCREL_ITYPE
2649 addr = &p.From
2650 } else if p.Mark&NEED_PCREL_STYPE_RELOC == NEED_PCREL_STYPE_RELOC {
2651 rt = objabi.R_RISCV_PCREL_STYPE
2652 addr = &p.To
2653 } else {
2654 break
2655 }
2656 if p.As == AAUIPC {
2657 if p.Link == nil {
2658 ctxt.Diag("AUIPC needing PC-relative reloc missing following instruction")
2659 break
2660 }
2661 addr = &p.RestArgs[0].Addr
2662 }
2663 if addr.Sym == nil {
2664 ctxt.Diag("PC-relative relocation missing symbol")
2665 break
2666 }
2667 if addr.Sym.Type == objabi.STLSBSS {
2668 if ctxt.Flag_shared {
2669 rt = objabi.R_RISCV_TLS_IE
2670 } else {
2671 rt = objabi.R_RISCV_TLS_LE
2672 }
2673 }
2674
2675 cursym.AddRel(ctxt, obj.Reloc{
2676 Type: rt,
2677 Off: int32(p.Pc),
2678 Siz: 8,
2679 Sym: addr.Sym,
2680 Add: addr.Offset,
2681 })
2682
2683 case obj.APCALIGN:
2684 alignedValue := p.From.Offset
2685 v := pcAlignPadLength(p.Pc, alignedValue)
2686 offset := p.Pc
2687 for ; v >= 4; v -= 4 {
2688
2689 cursym.WriteBytes(ctxt, offset, []byte{0x13, 0, 0, 0})
2690 offset += 4
2691 }
2692 continue
2693 }
2694
2695 offset := p.Pc
2696 for _, ins := range instructionsForProg(p) {
2697 if ic, err := ins.encode(); err == nil {
2698 cursym.WriteInt(ctxt, offset, ins.length(), int64(ic))
2699 offset += int64(ins.length())
2700 }
2701 if ins.usesRegTmp() {
2702 p.Mark |= USES_REG_TMP
2703 }
2704 }
2705 }
2706
2707 obj.MarkUnsafePoints(ctxt, cursym.Func().Text, newprog, isUnsafePoint, nil)
2708 }
2709
2710 func isUnsafePoint(p *obj.Prog) bool {
2711 return p.Mark&USES_REG_TMP == USES_REG_TMP || p.From.Reg == REG_TMP || p.To.Reg == REG_TMP || p.Reg == REG_TMP
2712 }
2713
2714 func ParseSuffix(prog *obj.Prog, cond string) (err error) {
2715 switch prog.As {
2716 case AFCVTWS, AFCVTLS, AFCVTWUS, AFCVTLUS, AFCVTWD, AFCVTLD, AFCVTWUD, AFCVTLUD:
2717 prog.Scond, err = rmSuffixEncode(strings.TrimPrefix(cond, "."))
2718 }
2719 return
2720 }
2721
2722 var LinkRISCV64 = obj.LinkArch{
2723 Arch: sys.ArchRISCV64,
2724 Init: buildop,
2725 Preprocess: preprocess,
2726 Assemble: assemble,
2727 Progedit: progedit,
2728 UnaryDst: unaryDst,
2729 DWARFRegisters: RISCV64DWARFRegisters,
2730 }
2731
View as plain text