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