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