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