1 // Copyright © 2015 The Go Authors. All rights reserved.
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
33 func buildop(ctxt *obj.Link) {}
35 func jalToSym(ctxt *obj.Link, p *obj.Prog, lr int16) {
37 case obj.ACALL, obj.AJMP, obj.ARET, obj.ADUFFZERO, obj.ADUFFCOPY:
39 ctxt.Diag("unexpected Prog in jalToSym: %v", p)
44 p.Mark |= NEED_JAL_RELOC
45 p.From.Type = obj.TYPE_REG
50 // progedit is called individually for each *obj.Prog. It normalizes instruction
51 // formats and eliminates as many pseudo-instructions as possible.
52 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
54 // Expand binary instructions to ternary ones.
55 if p.Reg == obj.REG_NONE {
57 case AADDI, ASLTI, ASLTIU, AANDI, AORI, AXORI, ASLLI, ASRLI, ASRAI,
58 AADDIW, ASLLIW, ASRLIW, ASRAIW, AADDW, ASUBW, ASLLW, ASRLW, ASRAW,
59 AADD, AAND, AOR, AXOR, ASLL, ASRL, ASUB, ASRA,
60 AMUL, AMULH, AMULHU, AMULHSU, AMULW, ADIV, ADIVU, ADIVW, ADIVUW,
61 AREM, AREMU, AREMW, AREMUW:
66 // Rewrite instructions with constant operands to refer to the immediate
67 // form of the instruction.
68 if p.From.Type == obj.TYPE_CONST {
101 // Turn JMP into JAL ZERO or JALR ZERO.
102 p.From.Type = obj.TYPE_REG
103 p.From.Reg = REG_ZERO
106 case obj.TYPE_BRANCH:
112 case obj.NAME_EXTERN, obj.NAME_STATIC:
113 // Handled in preprocess.
115 ctxt.Diag("unsupported name %d for %v", p.To.Name, p)
118 panic(fmt.Sprintf("unhandled type %+v", p.To.Type))
124 // Handled in preprocess.
127 p.From.Type = obj.TYPE_REG
130 ctxt.Diag("unknown destination type %+v in CALL: %v", p.To.Type, p)
137 // SCALL is the old name for ECALL.
141 // SBREAK is the old name for EBREAK.
145 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 {
146 ctz := bits.TrailingZeros64(uint64(p.From.Offset))
147 val := p.From.Offset >> ctz
148 if int64(int32(val)) == val {
149 // It's ok. We can handle constants with many trailing zeros.
152 // Put >32-bit constants in memory and load them.
153 p.From.Type = obj.TYPE_MEM
154 p.From.Sym = ctxt.Int64Sym(p.From.Offset)
155 p.From.Name = obj.NAME_EXTERN
161 // addrToReg extracts the register from an Addr, handling special Addr.Names.
162 func addrToReg(a obj.Addr) int16 {
164 case obj.NAME_PARAM, obj.NAME_AUTO:
170 // movToLoad converts a MOV mnemonic into the corresponding load instruction.
171 func movToLoad(mnemonic obj.As) obj.As {
192 panic(fmt.Sprintf("%+v is not a MOV", mnemonic))
196 // movToStore converts a MOV mnemonic into the corresponding store instruction.
197 func movToStore(mnemonic obj.As) obj.As {
212 panic(fmt.Sprintf("%+v is not a MOV", mnemonic))
216 // markRelocs marks an obj.Prog that specifies a MOV pseudo-instruction and
217 // requires relocation.
218 func markRelocs(p *obj.Prog) {
220 case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
222 case p.From.Type == obj.TYPE_ADDR && p.To.Type == obj.TYPE_REG:
224 case obj.NAME_EXTERN, obj.NAME_STATIC:
225 p.Mark |= NEED_PCREL_ITYPE_RELOC
227 case p.From.Type == obj.TYPE_MEM && p.To.Type == obj.TYPE_REG:
229 case obj.NAME_EXTERN, obj.NAME_STATIC:
230 p.Mark |= NEED_PCREL_ITYPE_RELOC
232 case p.From.Type == obj.TYPE_REG && p.To.Type == obj.TYPE_MEM:
234 case obj.NAME_EXTERN, obj.NAME_STATIC:
235 p.Mark |= NEED_PCREL_STYPE_RELOC
241 // InvertBranch inverts the condition of a conditional branch.
242 func InvertBranch(as obj.As) obj.As {
277 panic("InvertBranch: not a branch")
281 // containsCall reports whether the symbol contains a CALL (or equivalent)
282 // instruction. Must be called after progedit.
283 func containsCall(sym *obj.LSym) bool {
284 // CALLs are CALL or JAL(R) with link register LR.
285 for p := sym.Func().Text; p != nil; p = p.Link {
287 case obj.ACALL, obj.ADUFFZERO, obj.ADUFFCOPY:
290 if p.From.Type == obj.TYPE_REG && p.From.Reg == REG_LR {
299 // setPCs sets the Pc field in all instructions reachable from p.
300 // It uses pc as the initial value and returns the next available pc.
301 func setPCs(p *obj.Prog, pc int64) int64 {
302 for ; p != nil; p = p.Link {
304 for _, ins := range instructionsForProg(p) {
305 pc += int64(ins.length())
311 // stackOffset updates Addr offsets based on the current stack size.
313 // The stack looks like:
314 // -------------------
319 // -------------------
320 // | Parent RA | SP on function entry
321 // -------------------
327 // -------------------
328 // | RA | SP during function execution
329 // -------------------
331 // FixedFrameSize makes other packages aware of the space allocated for RA.
333 // A nicer version of this diagram can be found on slide 21 of the presentation
334 // attached to https://golang.org/issue/16922#issuecomment-243748180.
335 func stackOffset(a *obj.Addr, stacksize int64) {
338 // Adjust to the top of AUTOs.
339 a.Offset += stacksize
341 // Adjust to the bottom of PARAMs.
342 a.Offset += stacksize + 8
346 // preprocess generates prologue and epilogue code, computes PC-relative branch
347 // and jump offsets, and resolves pseudo-registers.
349 // preprocess is called once per linker symbol.
351 // When preprocess finishes, all instructions in the symbol are either
352 // concrete, real RISC-V instructions or directive pseudo-ops like TEXT,
353 // PCDATA, and FUNCDATA.
354 func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
355 if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
359 // Generate the prologue.
360 text := cursym.Func().Text
361 if text.As != obj.ATEXT {
362 ctxt.Diag("preprocess: found symbol that does not start with TEXT directive")
366 stacksize := text.To.Offset
368 // Historical way to mark NOFRAME.
369 text.From.Sym.Set(obj.AttrNoFrame, true)
373 ctxt.Diag("negative frame size %d - did you mean NOFRAME?", stacksize)
375 if text.From.Sym.NoFrame() {
377 ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", stacksize)
381 if !containsCall(cursym) {
382 text.From.Sym.Set(obj.AttrLeaf, true)
384 // A leaf function with no locals has no frame.
385 text.From.Sym.Set(obj.AttrNoFrame, true)
389 // Save LR unless there is no frame.
390 if !text.From.Sym.NoFrame() {
391 stacksize += ctxt.Arch.FixedFrameSize
394 cursym.Func().Args = text.To.Val.(int32)
395 cursym.Func().Locals = int32(stacksize)
399 if !cursym.Func().Text.From.Sym.NoSplit() {
400 prologue = stacksplit(ctxt, prologue, cursym, newprog, stacksize) // emit split check
404 prologue = ctxt.StartUnsafePoint(prologue, newprog)
407 prologue = obj.Appendp(prologue, newprog)
409 prologue.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
410 prologue.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: -stacksize}
412 // Insert stack adjustment.
413 prologue = obj.Appendp(prologue, newprog)
415 prologue.From = obj.Addr{Type: obj.TYPE_CONST, Offset: -stacksize}
416 prologue.Reg = REG_SP
417 prologue.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_SP}
418 prologue.Spadj = int32(stacksize)
420 prologue = ctxt.EndUnsafePoint(prologue, newprog, -1)
422 // On Linux, in a cgo binary we may get a SIGSETXID signal early on
423 // before the signal stack is set, as glibc doesn't allow us to block
424 // SIGSETXID. So a signal may land on the current stack and clobber
425 // the content below the SP. We store the LR again after the SP is
427 prologue = obj.Appendp(prologue, newprog)
429 prologue.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
430 prologue.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 0}
433 if cursym.Func().Text.From.Sym.Wrapper() {
434 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
436 // MOV g_panic(g), X5
437 // BNE X5, ZERO, adjust
440 // ...rest of function..
442 // MOV panic_argp(X5), X6
443 // ADD $(autosize+FIXED_FRAME), SP, X7
445 // ADD $FIXED_FRAME, SP, X6
446 // MOV X6, panic_argp(X5)
449 // The NOP is needed to give the jumps somewhere to land.
451 ldpanic := obj.Appendp(prologue, newprog)
454 ldpanic.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REGG, Offset: 4 * int64(ctxt.Arch.PtrSize)} // G.panic
455 ldpanic.Reg = obj.REG_NONE
456 ldpanic.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X5}
458 bneadj := obj.Appendp(ldpanic, newprog)
460 bneadj.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X5}
461 bneadj.Reg = REG_ZERO
462 bneadj.To.Type = obj.TYPE_BRANCH
464 endadj := obj.Appendp(bneadj, newprog)
468 for last.Link != nil {
472 getargp := obj.Appendp(last, newprog)
474 getargp.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_X5, Offset: 0} // Panic.argp
475 getargp.Reg = obj.REG_NONE
476 getargp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X6}
478 bneadj.To.SetTarget(getargp)
480 calcargp := obj.Appendp(getargp, newprog)
482 calcargp.From = obj.Addr{Type: obj.TYPE_CONST, Offset: stacksize + ctxt.Arch.FixedFrameSize}
483 calcargp.Reg = REG_SP
484 calcargp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X7}
486 testargp := obj.Appendp(calcargp, newprog)
488 testargp.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X6}
489 testargp.Reg = REG_X7
490 testargp.To.Type = obj.TYPE_BRANCH
491 testargp.To.SetTarget(endadj)
493 adjargp := obj.Appendp(testargp, newprog)
495 adjargp.From = obj.Addr{Type: obj.TYPE_CONST, Offset: int64(ctxt.Arch.PtrSize)}
497 adjargp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X6}
499 setargp := obj.Appendp(adjargp, newprog)
501 setargp.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X6}
502 setargp.Reg = obj.REG_NONE
503 setargp.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_X5, Offset: 0} // Panic.argp
505 godone := obj.Appendp(setargp, newprog)
507 godone.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
508 godone.To.Type = obj.TYPE_BRANCH
509 godone.To.SetTarget(endadj)
512 // Update stack-based offsets.
513 for p := cursym.Func().Text; p != nil; p = p.Link {
514 stackOffset(&p.From, stacksize)
515 stackOffset(&p.To, stacksize)
518 // Additional instruction rewriting.
519 for p := cursym.Func().Text; p != nil; p = p.Link {
521 case obj.AGETCALLERPC:
525 p.From.Type = obj.TYPE_REG
530 p.From.Type = obj.TYPE_MEM
534 case obj.ACALL, obj.ADUFFZERO, obj.ADUFFCOPY:
537 jalToSym(ctxt, p, REG_LR)
544 case obj.NAME_EXTERN, obj.NAME_STATIC:
545 jalToSym(ctxt, p, REG_ZERO)
550 // Replace RET with epilogue.
556 p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 0}
557 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
558 p = obj.Appendp(p, newprog)
561 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: stacksize}
563 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_SP}
564 p.Spadj = int32(-stacksize)
565 p = obj.Appendp(p, newprog)
571 jalToSym(ctxt, p, REG_ZERO)
574 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
576 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
579 // "Add back" the stack removed in the previous instruction.
581 // This is to avoid confusing pctospadj, which sums
582 // Spadj from function entry to each PC, and shouldn't
583 // count adjustments from earlier epilogues, since they
584 // won't affect later PCs.
585 p.Spadj = int32(stacksize)
588 // Refine Spadjs account for adjustment via ADDI instruction.
589 if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_SP && p.From.Type == obj.TYPE_CONST {
590 p.Spadj = int32(-p.From.Offset)
594 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
596 if f.FuncFlag&abi.FuncFlagSPWrite == 0 {
597 f.FuncFlag |= abi.FuncFlagSPWrite
598 if ctxt.Debugvlog || !ctxt.IsAsm {
599 ctxt.Logf("auto-SPWRITE: %s %v\n", cursym.Name, p)
601 ctxt.Diag("invalid auto-SPWRITE in non-assembly")
603 log.Fatalf("bad SPWRITE")
611 for p := cursym.Func().Text; p != nil; p = p.Link {
613 if p.Mark&NEED_JAL_RELOC == NEED_JAL_RELOC {
617 const callTrampSize = 8 // 2 machine instructions.
618 maxTrampSize := int64(callCount * callTrampSize)
620 // Compute instruction addresses. Once we do that, we need to check for
621 // overextended jumps and branches. Within each iteration, Pc differences
622 // are always lower bounds (since the program gets monotonically longer,
623 // a fixed point will be reached). No attempt to handle functions > 2GiB.
625 big, rescan := false, false
626 maxPC := setPCs(cursym.Func().Text, 0)
627 if maxPC+maxTrampSize > (1 << 20) {
631 for p := cursym.Func().Text; p != nil; p = p.Link {
633 case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ:
634 if p.To.Type != obj.TYPE_BRANCH {
635 panic("assemble: instruction with branch-like opcode lacks destination")
637 offset := p.To.Target().Pc - p.Pc
638 if offset < -4096 || 4096 <= offset {
639 // Branch is long. Replace it with a jump.
640 jmp := obj.Appendp(p, newprog)
642 jmp.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
643 jmp.To = obj.Addr{Type: obj.TYPE_BRANCH}
644 jmp.To.SetTarget(p.To.Target())
646 p.As = InvertBranch(p.As)
647 p.To.SetTarget(jmp.Link)
649 // We may have made previous branches too long,
654 // Linker will handle the intersymbol case and trampolines.
655 if p.To.Target() == nil {
659 // This function is going to be too large for JALs
660 // to reach trampolines. Replace with AUIPC+JALR.
661 jmp := obj.Appendp(p, newprog)
664 jmp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
667 p.Mark = (p.Mark &^ NEED_JAL_RELOC) | NEED_CALL_RELOC
668 p.AddRestSource(obj.Addr{Type: obj.TYPE_CONST, Offset: p.To.Offset, Sym: p.To.Sym})
669 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
671 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
676 offset := p.To.Target().Pc - p.Pc
677 if offset < -(1<<20) || (1<<20) <= offset {
678 // Replace with 2-instruction sequence. This assumes
679 // that TMP is not live across J instructions, since
680 // it is reserved by SSA.
681 jmp := obj.Appendp(p, newprog)
684 jmp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
686 // p.From is not generally valid, however will be
687 // fixed up in the next loop.
689 p.From = obj.Addr{Type: obj.TYPE_BRANCH, Sym: p.From.Sym}
690 p.From.SetTarget(p.To.Target())
692 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
704 // Now that there are no long branches, resolve branch and jump targets.
705 // At this point, instruction rewriting which changes the number of
706 // instructions will break everything--don't do it!
707 for p := cursym.Func().Text; p != nil; p = p.Link {
709 case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ:
711 case obj.TYPE_BRANCH:
712 p.To.Type, p.To.Offset = obj.TYPE_CONST, p.To.Target().Pc-p.Pc
714 panic("unhandled type")
718 // Linker will handle the intersymbol case and trampolines.
719 if p.To.Target() != nil {
720 p.To.Type, p.To.Offset = obj.TYPE_CONST, p.To.Target().Pc-p.Pc
724 if p.From.Type == obj.TYPE_BRANCH {
725 low, high, err := Split32BitImmediate(p.From.Target().Pc - p.Pc)
727 ctxt.Diag("%v: jump displacement %d too large", p, p.To.Target().Pc-p.Pc)
729 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high, Sym: cursym}
730 p.Link.To.Offset = low
735 // Validate all instructions - this provides nice error messages.
736 for p := cursym.Func().Text; p != nil; p = p.Link {
737 for _, ins := range instructionsForProg(p) {
743 func stacksplit(ctxt *obj.Link, p *obj.Prog, cursym *obj.LSym, newprog obj.ProgAlloc, framesize int64) *obj.Prog {
744 // Leaf function with no frame is effectively NOSPLIT.
749 if ctxt.Flag_maymorestack != "" {
750 // Save LR and REGCTXT
752 p = ctxt.StartUnsafePoint(p, newprog)
754 // Spill Arguments. This has to happen before we open
755 // any more frame space.
756 p = cursym.Func().SpillRegisterArgs(p, newprog)
759 p = obj.Appendp(p, newprog)
761 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
762 p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: -frameSize}
764 p = obj.Appendp(p, newprog)
766 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: -frameSize}
768 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_SP}
770 // MOV REGCTXT, 8(SP)
771 p = obj.Appendp(p, newprog)
773 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_CTXT}
774 p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 8}
777 p = obj.Appendp(p, newprog)
779 p.To.Type = obj.TYPE_BRANCH
780 // See ../x86/obj6.go
781 p.To.Sym = ctxt.LookupABI(ctxt.Flag_maymorestack, cursym.ABI())
782 jalToSym(ctxt, p, REG_X5)
784 // Restore LR and REGCTXT
786 // MOV 8(SP), REGCTXT
787 p = obj.Appendp(p, newprog)
789 p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 8}
790 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_CTXT}
792 p = obj.Appendp(p, newprog)
794 p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 0}
795 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
797 p = obj.Appendp(p, newprog)
799 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: frameSize}
801 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_SP}
805 p = cursym.Func().UnspillRegisterArgs(p, newprog)
806 p = ctxt.EndUnsafePoint(p, newprog, -1)
809 // Jump back to here after morestack returns.
812 // MOV g_stackguard(g), X6
813 p = obj.Appendp(p, newprog)
815 p.From.Type = obj.TYPE_MEM
817 p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
819 p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
821 p.To.Type = obj.TYPE_REG
824 // Mark the stack bound check and morestack call async nonpreemptible.
825 // If we get preempted here, when resumed the preemption request is
826 // cleared, but we'll still call morestack, which will double the stack
827 // unnecessarily. See issue #35470.
828 p = ctxt.StartUnsafePoint(p, newprog)
830 var to_done, to_more *obj.Prog
832 if framesize <= abi.StackSmall {
834 // // if SP > stackguard { goto done }
835 // BLTU stackguard, SP, done
836 p = obj.Appendp(p, newprog)
838 p.From.Type = obj.TYPE_REG
841 p.To.Type = obj.TYPE_BRANCH
844 // large stack: SP-framesize < stackguard-StackSmall
845 offset := int64(framesize) - abi.StackSmall
846 if framesize > abi.StackBig {
847 // Such a large stack we need to protect against underflow.
848 // The runtime guarantees SP > objabi.StackBig, but
849 // framesize is large enough that SP-framesize may
850 // underflow, causing a direct comparison with the
851 // stack guard to incorrectly succeed. We explicitly
852 // guard against underflow.
854 // MOV $(framesize-StackSmall), X7
855 // BLTU SP, X7, label-of-call-to-morestack
857 p = obj.Appendp(p, newprog)
859 p.From.Type = obj.TYPE_CONST
860 p.From.Offset = offset
861 p.To.Type = obj.TYPE_REG
864 p = obj.Appendp(p, newprog)
866 p.From.Type = obj.TYPE_REG
869 p.To.Type = obj.TYPE_BRANCH
873 // Check against the stack guard. We've ensured this won't underflow.
874 // ADD $-(framesize-StackSmall), SP, X7
875 // // if X7 > stackguard { goto done }
876 // BLTU stackguard, X7, done
877 p = obj.Appendp(p, newprog)
879 p.From.Type = obj.TYPE_CONST
880 p.From.Offset = -offset
882 p.To.Type = obj.TYPE_REG
885 p = obj.Appendp(p, newprog)
887 p.From.Type = obj.TYPE_REG
890 p.To.Type = obj.TYPE_BRANCH
894 // Spill the register args that could be clobbered by the
896 p = ctxt.EmitEntryStackMap(cursym, p, newprog)
897 p = cursym.Func().SpillRegisterArgs(p, newprog)
899 // CALL runtime.morestack(SB)
900 p = obj.Appendp(p, newprog)
902 p.To.Type = obj.TYPE_BRANCH
905 p.To.Sym = ctxt.Lookup("runtime.morestackc")
906 } else if !cursym.Func().Text.From.Sym.NeedCtxt() {
907 p.To.Sym = ctxt.Lookup("runtime.morestack_noctxt")
909 p.To.Sym = ctxt.Lookup("runtime.morestack")
912 to_more.To.SetTarget(p)
914 jalToSym(ctxt, p, REG_X5)
916 // The instructions which unspill regs should be preemptible.
917 p = ctxt.EndUnsafePoint(p, newprog, -1)
918 p = cursym.Func().UnspillRegisterArgs(p, newprog)
921 p = obj.Appendp(p, newprog)
923 p.To = obj.Addr{Type: obj.TYPE_BRANCH}
924 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
925 p.To.SetTarget(startPred.Link)
927 // placeholder for to_done's jump target
928 p = obj.Appendp(p, newprog)
929 p.As = obj.ANOP // zero-width place holder
930 to_done.To.SetTarget(p)
935 // signExtend sign extends val starting at bit bit.
936 func signExtend(val int64, bit uint) int64 {
937 return val << (64 - bit) >> (64 - bit)
940 // Split32BitImmediate splits a signed 32-bit immediate into a signed 20-bit
941 // upper immediate and a signed 12-bit lower immediate to be added to the upper
942 // result. For example, high may be used in LUI and low in a following ADDI to
943 // generate a full 32-bit constant.
944 func Split32BitImmediate(imm int64) (low, high int64, err error) {
945 if err := immIFits(imm, 32); err != nil {
949 // Nothing special needs to be done if the immediate fits in 12 bits.
950 if err := immIFits(imm, 12); err == nil {
956 // The bottom 12 bits will be treated as signed.
958 // If that will result in a negative 12 bit number, add 1 to
959 // our upper bits to adjust for the borrow.
961 // It is not possible for this increment to overflow. To
962 // overflow, the 20 top bits would be 1, and the sign bit for
963 // the low 12 bits would be set, in which case the entire 32
964 // bit pattern fits in a 12 bit signed value.
965 if imm&(1<<11) != 0 {
969 low = signExtend(imm, 12)
970 high = signExtend(high, 20)
972 return low, high, nil
975 func regVal(r, min, max uint32) uint32 {
976 if r < min || r > max {
977 panic(fmt.Sprintf("register out of range, want %d <= %d <= %d", min, r, max))
982 // regI returns an integer register.
983 func regI(r uint32) uint32 {
984 return regVal(r, REG_X0, REG_X31)
987 // regF returns a float register.
988 func regF(r uint32) uint32 {
989 return regVal(r, REG_F0, REG_F31)
992 // regAddr extracts a register from an Addr.
993 func regAddr(a obj.Addr, min, max uint32) uint32 {
994 if a.Type != obj.TYPE_REG {
995 panic(fmt.Sprintf("ill typed: %+v", a))
997 return regVal(uint32(a.Reg), min, max)
1000 // regIAddr extracts the integer register from an Addr.
1001 func regIAddr(a obj.Addr) uint32 {
1002 return regAddr(a, REG_X0, REG_X31)
1005 // regFAddr extracts the float register from an Addr.
1006 func regFAddr(a obj.Addr) uint32 {
1007 return regAddr(a, REG_F0, REG_F31)
1010 // immEven checks that the immediate is a multiple of two. If it
1011 // is not, an error is returned.
1012 func immEven(x int64) error {
1014 return fmt.Errorf("immediate %#x is not a multiple of two", x)
1019 // immIFits checks whether the immediate value x fits in nbits bits
1020 // as a signed integer. If it does not, an error is returned.
1021 func immIFits(x int64, nbits uint) error {
1023 min := int64(-1) << nbits
1024 max := int64(1)<<nbits - 1
1025 if x < min || x > max {
1027 return fmt.Errorf("signed immediate %d must be in range [%d, %d] (%d bits)", x, min, max, nbits)
1029 return fmt.Errorf("signed immediate %#x must be in range [%#x, %#x] (%d bits)", x, min, max, nbits)
1034 // immI extracts the signed integer of the specified size from an immediate.
1035 func immI(as obj.As, imm int64, nbits uint) uint32 {
1036 if err := immIFits(imm, nbits); err != nil {
1037 panic(fmt.Sprintf("%v: %v", as, err))
1042 func wantImmI(ctxt *obj.Link, as obj.As, imm int64, nbits uint) {
1043 if err := immIFits(imm, nbits); err != nil {
1044 ctxt.Diag("%v: %v", as, err)
1048 func wantReg(ctxt *obj.Link, as obj.As, pos string, descr string, r, min, max uint32) {
1049 if r < min || r > max {
1051 if r != obj.REG_NONE {
1052 suffix = fmt.Sprintf(" but got non-%s register %s", descr, RegName(int(r)))
1054 ctxt.Diag("%v: expected %s register in %s position%s", as, descr, pos, suffix)
1058 func wantNoneReg(ctxt *obj.Link, as obj.As, pos string, r uint32) {
1059 if r != obj.REG_NONE {
1060 ctxt.Diag("%v: expected no register in %s but got register %s", as, pos, RegName(int(r)))
1064 // wantIntReg checks that r is an integer register.
1065 func wantIntReg(ctxt *obj.Link, as obj.As, pos string, r uint32) {
1066 wantReg(ctxt, as, pos, "integer", r, REG_X0, REG_X31)
1069 // wantFloatReg checks that r is a floating-point register.
1070 func wantFloatReg(ctxt *obj.Link, as obj.As, pos string, r uint32) {
1071 wantReg(ctxt, as, pos, "float", r, REG_F0, REG_F31)
1074 // wantEvenOffset checks that the offset is a multiple of two.
1075 func wantEvenOffset(ctxt *obj.Link, as obj.As, offset int64) {
1076 if err := immEven(offset); err != nil {
1077 ctxt.Diag("%v: %v", as, err)
1081 func validateRIII(ctxt *obj.Link, ins *instruction) {
1082 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1083 wantIntReg(ctxt, ins.as, "rs1", ins.rs1)
1084 wantIntReg(ctxt, ins.as, "rs2", ins.rs2)
1085 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1088 func validateRFFF(ctxt *obj.Link, ins *instruction) {
1089 wantFloatReg(ctxt, ins.as, "rd", ins.rd)
1090 wantFloatReg(ctxt, ins.as, "rs1", ins.rs1)
1091 wantFloatReg(ctxt, ins.as, "rs2", ins.rs2)
1092 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1095 func validateRFFFF(ctxt *obj.Link, ins *instruction) {
1096 wantFloatReg(ctxt, ins.as, "rd", ins.rd)
1097 wantFloatReg(ctxt, ins.as, "rs1", ins.rs1)
1098 wantFloatReg(ctxt, ins.as, "rs2", ins.rs2)
1099 wantFloatReg(ctxt, ins.as, "rs3", ins.rs3)
1102 func validateRFFI(ctxt *obj.Link, ins *instruction) {
1103 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1104 wantFloatReg(ctxt, ins.as, "rs1", ins.rs1)
1105 wantFloatReg(ctxt, ins.as, "rs2", ins.rs2)
1106 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1109 func validateRFI(ctxt *obj.Link, ins *instruction) {
1110 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1111 wantNoneReg(ctxt, ins.as, "rs1", ins.rs1)
1112 wantFloatReg(ctxt, ins.as, "rs2", ins.rs2)
1113 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1116 func validateRIF(ctxt *obj.Link, ins *instruction) {
1117 wantFloatReg(ctxt, ins.as, "rd", ins.rd)
1118 wantNoneReg(ctxt, ins.as, "rs1", ins.rs1)
1119 wantIntReg(ctxt, ins.as, "rs2", ins.rs2)
1120 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1123 func validateRFF(ctxt *obj.Link, ins *instruction) {
1124 wantFloatReg(ctxt, ins.as, "rd", ins.rd)
1125 wantNoneReg(ctxt, ins.as, "rs1", ins.rs1)
1126 wantFloatReg(ctxt, ins.as, "rs2", ins.rs2)
1127 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1130 func validateII(ctxt *obj.Link, ins *instruction) {
1131 wantImmI(ctxt, ins.as, ins.imm, 12)
1132 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1133 wantIntReg(ctxt, ins.as, "rs1", ins.rs1)
1134 wantNoneReg(ctxt, ins.as, "rs2", ins.rs2)
1135 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1138 func validateIF(ctxt *obj.Link, ins *instruction) {
1139 wantImmI(ctxt, ins.as, ins.imm, 12)
1140 wantFloatReg(ctxt, ins.as, "rd", ins.rd)
1141 wantIntReg(ctxt, ins.as, "rs1", ins.rs1)
1142 wantNoneReg(ctxt, ins.as, "rs2", ins.rs2)
1143 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1146 func validateSI(ctxt *obj.Link, ins *instruction) {
1147 wantImmI(ctxt, ins.as, ins.imm, 12)
1148 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1149 wantIntReg(ctxt, ins.as, "rs1", ins.rs1)
1150 wantNoneReg(ctxt, ins.as, "rs2", ins.rs2)
1151 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1154 func validateSF(ctxt *obj.Link, ins *instruction) {
1155 wantImmI(ctxt, ins.as, ins.imm, 12)
1156 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1157 wantFloatReg(ctxt, ins.as, "rs1", ins.rs1)
1158 wantNoneReg(ctxt, ins.as, "rs2", ins.rs2)
1159 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1162 func validateB(ctxt *obj.Link, ins *instruction) {
1163 // Offsets are multiples of two, so accept 13 bit immediates for the
1164 // 12 bit slot. We implicitly drop the least significant bit in encodeB.
1165 wantEvenOffset(ctxt, ins.as, ins.imm)
1166 wantImmI(ctxt, ins.as, ins.imm, 13)
1167 wantNoneReg(ctxt, ins.as, "rd", ins.rd)
1168 wantIntReg(ctxt, ins.as, "rs1", ins.rs1)
1169 wantIntReg(ctxt, ins.as, "rs2", ins.rs2)
1170 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1173 func validateU(ctxt *obj.Link, ins *instruction) {
1174 wantImmI(ctxt, ins.as, ins.imm, 20)
1175 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1176 wantNoneReg(ctxt, ins.as, "rs1", ins.rs1)
1177 wantNoneReg(ctxt, ins.as, "rs2", ins.rs2)
1178 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1181 func validateJ(ctxt *obj.Link, ins *instruction) {
1182 // Offsets are multiples of two, so accept 21 bit immediates for the
1183 // 20 bit slot. We implicitly drop the least significant bit in encodeJ.
1184 wantEvenOffset(ctxt, ins.as, ins.imm)
1185 wantImmI(ctxt, ins.as, ins.imm, 21)
1186 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1187 wantNoneReg(ctxt, ins.as, "rs1", ins.rs1)
1188 wantNoneReg(ctxt, ins.as, "rs2", ins.rs2)
1189 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1192 func validateRaw(ctxt *obj.Link, ins *instruction) {
1193 // Treat the raw value specially as a 32-bit unsigned integer.
1194 // Nobody wants to enter negative machine code.
1195 if ins.imm < 0 || 1<<32 <= ins.imm {
1196 ctxt.Diag("%v: immediate %d in raw position cannot be larger than 32 bits", ins.as, ins.imm)
1200 // extractBitAndShift extracts the specified bit from the given immediate,
1201 // before shifting it to the requested position and returning it.
1202 func extractBitAndShift(imm uint32, bit, pos int) uint32 {
1203 return ((imm >> bit) & 1) << pos
1206 // encodeR encodes an R-type RISC-V instruction.
1207 func encodeR(as obj.As, rs1, rs2, rd, funct3, funct7 uint32) uint32 {
1210 panic("encodeR: could not encode instruction")
1212 if enc.rs2 != 0 && rs2 != 0 {
1213 panic("encodeR: instruction uses rs2, but rs2 was nonzero")
1215 return funct7<<25 | enc.funct7<<25 | enc.rs2<<20 | rs2<<20 | rs1<<15 | enc.funct3<<12 | funct3<<12 | rd<<7 | enc.opcode
1218 // encodeR4 encodes an R4-type RISC-V instruction.
1219 func encodeR4(as obj.As, rs1, rs2, rs3, rd, funct3, funct2 uint32) uint32 {
1222 panic("encodeR4: could not encode instruction")
1225 panic("encodeR4: instruction uses rs2")
1227 funct2 |= enc.funct7
1229 panic("encodeR4: funct2 requires more than 2 bits")
1231 return rs3<<27 | funct2<<25 | rs2<<20 | rs1<<15 | enc.funct3<<12 | funct3<<12 | rd<<7 | enc.opcode
1234 func encodeRIII(ins *instruction) uint32 {
1235 return encodeR(ins.as, regI(ins.rs1), regI(ins.rs2), regI(ins.rd), ins.funct3, ins.funct7)
1238 func encodeRFFF(ins *instruction) uint32 {
1239 return encodeR(ins.as, regF(ins.rs1), regF(ins.rs2), regF(ins.rd), ins.funct3, ins.funct7)
1242 func encodeRFFFF(ins *instruction) uint32 {
1243 return encodeR4(ins.as, regF(ins.rs1), regF(ins.rs2), regF(ins.rs3), regF(ins.rd), ins.funct3, ins.funct7)
1246 func encodeRFFI(ins *instruction) uint32 {
1247 return encodeR(ins.as, regF(ins.rs1), regF(ins.rs2), regI(ins.rd), ins.funct3, ins.funct7)
1250 func encodeRFI(ins *instruction) uint32 {
1251 return encodeR(ins.as, regF(ins.rs2), 0, regI(ins.rd), ins.funct3, ins.funct7)
1254 func encodeRIF(ins *instruction) uint32 {
1255 return encodeR(ins.as, regI(ins.rs2), 0, regF(ins.rd), ins.funct3, ins.funct7)
1258 func encodeRFF(ins *instruction) uint32 {
1259 return encodeR(ins.as, regF(ins.rs2), 0, regF(ins.rd), ins.funct3, ins.funct7)
1262 // encodeI encodes an I-type RISC-V instruction.
1263 func encodeI(as obj.As, rs1, rd, imm uint32) uint32 {
1266 panic("encodeI: could not encode instruction")
1268 imm |= uint32(enc.csr)
1269 return imm<<20 | rs1<<15 | enc.funct3<<12 | rd<<7 | enc.opcode
1272 func encodeII(ins *instruction) uint32 {
1273 return encodeI(ins.as, regI(ins.rs1), regI(ins.rd), uint32(ins.imm))
1276 func encodeIF(ins *instruction) uint32 {
1277 return encodeI(ins.as, regI(ins.rs1), regF(ins.rd), uint32(ins.imm))
1280 // encodeS encodes an S-type RISC-V instruction.
1281 func encodeS(as obj.As, rs1, rs2, imm uint32) uint32 {
1284 panic("encodeS: could not encode instruction")
1286 return (imm>>5)<<25 | rs2<<20 | rs1<<15 | enc.funct3<<12 | (imm&0x1f)<<7 | enc.opcode
1289 func encodeSI(ins *instruction) uint32 {
1290 return encodeS(ins.as, regI(ins.rd), regI(ins.rs1), uint32(ins.imm))
1293 func encodeSF(ins *instruction) uint32 {
1294 return encodeS(ins.as, regI(ins.rd), regF(ins.rs1), uint32(ins.imm))
1297 // encodeBImmediate encodes an immediate for a B-type RISC-V instruction.
1298 func encodeBImmediate(imm uint32) uint32 {
1299 return (imm>>12)<<31 | ((imm>>5)&0x3f)<<25 | ((imm>>1)&0xf)<<8 | ((imm>>11)&0x1)<<7
1302 // encodeB encodes a B-type RISC-V instruction.
1303 func encodeB(ins *instruction) uint32 {
1304 imm := immI(ins.as, ins.imm, 13)
1305 rs2 := regI(ins.rs1)
1306 rs1 := regI(ins.rs2)
1307 enc := encode(ins.as)
1309 panic("encodeB: could not encode instruction")
1311 return encodeBImmediate(imm) | rs2<<20 | rs1<<15 | enc.funct3<<12 | enc.opcode
1314 // encodeU encodes a U-type RISC-V instruction.
1315 func encodeU(ins *instruction) uint32 {
1316 // The immediates for encodeU are the upper 20 bits of a 32 bit value.
1317 // Rather than have the user/compiler generate a 32 bit constant, the
1318 // bottommost bits of which must all be zero, instead accept just the
1320 imm := immI(ins.as, ins.imm, 20)
1322 enc := encode(ins.as)
1324 panic("encodeU: could not encode instruction")
1326 return imm<<12 | rd<<7 | enc.opcode
1329 // encodeJImmediate encodes an immediate for a J-type RISC-V instruction.
1330 func encodeJImmediate(imm uint32) uint32 {
1331 return (imm>>20)<<31 | ((imm>>1)&0x3ff)<<21 | ((imm>>11)&0x1)<<20 | ((imm>>12)&0xff)<<12
1334 // encodeJ encodes a J-type RISC-V instruction.
1335 func encodeJ(ins *instruction) uint32 {
1336 imm := immI(ins.as, ins.imm, 21)
1338 enc := encode(ins.as)
1340 panic("encodeJ: could not encode instruction")
1342 return encodeJImmediate(imm) | rd<<7 | enc.opcode
1345 // encodeCBImmediate encodes an immediate for a CB-type RISC-V instruction.
1346 func encodeCBImmediate(imm uint32) uint32 {
1347 // Bit order - [8|4:3|7:6|2:1|5]
1348 bits := extractBitAndShift(imm, 8, 7)
1349 bits |= extractBitAndShift(imm, 4, 6)
1350 bits |= extractBitAndShift(imm, 3, 5)
1351 bits |= extractBitAndShift(imm, 7, 4)
1352 bits |= extractBitAndShift(imm, 6, 3)
1353 bits |= extractBitAndShift(imm, 2, 2)
1354 bits |= extractBitAndShift(imm, 1, 1)
1355 bits |= extractBitAndShift(imm, 5, 0)
1356 return (bits>>5)<<10 | (bits&0x1f)<<2
1359 // encodeCJImmediate encodes an immediate for a CJ-type RISC-V instruction.
1360 func encodeCJImmediate(imm uint32) uint32 {
1361 // Bit order - [11|4|9:8|10|6|7|3:1|5]
1362 bits := extractBitAndShift(imm, 11, 10)
1363 bits |= extractBitAndShift(imm, 4, 9)
1364 bits |= extractBitAndShift(imm, 9, 8)
1365 bits |= extractBitAndShift(imm, 8, 7)
1366 bits |= extractBitAndShift(imm, 10, 6)
1367 bits |= extractBitAndShift(imm, 6, 5)
1368 bits |= extractBitAndShift(imm, 7, 4)
1369 bits |= extractBitAndShift(imm, 3, 3)
1370 bits |= extractBitAndShift(imm, 2, 2)
1371 bits |= extractBitAndShift(imm, 1, 1)
1372 bits |= extractBitAndShift(imm, 5, 0)
1376 func encodeRawIns(ins *instruction) uint32 {
1377 // Treat the raw value specially as a 32-bit unsigned integer.
1378 // Nobody wants to enter negative machine code.
1379 if ins.imm < 0 || 1<<32 <= ins.imm {
1380 panic(fmt.Sprintf("immediate %d cannot fit in 32 bits", ins.imm))
1382 return uint32(ins.imm)
1385 func EncodeBImmediate(imm int64) (int64, error) {
1386 if err := immIFits(imm, 13); err != nil {
1389 if err := immEven(imm); err != nil {
1392 return int64(encodeBImmediate(uint32(imm))), nil
1395 func EncodeCBImmediate(imm int64) (int64, error) {
1396 if err := immIFits(imm, 9); err != nil {
1399 if err := immEven(imm); err != nil {
1402 return int64(encodeCBImmediate(uint32(imm))), nil
1405 func EncodeCJImmediate(imm int64) (int64, error) {
1406 if err := immIFits(imm, 12); err != nil {
1409 if err := immEven(imm); err != nil {
1412 return int64(encodeCJImmediate(uint32(imm))), nil
1415 func EncodeIImmediate(imm int64) (int64, error) {
1416 if err := immIFits(imm, 12); err != nil {
1419 return imm << 20, nil
1422 func EncodeJImmediate(imm int64) (int64, error) {
1423 if err := immIFits(imm, 21); err != nil {
1426 if err := immEven(imm); err != nil {
1429 return int64(encodeJImmediate(uint32(imm))), nil
1432 func EncodeSImmediate(imm int64) (int64, error) {
1433 if err := immIFits(imm, 12); err != nil {
1436 return ((imm >> 5) << 25) | ((imm & 0x1f) << 7), nil
1439 func EncodeUImmediate(imm int64) (int64, error) {
1440 if err := immIFits(imm, 20); err != nil {
1443 return imm << 12, nil
1446 type encoding struct {
1447 encode func(*instruction) uint32 // encode returns the machine code for an instruction
1448 validate func(*obj.Link, *instruction) // validate validates an instruction
1449 length int // length of encoded instruction; 0 for pseudo-ops, 4 otherwise
1453 // Encodings have the following naming convention:
1455 // 1. the instruction encoding (R/I/S/B/U/J), in lowercase
1456 // 2. zero or more register operand identifiers (I = integer
1457 // register, F = float register), in uppercase
1458 // 3. the word "Encoding"
1460 // For example, rIIIEncoding indicates an R-type instruction with two
1461 // integer register inputs and an integer register output; sFEncoding
1462 // indicates an S-type instruction with rs2 being a float register.
1464 rIIIEncoding = encoding{encode: encodeRIII, validate: validateRIII, length: 4}
1465 rFFFEncoding = encoding{encode: encodeRFFF, validate: validateRFFF, length: 4}
1466 rFFFFEncoding = encoding{encode: encodeRFFFF, validate: validateRFFFF, length: 4}
1467 rFFIEncoding = encoding{encode: encodeRFFI, validate: validateRFFI, length: 4}
1468 rFIEncoding = encoding{encode: encodeRFI, validate: validateRFI, length: 4}
1469 rIFEncoding = encoding{encode: encodeRIF, validate: validateRIF, length: 4}
1470 rFFEncoding = encoding{encode: encodeRFF, validate: validateRFF, length: 4}
1472 iIEncoding = encoding{encode: encodeII, validate: validateII, length: 4}
1473 iFEncoding = encoding{encode: encodeIF, validate: validateIF, length: 4}
1475 sIEncoding = encoding{encode: encodeSI, validate: validateSI, length: 4}
1476 sFEncoding = encoding{encode: encodeSF, validate: validateSF, length: 4}
1478 bEncoding = encoding{encode: encodeB, validate: validateB, length: 4}
1479 uEncoding = encoding{encode: encodeU, validate: validateU, length: 4}
1480 jEncoding = encoding{encode: encodeJ, validate: validateJ, length: 4}
1482 // rawEncoding encodes a raw instruction byte sequence.
1483 rawEncoding = encoding{encode: encodeRawIns, validate: validateRaw, length: 4}
1485 // pseudoOpEncoding panics if encoding is attempted, but does no validation.
1486 pseudoOpEncoding = encoding{encode: nil, validate: func(*obj.Link, *instruction) {}, length: 0}
1488 // badEncoding is used when an invalid op is encountered.
1489 // An error has already been generated, so let anything else through.
1490 badEncoding = encoding{encode: func(*instruction) uint32 { return 0 }, validate: func(*obj.Link, *instruction) {}, length: 0}
1493 // encodings contains the encodings for RISC-V instructions.
1494 // Instructions are masked with obj.AMask to keep indices small.
1495 var encodings = [ALAST & obj.AMask]encoding{
1499 // 2.4: Integer Computational Instructions
1500 AADDI & obj.AMask: iIEncoding,
1501 ASLTI & obj.AMask: iIEncoding,
1502 ASLTIU & obj.AMask: iIEncoding,
1503 AANDI & obj.AMask: iIEncoding,
1504 AORI & obj.AMask: iIEncoding,
1505 AXORI & obj.AMask: iIEncoding,
1506 ASLLI & obj.AMask: iIEncoding,
1507 ASRLI & obj.AMask: iIEncoding,
1508 ASRAI & obj.AMask: iIEncoding,
1509 ALUI & obj.AMask: uEncoding,
1510 AAUIPC & obj.AMask: uEncoding,
1511 AADD & obj.AMask: rIIIEncoding,
1512 ASLT & obj.AMask: rIIIEncoding,
1513 ASLTU & obj.AMask: rIIIEncoding,
1514 AAND & obj.AMask: rIIIEncoding,
1515 AOR & obj.AMask: rIIIEncoding,
1516 AXOR & obj.AMask: rIIIEncoding,
1517 ASLL & obj.AMask: rIIIEncoding,
1518 ASRL & obj.AMask: rIIIEncoding,
1519 ASUB & obj.AMask: rIIIEncoding,
1520 ASRA & obj.AMask: rIIIEncoding,
1522 // 2.5: Control Transfer Instructions
1523 AJAL & obj.AMask: jEncoding,
1524 AJALR & obj.AMask: iIEncoding,
1525 ABEQ & obj.AMask: bEncoding,
1526 ABNE & obj.AMask: bEncoding,
1527 ABLT & obj.AMask: bEncoding,
1528 ABLTU & obj.AMask: bEncoding,
1529 ABGE & obj.AMask: bEncoding,
1530 ABGEU & obj.AMask: bEncoding,
1532 // 2.6: Load and Store Instructions
1533 ALW & obj.AMask: iIEncoding,
1534 ALWU & obj.AMask: iIEncoding,
1535 ALH & obj.AMask: iIEncoding,
1536 ALHU & obj.AMask: iIEncoding,
1537 ALB & obj.AMask: iIEncoding,
1538 ALBU & obj.AMask: iIEncoding,
1539 ASW & obj.AMask: sIEncoding,
1540 ASH & obj.AMask: sIEncoding,
1541 ASB & obj.AMask: sIEncoding,
1543 // 2.7: Memory Ordering
1544 AFENCE & obj.AMask: iIEncoding,
1546 // 5.2: Integer Computational Instructions (RV64I)
1547 AADDIW & obj.AMask: iIEncoding,
1548 ASLLIW & obj.AMask: iIEncoding,
1549 ASRLIW & obj.AMask: iIEncoding,
1550 ASRAIW & obj.AMask: iIEncoding,
1551 AADDW & obj.AMask: rIIIEncoding,
1552 ASLLW & obj.AMask: rIIIEncoding,
1553 ASRLW & obj.AMask: rIIIEncoding,
1554 ASUBW & obj.AMask: rIIIEncoding,
1555 ASRAW & obj.AMask: rIIIEncoding,
1557 // 5.3: Load and Store Instructions (RV64I)
1558 ALD & obj.AMask: iIEncoding,
1559 ASD & obj.AMask: sIEncoding,
1561 // 7.1: Multiplication Operations
1562 AMUL & obj.AMask: rIIIEncoding,
1563 AMULH & obj.AMask: rIIIEncoding,
1564 AMULHU & obj.AMask: rIIIEncoding,
1565 AMULHSU & obj.AMask: rIIIEncoding,
1566 AMULW & obj.AMask: rIIIEncoding,
1567 ADIV & obj.AMask: rIIIEncoding,
1568 ADIVU & obj.AMask: rIIIEncoding,
1569 AREM & obj.AMask: rIIIEncoding,
1570 AREMU & obj.AMask: rIIIEncoding,
1571 ADIVW & obj.AMask: rIIIEncoding,
1572 ADIVUW & obj.AMask: rIIIEncoding,
1573 AREMW & obj.AMask: rIIIEncoding,
1574 AREMUW & obj.AMask: rIIIEncoding,
1576 // 8.2: Load-Reserved/Store-Conditional
1577 ALRW & obj.AMask: rIIIEncoding,
1578 ALRD & obj.AMask: rIIIEncoding,
1579 ASCW & obj.AMask: rIIIEncoding,
1580 ASCD & obj.AMask: rIIIEncoding,
1582 // 8.3: Atomic Memory Operations
1583 AAMOSWAPW & obj.AMask: rIIIEncoding,
1584 AAMOSWAPD & obj.AMask: rIIIEncoding,
1585 AAMOADDW & obj.AMask: rIIIEncoding,
1586 AAMOADDD & obj.AMask: rIIIEncoding,
1587 AAMOANDW & obj.AMask: rIIIEncoding,
1588 AAMOANDD & obj.AMask: rIIIEncoding,
1589 AAMOORW & obj.AMask: rIIIEncoding,
1590 AAMOORD & obj.AMask: rIIIEncoding,
1591 AAMOXORW & obj.AMask: rIIIEncoding,
1592 AAMOXORD & obj.AMask: rIIIEncoding,
1593 AAMOMAXW & obj.AMask: rIIIEncoding,
1594 AAMOMAXD & obj.AMask: rIIIEncoding,
1595 AAMOMAXUW & obj.AMask: rIIIEncoding,
1596 AAMOMAXUD & obj.AMask: rIIIEncoding,
1597 AAMOMINW & obj.AMask: rIIIEncoding,
1598 AAMOMIND & obj.AMask: rIIIEncoding,
1599 AAMOMINUW & obj.AMask: rIIIEncoding,
1600 AAMOMINUD & obj.AMask: rIIIEncoding,
1602 // 10.1: Base Counters and Timers
1603 ARDCYCLE & obj.AMask: iIEncoding,
1604 ARDTIME & obj.AMask: iIEncoding,
1605 ARDINSTRET & obj.AMask: iIEncoding,
1607 // 11.5: Single-Precision Load and Store Instructions
1608 AFLW & obj.AMask: iFEncoding,
1609 AFSW & obj.AMask: sFEncoding,
1611 // 11.6: Single-Precision Floating-Point Computational Instructions
1612 AFADDS & obj.AMask: rFFFEncoding,
1613 AFSUBS & obj.AMask: rFFFEncoding,
1614 AFMULS & obj.AMask: rFFFEncoding,
1615 AFDIVS & obj.AMask: rFFFEncoding,
1616 AFMINS & obj.AMask: rFFFEncoding,
1617 AFMAXS & obj.AMask: rFFFEncoding,
1618 AFSQRTS & obj.AMask: rFFFEncoding,
1619 AFMADDS & obj.AMask: rFFFFEncoding,
1620 AFMSUBS & obj.AMask: rFFFFEncoding,
1621 AFNMSUBS & obj.AMask: rFFFFEncoding,
1622 AFNMADDS & obj.AMask: rFFFFEncoding,
1624 // 11.7: Single-Precision Floating-Point Conversion and Move Instructions
1625 AFCVTWS & obj.AMask: rFIEncoding,
1626 AFCVTLS & obj.AMask: rFIEncoding,
1627 AFCVTSW & obj.AMask: rIFEncoding,
1628 AFCVTSL & obj.AMask: rIFEncoding,
1629 AFCVTWUS & obj.AMask: rFIEncoding,
1630 AFCVTLUS & obj.AMask: rFIEncoding,
1631 AFCVTSWU & obj.AMask: rIFEncoding,
1632 AFCVTSLU & obj.AMask: rIFEncoding,
1633 AFSGNJS & obj.AMask: rFFFEncoding,
1634 AFSGNJNS & obj.AMask: rFFFEncoding,
1635 AFSGNJXS & obj.AMask: rFFFEncoding,
1636 AFMVXS & obj.AMask: rFIEncoding,
1637 AFMVSX & obj.AMask: rIFEncoding,
1638 AFMVXW & obj.AMask: rFIEncoding,
1639 AFMVWX & obj.AMask: rIFEncoding,
1641 // 11.8: Single-Precision Floating-Point Compare Instructions
1642 AFEQS & obj.AMask: rFFIEncoding,
1643 AFLTS & obj.AMask: rFFIEncoding,
1644 AFLES & obj.AMask: rFFIEncoding,
1646 // 11.9: Single-Precision Floating-Point Classify Instruction
1647 AFCLASSS & obj.AMask: rFIEncoding,
1649 // 12.3: Double-Precision Load and Store Instructions
1650 AFLD & obj.AMask: iFEncoding,
1651 AFSD & obj.AMask: sFEncoding,
1653 // 12.4: Double-Precision Floating-Point Computational Instructions
1654 AFADDD & obj.AMask: rFFFEncoding,
1655 AFSUBD & obj.AMask: rFFFEncoding,
1656 AFMULD & obj.AMask: rFFFEncoding,
1657 AFDIVD & obj.AMask: rFFFEncoding,
1658 AFMIND & obj.AMask: rFFFEncoding,
1659 AFMAXD & obj.AMask: rFFFEncoding,
1660 AFSQRTD & obj.AMask: rFFFEncoding,
1661 AFMADDD & obj.AMask: rFFFFEncoding,
1662 AFMSUBD & obj.AMask: rFFFFEncoding,
1663 AFNMSUBD & obj.AMask: rFFFFEncoding,
1664 AFNMADDD & obj.AMask: rFFFFEncoding,
1666 // 12.5: Double-Precision Floating-Point Conversion and Move Instructions
1667 AFCVTWD & obj.AMask: rFIEncoding,
1668 AFCVTLD & obj.AMask: rFIEncoding,
1669 AFCVTDW & obj.AMask: rIFEncoding,
1670 AFCVTDL & obj.AMask: rIFEncoding,
1671 AFCVTWUD & obj.AMask: rFIEncoding,
1672 AFCVTLUD & obj.AMask: rFIEncoding,
1673 AFCVTDWU & obj.AMask: rIFEncoding,
1674 AFCVTDLU & obj.AMask: rIFEncoding,
1675 AFCVTSD & obj.AMask: rFFEncoding,
1676 AFCVTDS & obj.AMask: rFFEncoding,
1677 AFSGNJD & obj.AMask: rFFFEncoding,
1678 AFSGNJND & obj.AMask: rFFFEncoding,
1679 AFSGNJXD & obj.AMask: rFFFEncoding,
1680 AFMVXD & obj.AMask: rFIEncoding,
1681 AFMVDX & obj.AMask: rIFEncoding,
1683 // 12.6: Double-Precision Floating-Point Compare Instructions
1684 AFEQD & obj.AMask: rFFIEncoding,
1685 AFLTD & obj.AMask: rFFIEncoding,
1686 AFLED & obj.AMask: rFFIEncoding,
1688 // 12.7: Double-Precision Floating-Point Classify Instruction
1689 AFCLASSD & obj.AMask: rFIEncoding,
1693 // 3.2.1: Environment Call and Breakpoint
1694 AECALL & obj.AMask: iIEncoding,
1695 AEBREAK & obj.AMask: iIEncoding,
1698 AWORD & obj.AMask: rawEncoding,
1700 // Pseudo-operations
1701 obj.AFUNCDATA: pseudoOpEncoding,
1702 obj.APCDATA: pseudoOpEncoding,
1703 obj.ATEXT: pseudoOpEncoding,
1704 obj.ANOP: pseudoOpEncoding,
1705 obj.ADUFFZERO: pseudoOpEncoding,
1706 obj.ADUFFCOPY: pseudoOpEncoding,
1709 // encodingForAs returns the encoding for an obj.As.
1710 func encodingForAs(as obj.As) (encoding, error) {
1711 if base := as &^ obj.AMask; base != obj.ABaseRISCV && base != 0 {
1712 return badEncoding, fmt.Errorf("encodingForAs: not a RISC-V instruction %s", as)
1714 asi := as & obj.AMask
1715 if int(asi) >= len(encodings) {
1716 return badEncoding, fmt.Errorf("encodingForAs: bad RISC-V instruction %s", as)
1718 enc := encodings[asi]
1719 if enc.validate == nil {
1720 return badEncoding, fmt.Errorf("encodingForAs: no encoding for instruction %s", as)
1725 type instruction struct {
1726 as obj.As // Assembler opcode
1727 rd uint32 // Destination register
1728 rs1 uint32 // Source register 1
1729 rs2 uint32 // Source register 2
1730 rs3 uint32 // Source register 3
1731 imm int64 // Immediate
1732 funct3 uint32 // Function 3
1733 funct7 uint32 // Function 7 (or Function 2)
1736 func (ins *instruction) encode() (uint32, error) {
1737 enc, err := encodingForAs(ins.as)
1741 if enc.length <= 0 {
1742 return 0, fmt.Errorf("%v: encoding called for a pseudo instruction", ins.as)
1744 return enc.encode(ins), nil
1747 func (ins *instruction) length() int {
1748 enc, err := encodingForAs(ins.as)
1755 func (ins *instruction) validate(ctxt *obj.Link) {
1756 enc, err := encodingForAs(ins.as)
1758 ctxt.Diag(err.Error())
1761 enc.validate(ctxt, ins)
1764 func (ins *instruction) usesRegTmp() bool {
1765 return ins.rd == REG_TMP || ins.rs1 == REG_TMP || ins.rs2 == REG_TMP
1768 // instructionForProg returns the default *obj.Prog to instruction mapping.
1769 func instructionForProg(p *obj.Prog) *instruction {
1770 ins := &instruction{
1772 rd: uint32(p.To.Reg),
1774 rs2: uint32(p.From.Reg),
1777 if len(p.RestArgs) == 1 {
1778 ins.rs3 = uint32(p.RestArgs[0].Reg)
1783 // instructionsForOpImmediate returns the machine instructions for an immediate
1784 // operand. The instruction is specified by as and the source register is
1785 // specified by rs, instead of the obj.Prog.
1786 func instructionsForOpImmediate(p *obj.Prog, as obj.As, rs int16) []*instruction {
1787 // <opi> $imm, REG, TO
1788 ins := instructionForProg(p)
1789 ins.as, ins.rs1, ins.rs2 = as, uint32(rs), obj.REG_NONE
1791 low, high, err := Split32BitImmediate(ins.imm)
1793 p.Ctxt.Diag("%v: constant %d too large", p, ins.imm, err)
1797 return []*instruction{ins}
1800 // Split into two additions, if possible.
1801 // Do not split SP-writing instructions, as otherwise the recorded SP delta may be wrong.
1802 if p.Spadj == 0 && ins.as == AADDI && ins.imm >= -(1<<12) && ins.imm < 1<<12-1 {
1804 imm1 := ins.imm - imm0
1806 // ADDI $(imm/2), REG, TO
1807 // ADDI $(imm-imm/2), TO, TO
1809 insADDI := &instruction{as: AADDI, rd: ins.rd, rs1: ins.rd, imm: imm1}
1810 return []*instruction{ins, insADDI}
1814 // ADDIW $low, TMP, TMP
1815 // <op> TMP, REG, TO
1816 insLUI := &instruction{as: ALUI, rd: REG_TMP, imm: high}
1817 insADDIW := &instruction{as: AADDIW, rd: REG_TMP, rs1: REG_TMP, imm: low}
1828 p.Ctxt.Diag("unsupported immediate instruction %v for splitting", p)
1833 return []*instruction{insLUI, ins}
1835 return []*instruction{insLUI, insADDIW, ins}
1838 // instructionsForLoad returns the machine instructions for a load. The load
1839 // instruction is specified by as and the base/source register is specified
1840 // by rs, instead of the obj.Prog.
1841 func instructionsForLoad(p *obj.Prog, as obj.As, rs int16) []*instruction {
1842 if p.From.Type != obj.TYPE_MEM {
1843 p.Ctxt.Diag("%v requires memory for source", p)
1848 case ALD, ALB, ALH, ALW, ALBU, ALHU, ALWU, AFLW, AFLD:
1850 p.Ctxt.Diag("%v: unknown load instruction %v", p, as)
1854 // <load> $imm, REG, TO (load $imm+(REG), TO)
1855 ins := instructionForProg(p)
1856 ins.as, ins.rs1, ins.rs2 = as, uint32(rs), obj.REG_NONE
1857 ins.imm = p.From.Offset
1859 low, high, err := Split32BitImmediate(ins.imm)
1861 p.Ctxt.Diag("%v: constant %d too large", p, ins.imm)
1865 return []*instruction{ins}
1869 // ADD TMP, REG, TMP
1870 // <load> $low, TMP, TO
1871 insLUI := &instruction{as: ALUI, rd: REG_TMP, imm: high}
1872 insADD := &instruction{as: AADD, rd: REG_TMP, rs1: REG_TMP, rs2: ins.rs1}
1873 ins.rs1, ins.imm = REG_TMP, low
1875 return []*instruction{insLUI, insADD, ins}
1878 // instructionsForStore returns the machine instructions for a store. The store
1879 // instruction is specified by as and the target/source register is specified
1880 // by rd, instead of the obj.Prog.
1881 func instructionsForStore(p *obj.Prog, as obj.As, rd int16) []*instruction {
1882 if p.To.Type != obj.TYPE_MEM {
1883 p.Ctxt.Diag("%v requires memory for destination", p)
1888 case ASW, ASH, ASB, ASD, AFSW, AFSD:
1890 p.Ctxt.Diag("%v: unknown store instruction %v", p, as)
1894 // <store> $imm, REG, TO (store $imm+(TO), REG)
1895 ins := instructionForProg(p)
1896 ins.as, ins.rd, ins.rs1, ins.rs2 = as, uint32(rd), uint32(p.From.Reg), obj.REG_NONE
1897 ins.imm = p.To.Offset
1899 low, high, err := Split32BitImmediate(ins.imm)
1901 p.Ctxt.Diag("%v: constant %d too large", p, ins.imm)
1905 return []*instruction{ins}
1910 // <store> $low, REG, TMP
1911 insLUI := &instruction{as: ALUI, rd: REG_TMP, imm: high}
1912 insADD := &instruction{as: AADD, rd: REG_TMP, rs1: REG_TMP, rs2: ins.rd}
1913 ins.rd, ins.imm = REG_TMP, low
1915 return []*instruction{insLUI, insADD, ins}
1918 func instructionsForTLS(p *obj.Prog, ins *instruction) []*instruction {
1919 insAddTP := &instruction{as: AADD, rd: REG_TMP, rs1: REG_TMP, rs2: REG_TP}
1921 var inss []*instruction
1922 if p.Ctxt.Flag_shared {
1923 // TLS initial-exec mode - load TLS offset from GOT, add the thread pointer
1924 // register, then load from or store to the resulting memory location.
1925 insAUIPC := &instruction{as: AAUIPC, rd: REG_TMP}
1926 insLoadTLSOffset := &instruction{as: ALD, rd: REG_TMP, rs1: REG_TMP}
1927 inss = []*instruction{insAUIPC, insLoadTLSOffset, insAddTP, ins}
1929 // TLS local-exec mode - load upper TLS offset, add the lower TLS offset,
1930 // add the thread pointer register, then load from or store to the resulting
1931 // memory location. Note that this differs from the suggested three
1932 // instruction sequence, as the Go linker does not currently have an
1933 // easy way to handle relocation across 12 bytes of machine code.
1934 insLUI := &instruction{as: ALUI, rd: REG_TMP}
1935 insADDIW := &instruction{as: AADDIW, rd: REG_TMP, rs1: REG_TMP}
1936 inss = []*instruction{insLUI, insADDIW, insAddTP, ins}
1941 func instructionsForTLSLoad(p *obj.Prog) []*instruction {
1942 if p.From.Sym.Type != objabi.STLSBSS {
1943 p.Ctxt.Diag("%v: %v is not a TLS symbol", p, p.From.Sym)
1947 ins := instructionForProg(p)
1948 ins.as, ins.rs1, ins.rs2, ins.imm = movToLoad(p.As), REG_TMP, obj.REG_NONE, 0
1950 return instructionsForTLS(p, ins)
1953 func instructionsForTLSStore(p *obj.Prog) []*instruction {
1954 if p.To.Sym.Type != objabi.STLSBSS {
1955 p.Ctxt.Diag("%v: %v is not a TLS symbol", p, p.To.Sym)
1959 ins := instructionForProg(p)
1960 ins.as, ins.rd, ins.rs1, ins.rs2, ins.imm = movToStore(p.As), REG_TMP, uint32(p.From.Reg), obj.REG_NONE, 0
1962 return instructionsForTLS(p, ins)
1965 // instructionsForMOV returns the machine instructions for an *obj.Prog that
1966 // uses a MOV pseudo-instruction.
1967 func instructionsForMOV(p *obj.Prog) []*instruction {
1968 ins := instructionForProg(p)
1969 inss := []*instruction{ins}
1972 p.Ctxt.Diag("%v: illegal MOV instruction", p)
1977 case p.From.Type == obj.TYPE_CONST && p.To.Type == obj.TYPE_REG:
1978 // Handle constant to register moves.
1980 p.Ctxt.Diag("%v: unsupported constant load", p)
1984 // For constants larger than 32 bits in size that have trailing zeros,
1985 // use the value with the trailing zeros removed and then use a SLLI
1986 // instruction to restore the original constant.
1988 // MOV $0x8000000000000000, X10
1991 // SLLI $63, X10, X10
1992 var insSLLI *instruction
1993 if err := immIFits(ins.imm, 32); err != nil {
1994 ctz := bits.TrailingZeros64(uint64(ins.imm))
1995 if err := immIFits(ins.imm>>ctz, 32); err == nil {
1996 ins.imm = ins.imm >> ctz
1997 insSLLI = &instruction{as: ASLLI, rd: ins.rd, rs1: ins.rd, imm: int64(ctz)}
2001 low, high, err := Split32BitImmediate(ins.imm)
2003 p.Ctxt.Diag("%v: constant %d too large: %v", p, ins.imm, err)
2007 // MOV $c, R -> ADD $c, ZERO, R
2008 ins.as, ins.rs1, ins.rs2, ins.imm = AADDI, REG_ZERO, obj.REG_NONE, low
2010 // LUI is only necessary if the constant does not fit in 12 bits.
2012 // LUI top20bits(c), R
2013 // ADD bottom12bits(c), R, R
2014 insLUI := &instruction{as: ALUI, rd: ins.rd, imm: high}
2015 inss = []*instruction{insLUI}
2017 ins.as, ins.rs1 = AADDIW, ins.rd
2018 inss = append(inss, ins)
2022 inss = append(inss, insSLLI)
2025 case p.From.Type == obj.TYPE_CONST && p.To.Type != obj.TYPE_REG:
2026 p.Ctxt.Diag("%v: constant load must target register", p)
2029 case p.From.Type == obj.TYPE_REG && p.To.Type == obj.TYPE_REG:
2030 // Handle register to register moves.
2032 case AMOV: // MOV Ra, Rb -> ADDI $0, Ra, Rb
2033 ins.as, ins.rs1, ins.rs2, ins.imm = AADDI, uint32(p.From.Reg), obj.REG_NONE, 0
2034 case AMOVW: // MOVW Ra, Rb -> ADDIW $0, Ra, Rb
2035 ins.as, ins.rs1, ins.rs2, ins.imm = AADDIW, uint32(p.From.Reg), obj.REG_NONE, 0
2036 case AMOVBU: // MOVBU Ra, Rb -> ANDI $255, Ra, Rb
2037 ins.as, ins.rs1, ins.rs2, ins.imm = AANDI, uint32(p.From.Reg), obj.REG_NONE, 255
2038 case AMOVF: // MOVF Ra, Rb -> FSGNJS Ra, Ra, Rb
2039 ins.as, ins.rs1 = AFSGNJS, uint32(p.From.Reg)
2040 case AMOVD: // MOVD Ra, Rb -> FSGNJD Ra, Ra, Rb
2041 ins.as, ins.rs1 = AFSGNJD, uint32(p.From.Reg)
2043 // Use SLLI/SRAI to extend.
2044 ins.as, ins.rs1, ins.rs2 = ASLLI, uint32(p.From.Reg), obj.REG_NONE
2047 } else if p.As == AMOVH {
2050 ins2 := &instruction{as: ASRAI, rd: ins.rd, rs1: ins.rd, imm: ins.imm}
2051 inss = append(inss, ins2)
2052 case AMOVHU, AMOVWU:
2053 // Use SLLI/SRLI to extend.
2054 ins.as, ins.rs1, ins.rs2 = ASLLI, uint32(p.From.Reg), obj.REG_NONE
2057 } else if p.As == AMOVWU {
2060 ins2 := &instruction{as: ASRLI, rd: ins.rd, rs1: ins.rd, imm: ins.imm}
2061 inss = append(inss, ins2)
2064 case p.From.Type == obj.TYPE_MEM && p.To.Type == obj.TYPE_REG:
2065 // Memory to register loads.
2066 switch p.From.Name {
2067 case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE:
2068 // MOV c(Rs), Rd -> L $c, Rs, Rd
2069 inss = instructionsForLoad(p, movToLoad(p.As), addrToReg(p.From))
2071 case obj.NAME_EXTERN, obj.NAME_STATIC:
2072 if p.From.Sym.Type == objabi.STLSBSS {
2073 return instructionsForTLSLoad(p)
2076 // Note that the values for $off_hi and $off_lo are currently
2077 // zero and will be assigned during relocation.
2079 // AUIPC $off_hi, Rd
2080 // L $off_lo, Rd, Rd
2081 insAUIPC := &instruction{as: AAUIPC, rd: ins.rd}
2082 ins.as, ins.rs1, ins.rs2, ins.imm = movToLoad(p.As), ins.rd, obj.REG_NONE, 0
2083 inss = []*instruction{insAUIPC, ins}
2086 p.Ctxt.Diag("unsupported name %d for %v", p.From.Name, p)
2090 case p.From.Type == obj.TYPE_REG && p.To.Type == obj.TYPE_MEM:
2091 // Register to memory stores.
2093 case AMOVBU, AMOVHU, AMOVWU:
2094 p.Ctxt.Diag("%v: unsupported unsigned store", p)
2098 case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE:
2099 // MOV Rs, c(Rd) -> S $c, Rs, Rd
2100 inss = instructionsForStore(p, movToStore(p.As), addrToReg(p.To))
2102 case obj.NAME_EXTERN, obj.NAME_STATIC:
2103 if p.To.Sym.Type == objabi.STLSBSS {
2104 return instructionsForTLSStore(p)
2107 // Note that the values for $off_hi and $off_lo are currently
2108 // zero and will be assigned during relocation.
2110 // AUIPC $off_hi, Rtmp
2111 // S $off_lo, Rtmp, Rd
2112 insAUIPC := &instruction{as: AAUIPC, rd: REG_TMP}
2113 ins.as, ins.rd, ins.rs1, ins.rs2, ins.imm = movToStore(p.As), REG_TMP, uint32(p.From.Reg), obj.REG_NONE, 0
2114 inss = []*instruction{insAUIPC, ins}
2117 p.Ctxt.Diag("unsupported name %d for %v", p.From.Name, p)
2121 case p.From.Type == obj.TYPE_ADDR && p.To.Type == obj.TYPE_REG:
2122 // MOV $sym+off(SP/SB), R
2124 p.Ctxt.Diag("%v: unsupported address load", p)
2127 switch p.From.Name {
2128 case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE:
2129 inss = instructionsForOpImmediate(p, AADDI, addrToReg(p.From))
2131 case obj.NAME_EXTERN, obj.NAME_STATIC:
2132 // Note that the values for $off_hi and $off_lo are currently
2133 // zero and will be assigned during relocation.
2137 insAUIPC := &instruction{as: AAUIPC, rd: ins.rd}
2138 ins.as, ins.rs1, ins.rs2, ins.imm = AADDI, ins.rd, obj.REG_NONE, 0
2139 inss = []*instruction{insAUIPC, ins}
2142 p.Ctxt.Diag("unsupported name %d for %v", p.From.Name, p)
2146 case p.From.Type == obj.TYPE_ADDR && p.To.Type != obj.TYPE_REG:
2147 p.Ctxt.Diag("%v: address load must target register", p)
2151 p.Ctxt.Diag("%v: unsupported MOV", p)
2158 // instructionsForProg returns the machine instructions for an *obj.Prog.
2159 func instructionsForProg(p *obj.Prog) []*instruction {
2160 ins := instructionForProg(p)
2161 inss := []*instruction{ins}
2163 if len(p.RestArgs) > 1 {
2164 p.Ctxt.Diag("too many source registers")
2170 ins.rd, ins.rs1, ins.rs2 = uint32(p.From.Reg), uint32(p.To.Reg), obj.REG_NONE
2171 ins.imm = p.To.Offset
2173 case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ:
2176 ins.as, ins.rs1, ins.rs2 = ABEQ, REG_ZERO, uint32(p.From.Reg)
2178 ins.as, ins.rs1, ins.rs2 = ABGE, REG_ZERO, uint32(p.From.Reg)
2180 ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), uint32(p.Reg)
2182 ins.as, ins.rs1, ins.rs2 = ABLTU, uint32(p.From.Reg), uint32(p.Reg)
2184 ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), REG_ZERO
2186 ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), uint32(p.Reg)
2188 ins.as, ins.rs1, ins.rs2 = ABGEU, uint32(p.From.Reg), uint32(p.Reg)
2190 ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), REG_ZERO
2192 ins.as, ins.rs1, ins.rs2 = ABLT, REG_ZERO, uint32(p.From.Reg)
2194 ins.as, ins.rs1, ins.rs2 = ABNE, REG_ZERO, uint32(p.From.Reg)
2196 ins.imm = p.To.Offset
2198 case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
2199 return instructionsForMOV(p)
2201 case ALW, ALWU, ALH, ALHU, ALB, ALBU, ALD, AFLW, AFLD:
2202 return instructionsForLoad(p, ins.as, p.From.Reg)
2204 case ASW, ASH, ASB, ASD, AFSW, AFSD:
2205 return instructionsForStore(p, ins.as, p.To.Reg)
2208 // Set aq to use acquire access ordering
2210 ins.rs1, ins.rs2 = uint32(p.From.Reg), REG_ZERO
2212 case AADDI, AANDI, AORI, AXORI:
2213 inss = instructionsForOpImmediate(p, ins.as, p.Reg)
2216 // Set release access ordering
2218 ins.rd, ins.rs1, ins.rs2 = uint32(p.RegTo2), uint32(p.To.Reg), uint32(p.From.Reg)
2220 case AAMOSWAPW, AAMOSWAPD, AAMOADDW, AAMOADDD, AAMOANDW, AAMOANDD, AAMOORW, AAMOORD,
2221 AAMOXORW, AAMOXORD, AAMOMINW, AAMOMIND, AAMOMINUW, AAMOMINUD, AAMOMAXW, AAMOMAXD, AAMOMAXUW, AAMOMAXUD:
2222 // Set aqrl to use acquire & release access ordering
2224 ins.rd, ins.rs1, ins.rs2 = uint32(p.RegTo2), uint32(p.To.Reg), uint32(p.From.Reg)
2226 case AECALL, AEBREAK, ARDCYCLE, ARDTIME, ARDINSTRET:
2227 insEnc := encode(p.As)
2228 if p.To.Type == obj.TYPE_NONE {
2232 ins.imm = insEnc.csr
2235 ins.rd, ins.rs1, ins.rs2 = REG_ZERO, REG_ZERO, obj.REG_NONE
2238 case AFCVTWS, AFCVTLS, AFCVTWUS, AFCVTLUS, AFCVTWD, AFCVTLD, AFCVTWUD, AFCVTLUD:
2239 // Set the rounding mode in funct3 to round to zero.
2243 // Replace FNE[SD] with FEQ[SD] and NOT.
2244 if p.To.Type != obj.TYPE_REG {
2245 p.Ctxt.Diag("%v needs an integer register output", ins.as)
2248 if ins.as == AFNES {
2253 ins2 := &instruction{
2254 as: AXORI, // [bit] xor 1 = not [bit]
2259 inss = append(inss, ins2)
2261 case AFSQRTS, AFSQRTD:
2262 // These instructions expect a zero (i.e. float register 0)
2263 // to be the second input operand.
2264 ins.rs1 = uint32(p.From.Reg)
2267 case AFMADDS, AFMSUBS, AFNMADDS, AFNMSUBS,
2268 AFMADDD, AFMSUBD, AFNMADDD, AFNMSUBD:
2269 // Swap the first two operands so that the operands are in the same
2270 // order as they are in the specification: RS1, RS2, RS3, RD.
2271 ins.rs1, ins.rs2 = ins.rs2, ins.rs1
2274 // NEG rs, rd -> SUB rs, X0, rd
2280 if ins.rd == obj.REG_NONE {
2285 // NOT rs, rd -> XORI $-1, rs, rd
2287 ins.rs1, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE
2288 if ins.rd == obj.REG_NONE {
2294 // SEQZ rs, rd -> SLTIU $1, rs, rd
2296 ins.rs1, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE
2300 // SNEZ rs, rd -> SLTU rs, x0, rd
2305 // FABSS rs, rd -> FSGNJXS rs, rs, rd
2307 ins.rs1 = uint32(p.From.Reg)
2310 // FABSD rs, rd -> FSGNJXD rs, rs, rd
2312 ins.rs1 = uint32(p.From.Reg)
2315 // FNEGS rs, rd -> FSGNJNS rs, rs, rd
2317 ins.rs1 = uint32(p.From.Reg)
2320 // FNEGD rs, rd -> FSGNJND rs, rs, rd
2322 ins.rs1 = uint32(p.From.Reg)
2324 case ASLLI, ASRLI, ASRAI:
2325 if ins.imm < 0 || ins.imm > 63 {
2326 p.Ctxt.Diag("%v: shift amount out of range 0 to 63", p)
2329 case ASLLIW, ASRLIW, ASRAIW:
2330 if ins.imm < 0 || ins.imm > 31 {
2331 p.Ctxt.Diag("%v: shift amount out of range 0 to 31", p)
2337 // assemble emits machine code.
2338 // It is called at the very end of the assembly process.
2339 func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
2341 ctxt.Diag("-spectre=ret not supported on riscv")
2342 ctxt.Retpoline = false // don't keep printing
2345 for p := cursym.Func().Text; p != nil; p = p.Link {
2348 if p.Mark&NEED_JAL_RELOC == NEED_JAL_RELOC {
2349 rel := obj.Addrel(cursym)
2350 rel.Off = int32(p.Pc)
2353 rel.Add = p.To.Offset
2354 rel.Type = objabi.R_RISCV_JAL
2357 if p.To.Sym != nil {
2358 ctxt.Diag("%v: unexpected AJALR with to symbol", p)
2361 case AAUIPC, AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
2363 var rt objabi.RelocType
2364 if p.Mark&NEED_CALL_RELOC == NEED_CALL_RELOC {
2365 rt = objabi.R_RISCV_CALL
2367 } else if p.Mark&NEED_PCREL_ITYPE_RELOC == NEED_PCREL_ITYPE_RELOC {
2368 rt = objabi.R_RISCV_PCREL_ITYPE
2370 } else if p.Mark&NEED_PCREL_STYPE_RELOC == NEED_PCREL_STYPE_RELOC {
2371 rt = objabi.R_RISCV_PCREL_STYPE
2378 ctxt.Diag("AUIPC needing PC-relative reloc missing following instruction")
2381 addr = &p.RestArgs[0].Addr
2383 if addr.Sym == nil {
2384 ctxt.Diag("PC-relative relocation missing symbol")
2387 if addr.Sym.Type == objabi.STLSBSS {
2388 if ctxt.Flag_shared {
2389 rt = objabi.R_RISCV_TLS_IE
2391 rt = objabi.R_RISCV_TLS_LE
2395 rel := obj.Addrel(cursym)
2396 rel.Off = int32(p.Pc)
2399 rel.Add = addr.Offset
2404 for _, ins := range instructionsForProg(p) {
2405 if ic, err := ins.encode(); err == nil {
2406 cursym.WriteInt(ctxt, offset, ins.length(), int64(ic))
2407 offset += int64(ins.length())
2409 if ins.usesRegTmp() {
2410 p.Mark |= USES_REG_TMP
2415 obj.MarkUnsafePoints(ctxt, cursym.Func().Text, newprog, isUnsafePoint, nil)
2418 func isUnsafePoint(p *obj.Prog) bool {
2419 return p.Mark&USES_REG_TMP == USES_REG_TMP || p.From.Reg == REG_TMP || p.To.Reg == REG_TMP || p.Reg == REG_TMP
2422 var LinkRISCV64 = obj.LinkArch{
2423 Arch: sys.ArchRISCV64,
2425 Preprocess: preprocess,
2429 DWARFRegisters: RISCV64DWARFRegisters,