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