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 {
73 p.As, p.From.Offset = AADDI, -p.From.Offset
93 p.As, p.From.Offset = AADDIW, -p.From.Offset
105 // Turn JMP into JAL ZERO or JALR ZERO.
106 p.From.Type = obj.TYPE_REG
107 p.From.Reg = REG_ZERO
110 case obj.TYPE_BRANCH:
116 case obj.NAME_EXTERN, obj.NAME_STATIC:
117 // Handled in preprocess.
119 ctxt.Diag("unsupported name %d for %v", p.To.Name, p)
122 panic(fmt.Sprintf("unhandled type %+v", p.To.Type))
128 // Handled in preprocess.
131 p.From.Type = obj.TYPE_REG
134 ctxt.Diag("unknown destination type %+v in CALL: %v", p.To.Type, p)
141 // SCALL is the old name for ECALL.
145 // SBREAK is the old name for EBREAK.
149 if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == obj.REG_NONE && int64(int32(p.From.Offset)) != p.From.Offset {
150 ctz := bits.TrailingZeros64(uint64(p.From.Offset))
151 val := p.From.Offset >> ctz
152 if int64(int32(val)) == val {
153 // It's ok. We can handle constants with many trailing zeros.
156 // Put >32-bit constants in memory and load them.
157 p.From.Type = obj.TYPE_MEM
158 p.From.Sym = ctxt.Int64Sym(p.From.Offset)
159 p.From.Name = obj.NAME_EXTERN
165 // addrToReg extracts the register from an Addr, handling special Addr.Names.
166 func addrToReg(a obj.Addr) int16 {
168 case obj.NAME_PARAM, obj.NAME_AUTO:
174 // movToLoad converts a MOV mnemonic into the corresponding load instruction.
175 func movToLoad(mnemonic obj.As) obj.As {
196 panic(fmt.Sprintf("%+v is not a MOV", mnemonic))
200 // movToStore converts a MOV mnemonic into the corresponding store instruction.
201 func movToStore(mnemonic obj.As) obj.As {
216 panic(fmt.Sprintf("%+v is not a MOV", mnemonic))
220 // markRelocs marks an obj.Prog that specifies a MOV pseudo-instruction and
221 // requires relocation.
222 func markRelocs(p *obj.Prog) {
224 case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
226 case p.From.Type == obj.TYPE_ADDR && p.To.Type == obj.TYPE_REG:
228 case obj.NAME_EXTERN, obj.NAME_STATIC:
229 p.Mark |= NEED_PCREL_ITYPE_RELOC
231 case p.From.Type == obj.TYPE_MEM && p.To.Type == obj.TYPE_REG:
233 case obj.NAME_EXTERN, obj.NAME_STATIC:
234 p.Mark |= NEED_PCREL_ITYPE_RELOC
236 case p.From.Type == obj.TYPE_REG && p.To.Type == obj.TYPE_MEM:
238 case obj.NAME_EXTERN, obj.NAME_STATIC:
239 p.Mark |= NEED_PCREL_STYPE_RELOC
245 // InvertBranch inverts the condition of a conditional branch.
246 func InvertBranch(as obj.As) obj.As {
281 panic("InvertBranch: not a branch")
285 // containsCall reports whether the symbol contains a CALL (or equivalent)
286 // instruction. Must be called after progedit.
287 func containsCall(sym *obj.LSym) bool {
288 // CALLs are CALL or JAL(R) with link register LR.
289 for p := sym.Func().Text; p != nil; p = p.Link {
291 case obj.ACALL, obj.ADUFFZERO, obj.ADUFFCOPY:
294 if p.From.Type == obj.TYPE_REG && p.From.Reg == REG_LR {
303 // setPCs sets the Pc field in all instructions reachable from p.
304 // It uses pc as the initial value and returns the next available pc.
305 func setPCs(p *obj.Prog, pc int64) int64 {
306 for ; p != nil; p = p.Link {
308 for _, ins := range instructionsForProg(p) {
309 pc += int64(ins.length())
315 // stackOffset updates Addr offsets based on the current stack size.
317 // The stack looks like:
318 // -------------------
323 // -------------------
324 // | Parent RA | SP on function entry
325 // -------------------
331 // -------------------
332 // | RA | SP during function execution
333 // -------------------
335 // FixedFrameSize makes other packages aware of the space allocated for RA.
337 // A nicer version of this diagram can be found on slide 21 of the presentation
338 // attached to https://golang.org/issue/16922#issuecomment-243748180.
339 func stackOffset(a *obj.Addr, stacksize int64) {
342 // Adjust to the top of AUTOs.
343 a.Offset += stacksize
345 // Adjust to the bottom of PARAMs.
346 a.Offset += stacksize + 8
350 // preprocess generates prologue and epilogue code, computes PC-relative branch
351 // and jump offsets, and resolves pseudo-registers.
353 // preprocess is called once per linker symbol.
355 // When preprocess finishes, all instructions in the symbol are either
356 // concrete, real RISC-V instructions or directive pseudo-ops like TEXT,
357 // PCDATA, and FUNCDATA.
358 func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
359 if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
363 // Generate the prologue.
364 text := cursym.Func().Text
365 if text.As != obj.ATEXT {
366 ctxt.Diag("preprocess: found symbol that does not start with TEXT directive")
370 stacksize := text.To.Offset
372 // Historical way to mark NOFRAME.
373 text.From.Sym.Set(obj.AttrNoFrame, true)
377 ctxt.Diag("negative frame size %d - did you mean NOFRAME?", stacksize)
379 if text.From.Sym.NoFrame() {
381 ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", stacksize)
385 if !containsCall(cursym) {
386 text.From.Sym.Set(obj.AttrLeaf, true)
388 // A leaf function with no locals has no frame.
389 text.From.Sym.Set(obj.AttrNoFrame, true)
393 // Save LR unless there is no frame.
394 if !text.From.Sym.NoFrame() {
395 stacksize += ctxt.Arch.FixedFrameSize
398 cursym.Func().Args = text.To.Val.(int32)
399 cursym.Func().Locals = int32(stacksize)
403 if !cursym.Func().Text.From.Sym.NoSplit() {
404 prologue = stacksplit(ctxt, prologue, cursym, newprog, stacksize) // emit split check
408 prologue = ctxt.StartUnsafePoint(prologue, newprog)
411 prologue = obj.Appendp(prologue, newprog)
413 prologue.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
414 prologue.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: -stacksize}
416 // Insert stack adjustment.
417 prologue = obj.Appendp(prologue, newprog)
419 prologue.From = obj.Addr{Type: obj.TYPE_CONST, Offset: -stacksize}
420 prologue.Reg = REG_SP
421 prologue.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_SP}
422 prologue.Spadj = int32(stacksize)
424 prologue = ctxt.EndUnsafePoint(prologue, newprog, -1)
426 // On Linux, in a cgo binary we may get a SIGSETXID signal early on
427 // before the signal stack is set, as glibc doesn't allow us to block
428 // SIGSETXID. So a signal may land on the current stack and clobber
429 // the content below the SP. We store the LR again after the SP is
431 prologue = obj.Appendp(prologue, newprog)
433 prologue.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
434 prologue.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 0}
437 if cursym.Func().Text.From.Sym.Wrapper() {
438 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
440 // MOV g_panic(g), X5
441 // BNE X5, ZERO, adjust
444 // ...rest of function..
446 // MOV panic_argp(X5), X6
447 // ADD $(autosize+FIXED_FRAME), SP, X7
449 // ADD $FIXED_FRAME, SP, X6
450 // MOV X6, panic_argp(X5)
453 // The NOP is needed to give the jumps somewhere to land.
455 ldpanic := obj.Appendp(prologue, newprog)
458 ldpanic.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REGG, Offset: 4 * int64(ctxt.Arch.PtrSize)} // G.panic
459 ldpanic.Reg = obj.REG_NONE
460 ldpanic.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X5}
462 bneadj := obj.Appendp(ldpanic, newprog)
464 bneadj.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X5}
465 bneadj.Reg = REG_ZERO
466 bneadj.To.Type = obj.TYPE_BRANCH
468 endadj := obj.Appendp(bneadj, newprog)
472 for last.Link != nil {
476 getargp := obj.Appendp(last, newprog)
478 getargp.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_X5, Offset: 0} // Panic.argp
479 getargp.Reg = obj.REG_NONE
480 getargp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X6}
482 bneadj.To.SetTarget(getargp)
484 calcargp := obj.Appendp(getargp, newprog)
486 calcargp.From = obj.Addr{Type: obj.TYPE_CONST, Offset: stacksize + ctxt.Arch.FixedFrameSize}
487 calcargp.Reg = REG_SP
488 calcargp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X7}
490 testargp := obj.Appendp(calcargp, newprog)
492 testargp.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X6}
493 testargp.Reg = REG_X7
494 testargp.To.Type = obj.TYPE_BRANCH
495 testargp.To.SetTarget(endadj)
497 adjargp := obj.Appendp(testargp, newprog)
499 adjargp.From = obj.Addr{Type: obj.TYPE_CONST, Offset: int64(ctxt.Arch.PtrSize)}
501 adjargp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X6}
503 setargp := obj.Appendp(adjargp, newprog)
505 setargp.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X6}
506 setargp.Reg = obj.REG_NONE
507 setargp.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_X5, Offset: 0} // Panic.argp
509 godone := obj.Appendp(setargp, newprog)
511 godone.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
512 godone.To.Type = obj.TYPE_BRANCH
513 godone.To.SetTarget(endadj)
516 // Update stack-based offsets.
517 for p := cursym.Func().Text; p != nil; p = p.Link {
518 stackOffset(&p.From, stacksize)
519 stackOffset(&p.To, stacksize)
522 // Additional instruction rewriting.
523 for p := cursym.Func().Text; p != nil; p = p.Link {
525 case obj.AGETCALLERPC:
529 p.From.Type = obj.TYPE_REG
534 p.From.Type = obj.TYPE_MEM
538 case obj.ACALL, obj.ADUFFZERO, obj.ADUFFCOPY:
541 jalToSym(ctxt, p, REG_LR)
548 case obj.NAME_EXTERN, obj.NAME_STATIC:
549 jalToSym(ctxt, p, REG_ZERO)
554 // Replace RET with epilogue.
560 p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 0}
561 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
562 p = obj.Appendp(p, newprog)
565 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: stacksize}
567 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_SP}
568 p.Spadj = int32(-stacksize)
569 p = obj.Appendp(p, newprog)
575 jalToSym(ctxt, p, REG_ZERO)
578 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
580 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
583 // "Add back" the stack removed in the previous instruction.
585 // This is to avoid confusing pctospadj, which sums
586 // Spadj from function entry to each PC, and shouldn't
587 // count adjustments from earlier epilogues, since they
588 // won't affect later PCs.
589 p.Spadj = int32(stacksize)
592 // Refine Spadjs account for adjustment via ADDI instruction.
593 if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_SP && p.From.Type == obj.TYPE_CONST {
594 p.Spadj = int32(-p.From.Offset)
598 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
600 if f.FuncFlag&abi.FuncFlagSPWrite == 0 {
601 f.FuncFlag |= abi.FuncFlagSPWrite
602 if ctxt.Debugvlog || !ctxt.IsAsm {
603 ctxt.Logf("auto-SPWRITE: %s %v\n", cursym.Name, p)
605 ctxt.Diag("invalid auto-SPWRITE in non-assembly")
607 log.Fatalf("bad SPWRITE")
615 for p := cursym.Func().Text; p != nil; p = p.Link {
617 if p.Mark&NEED_JAL_RELOC == NEED_JAL_RELOC {
621 const callTrampSize = 8 // 2 machine instructions.
622 maxTrampSize := int64(callCount * callTrampSize)
624 // Compute instruction addresses. Once we do that, we need to check for
625 // overextended jumps and branches. Within each iteration, Pc differences
626 // are always lower bounds (since the program gets monotonically longer,
627 // a fixed point will be reached). No attempt to handle functions > 2GiB.
629 big, rescan := false, false
630 maxPC := setPCs(cursym.Func().Text, 0)
631 if maxPC+maxTrampSize > (1 << 20) {
635 for p := cursym.Func().Text; p != nil; p = p.Link {
637 case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ:
638 if p.To.Type != obj.TYPE_BRANCH {
639 panic("assemble: instruction with branch-like opcode lacks destination")
641 offset := p.To.Target().Pc - p.Pc
642 if offset < -4096 || 4096 <= offset {
643 // Branch is long. Replace it with a jump.
644 jmp := obj.Appendp(p, newprog)
646 jmp.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
647 jmp.To = obj.Addr{Type: obj.TYPE_BRANCH}
648 jmp.To.SetTarget(p.To.Target())
650 p.As = InvertBranch(p.As)
651 p.To.SetTarget(jmp.Link)
653 // We may have made previous branches too long,
658 // Linker will handle the intersymbol case and trampolines.
659 if p.To.Target() == nil {
663 // This function is going to be too large for JALs
664 // to reach trampolines. Replace with AUIPC+JALR.
665 jmp := obj.Appendp(p, newprog)
668 jmp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
671 p.Mark = (p.Mark &^ NEED_JAL_RELOC) | NEED_CALL_RELOC
672 p.AddRestSource(obj.Addr{Type: obj.TYPE_CONST, Offset: p.To.Offset, Sym: p.To.Sym})
673 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
675 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
680 offset := p.To.Target().Pc - p.Pc
681 if offset < -(1<<20) || (1<<20) <= offset {
682 // Replace with 2-instruction sequence. This assumes
683 // that TMP is not live across J instructions, since
684 // it is reserved by SSA.
685 jmp := obj.Appendp(p, newprog)
688 jmp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
690 // p.From is not generally valid, however will be
691 // fixed up in the next loop.
693 p.From = obj.Addr{Type: obj.TYPE_BRANCH, Sym: p.From.Sym}
694 p.From.SetTarget(p.To.Target())
696 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
708 // Now that there are no long branches, resolve branch and jump targets.
709 // At this point, instruction rewriting which changes the number of
710 // instructions will break everything--don't do it!
711 for p := cursym.Func().Text; p != nil; p = p.Link {
713 case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ:
715 case obj.TYPE_BRANCH:
716 p.To.Type, p.To.Offset = obj.TYPE_CONST, p.To.Target().Pc-p.Pc
718 panic("unhandled type")
722 // Linker will handle the intersymbol case and trampolines.
723 if p.To.Target() != nil {
724 p.To.Type, p.To.Offset = obj.TYPE_CONST, p.To.Target().Pc-p.Pc
728 if p.From.Type == obj.TYPE_BRANCH {
729 low, high, err := Split32BitImmediate(p.From.Target().Pc - p.Pc)
731 ctxt.Diag("%v: jump displacement %d too large", p, p.To.Target().Pc-p.Pc)
733 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high, Sym: cursym}
734 p.Link.To.Offset = low
739 // Validate all instructions - this provides nice error messages.
740 for p := cursym.Func().Text; p != nil; p = p.Link {
741 for _, ins := range instructionsForProg(p) {
747 func stacksplit(ctxt *obj.Link, p *obj.Prog, cursym *obj.LSym, newprog obj.ProgAlloc, framesize int64) *obj.Prog {
748 // Leaf function with no frame is effectively NOSPLIT.
753 if ctxt.Flag_maymorestack != "" {
754 // Save LR and REGCTXT
756 p = ctxt.StartUnsafePoint(p, newprog)
758 // Spill Arguments. This has to happen before we open
759 // any more frame space.
760 p = cursym.Func().SpillRegisterArgs(p, newprog)
763 p = obj.Appendp(p, newprog)
765 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
766 p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: -frameSize}
768 p = obj.Appendp(p, newprog)
770 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: -frameSize}
772 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_SP}
774 // MOV REGCTXT, 8(SP)
775 p = obj.Appendp(p, newprog)
777 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_CTXT}
778 p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 8}
781 p = obj.Appendp(p, newprog)
783 p.To.Type = obj.TYPE_BRANCH
784 // See ../x86/obj6.go
785 p.To.Sym = ctxt.LookupABI(ctxt.Flag_maymorestack, cursym.ABI())
786 jalToSym(ctxt, p, REG_X5)
788 // Restore LR and REGCTXT
790 // MOV 8(SP), REGCTXT
791 p = obj.Appendp(p, newprog)
793 p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 8}
794 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_CTXT}
796 p = obj.Appendp(p, newprog)
798 p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 0}
799 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
801 p = obj.Appendp(p, newprog)
803 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: frameSize}
805 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_SP}
809 p = cursym.Func().UnspillRegisterArgs(p, newprog)
810 p = ctxt.EndUnsafePoint(p, newprog, -1)
813 // Jump back to here after morestack returns.
816 // MOV g_stackguard(g), X6
817 p = obj.Appendp(p, newprog)
819 p.From.Type = obj.TYPE_MEM
821 p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
823 p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
825 p.To.Type = obj.TYPE_REG
828 // Mark the stack bound check and morestack call async nonpreemptible.
829 // If we get preempted here, when resumed the preemption request is
830 // cleared, but we'll still call morestack, which will double the stack
831 // unnecessarily. See issue #35470.
832 p = ctxt.StartUnsafePoint(p, newprog)
834 var to_done, to_more *obj.Prog
836 if framesize <= abi.StackSmall {
838 // // if SP > stackguard { goto done }
839 // BLTU stackguard, SP, done
840 p = obj.Appendp(p, newprog)
842 p.From.Type = obj.TYPE_REG
845 p.To.Type = obj.TYPE_BRANCH
848 // large stack: SP-framesize < stackguard-StackSmall
849 offset := int64(framesize) - abi.StackSmall
850 if framesize > abi.StackBig {
851 // Such a large stack we need to protect against underflow.
852 // The runtime guarantees SP > objabi.StackBig, but
853 // framesize is large enough that SP-framesize may
854 // underflow, causing a direct comparison with the
855 // stack guard to incorrectly succeed. We explicitly
856 // guard against underflow.
858 // MOV $(framesize-StackSmall), X7
859 // BLTU SP, X7, label-of-call-to-morestack
861 p = obj.Appendp(p, newprog)
863 p.From.Type = obj.TYPE_CONST
864 p.From.Offset = offset
865 p.To.Type = obj.TYPE_REG
868 p = obj.Appendp(p, newprog)
870 p.From.Type = obj.TYPE_REG
873 p.To.Type = obj.TYPE_BRANCH
877 // Check against the stack guard. We've ensured this won't underflow.
878 // ADD $-(framesize-StackSmall), SP, X7
879 // // if X7 > stackguard { goto done }
880 // BLTU stackguard, X7, done
881 p = obj.Appendp(p, newprog)
883 p.From.Type = obj.TYPE_CONST
884 p.From.Offset = -offset
886 p.To.Type = obj.TYPE_REG
889 p = obj.Appendp(p, newprog)
891 p.From.Type = obj.TYPE_REG
894 p.To.Type = obj.TYPE_BRANCH
898 // Spill the register args that could be clobbered by the
900 p = ctxt.EmitEntryStackMap(cursym, p, newprog)
901 p = cursym.Func().SpillRegisterArgs(p, newprog)
903 // CALL runtime.morestack(SB)
904 p = obj.Appendp(p, newprog)
906 p.To.Type = obj.TYPE_BRANCH
909 p.To.Sym = ctxt.Lookup("runtime.morestackc")
910 } else if !cursym.Func().Text.From.Sym.NeedCtxt() {
911 p.To.Sym = ctxt.Lookup("runtime.morestack_noctxt")
913 p.To.Sym = ctxt.Lookup("runtime.morestack")
916 to_more.To.SetTarget(p)
918 jalToSym(ctxt, p, REG_X5)
920 // The instructions which unspill regs should be preemptible.
921 p = ctxt.EndUnsafePoint(p, newprog, -1)
922 p = cursym.Func().UnspillRegisterArgs(p, newprog)
925 p = obj.Appendp(p, newprog)
927 p.To = obj.Addr{Type: obj.TYPE_BRANCH}
928 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
929 p.To.SetTarget(startPred.Link)
931 // placeholder for to_done's jump target
932 p = obj.Appendp(p, newprog)
933 p.As = obj.ANOP // zero-width place holder
934 to_done.To.SetTarget(p)
939 // signExtend sign extends val starting at bit bit.
940 func signExtend(val int64, bit uint) int64 {
941 return val << (64 - bit) >> (64 - bit)
944 // Split32BitImmediate splits a signed 32-bit immediate into a signed 20-bit
945 // upper immediate and a signed 12-bit lower immediate to be added to the upper
946 // result. For example, high may be used in LUI and low in a following ADDI to
947 // generate a full 32-bit constant.
948 func Split32BitImmediate(imm int64) (low, high int64, err error) {
949 if err := immIFits(imm, 32); err != nil {
953 // Nothing special needs to be done if the immediate fits in 12 bits.
954 if err := immIFits(imm, 12); err == nil {
960 // The bottom 12 bits will be treated as signed.
962 // If that will result in a negative 12 bit number, add 1 to
963 // our upper bits to adjust for the borrow.
965 // It is not possible for this increment to overflow. To
966 // overflow, the 20 top bits would be 1, and the sign bit for
967 // the low 12 bits would be set, in which case the entire 32
968 // bit pattern fits in a 12 bit signed value.
969 if imm&(1<<11) != 0 {
973 low = signExtend(imm, 12)
974 high = signExtend(high, 20)
976 return low, high, nil
979 func regVal(r, min, max uint32) uint32 {
980 if r < min || r > max {
981 panic(fmt.Sprintf("register out of range, want %d <= %d <= %d", min, r, max))
986 // regI returns an integer register.
987 func regI(r uint32) uint32 {
988 return regVal(r, REG_X0, REG_X31)
991 // regF returns a float register.
992 func regF(r uint32) uint32 {
993 return regVal(r, REG_F0, REG_F31)
996 // regAddr extracts a register from an Addr.
997 func regAddr(a obj.Addr, min, max uint32) uint32 {
998 if a.Type != obj.TYPE_REG {
999 panic(fmt.Sprintf("ill typed: %+v", a))
1001 return regVal(uint32(a.Reg), min, max)
1004 // regIAddr extracts the integer register from an Addr.
1005 func regIAddr(a obj.Addr) uint32 {
1006 return regAddr(a, REG_X0, REG_X31)
1009 // regFAddr extracts the float register from an Addr.
1010 func regFAddr(a obj.Addr) uint32 {
1011 return regAddr(a, REG_F0, REG_F31)
1014 // immEven checks that the immediate is a multiple of two. If it
1015 // is not, an error is returned.
1016 func immEven(x int64) error {
1018 return fmt.Errorf("immediate %#x is not a multiple of two", x)
1023 // immIFits checks whether the immediate value x fits in nbits bits
1024 // as a signed integer. If it does not, an error is returned.
1025 func immIFits(x int64, nbits uint) error {
1027 min := int64(-1) << nbits
1028 max := int64(1)<<nbits - 1
1029 if x < min || x > max {
1031 return fmt.Errorf("signed immediate %d must be in range [%d, %d] (%d bits)", x, min, max, nbits)
1033 return fmt.Errorf("signed immediate %#x must be in range [%#x, %#x] (%d bits)", x, min, max, nbits)
1038 // immI extracts the signed integer of the specified size from an immediate.
1039 func immI(as obj.As, imm int64, nbits uint) uint32 {
1040 if err := immIFits(imm, nbits); err != nil {
1041 panic(fmt.Sprintf("%v: %v", as, err))
1046 func wantImmI(ctxt *obj.Link, as obj.As, imm int64, nbits uint) {
1047 if err := immIFits(imm, nbits); err != nil {
1048 ctxt.Diag("%v: %v", as, err)
1052 func wantReg(ctxt *obj.Link, as obj.As, pos string, descr string, r, min, max uint32) {
1053 if r < min || r > max {
1055 if r != obj.REG_NONE {
1056 suffix = fmt.Sprintf(" but got non-%s register %s", descr, RegName(int(r)))
1058 ctxt.Diag("%v: expected %s register in %s position%s", as, descr, pos, suffix)
1062 func wantNoneReg(ctxt *obj.Link, as obj.As, pos string, r uint32) {
1063 if r != obj.REG_NONE {
1064 ctxt.Diag("%v: expected no register in %s but got register %s", as, pos, RegName(int(r)))
1068 // wantIntReg checks that r is an integer register.
1069 func wantIntReg(ctxt *obj.Link, as obj.As, pos string, r uint32) {
1070 wantReg(ctxt, as, pos, "integer", r, REG_X0, REG_X31)
1073 // wantFloatReg checks that r is a floating-point register.
1074 func wantFloatReg(ctxt *obj.Link, as obj.As, pos string, r uint32) {
1075 wantReg(ctxt, as, pos, "float", r, REG_F0, REG_F31)
1078 // wantEvenOffset checks that the offset is a multiple of two.
1079 func wantEvenOffset(ctxt *obj.Link, as obj.As, offset int64) {
1080 if err := immEven(offset); err != nil {
1081 ctxt.Diag("%v: %v", as, err)
1085 func validateRIII(ctxt *obj.Link, ins *instruction) {
1086 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1087 wantIntReg(ctxt, ins.as, "rs1", ins.rs1)
1088 wantIntReg(ctxt, ins.as, "rs2", ins.rs2)
1089 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1092 func validateRFFF(ctxt *obj.Link, ins *instruction) {
1093 wantFloatReg(ctxt, ins.as, "rd", ins.rd)
1094 wantFloatReg(ctxt, ins.as, "rs1", ins.rs1)
1095 wantFloatReg(ctxt, ins.as, "rs2", ins.rs2)
1096 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1099 func validateRFFFF(ctxt *obj.Link, ins *instruction) {
1100 wantFloatReg(ctxt, ins.as, "rd", ins.rd)
1101 wantFloatReg(ctxt, ins.as, "rs1", ins.rs1)
1102 wantFloatReg(ctxt, ins.as, "rs2", ins.rs2)
1103 wantFloatReg(ctxt, ins.as, "rs3", ins.rs3)
1106 func validateRFFI(ctxt *obj.Link, ins *instruction) {
1107 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1108 wantFloatReg(ctxt, ins.as, "rs1", ins.rs1)
1109 wantFloatReg(ctxt, ins.as, "rs2", ins.rs2)
1110 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1113 func validateRFI(ctxt *obj.Link, ins *instruction) {
1114 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1115 wantNoneReg(ctxt, ins.as, "rs1", ins.rs1)
1116 wantFloatReg(ctxt, ins.as, "rs2", ins.rs2)
1117 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1120 func validateRIF(ctxt *obj.Link, ins *instruction) {
1121 wantFloatReg(ctxt, ins.as, "rd", ins.rd)
1122 wantNoneReg(ctxt, ins.as, "rs1", ins.rs1)
1123 wantIntReg(ctxt, ins.as, "rs2", ins.rs2)
1124 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1127 func validateRFF(ctxt *obj.Link, ins *instruction) {
1128 wantFloatReg(ctxt, ins.as, "rd", ins.rd)
1129 wantNoneReg(ctxt, ins.as, "rs1", ins.rs1)
1130 wantFloatReg(ctxt, ins.as, "rs2", ins.rs2)
1131 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1134 func validateII(ctxt *obj.Link, ins *instruction) {
1135 wantImmI(ctxt, ins.as, ins.imm, 12)
1136 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1137 wantIntReg(ctxt, ins.as, "rs1", ins.rs1)
1138 wantNoneReg(ctxt, ins.as, "rs2", ins.rs2)
1139 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1142 func validateIF(ctxt *obj.Link, ins *instruction) {
1143 wantImmI(ctxt, ins.as, ins.imm, 12)
1144 wantFloatReg(ctxt, ins.as, "rd", ins.rd)
1145 wantIntReg(ctxt, ins.as, "rs1", ins.rs1)
1146 wantNoneReg(ctxt, ins.as, "rs2", ins.rs2)
1147 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1150 func validateSI(ctxt *obj.Link, ins *instruction) {
1151 wantImmI(ctxt, ins.as, ins.imm, 12)
1152 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1153 wantIntReg(ctxt, ins.as, "rs1", ins.rs1)
1154 wantNoneReg(ctxt, ins.as, "rs2", ins.rs2)
1155 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1158 func validateSF(ctxt *obj.Link, ins *instruction) {
1159 wantImmI(ctxt, ins.as, ins.imm, 12)
1160 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1161 wantFloatReg(ctxt, ins.as, "rs1", ins.rs1)
1162 wantNoneReg(ctxt, ins.as, "rs2", ins.rs2)
1163 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1166 func validateB(ctxt *obj.Link, ins *instruction) {
1167 // Offsets are multiples of two, so accept 13 bit immediates for the
1168 // 12 bit slot. We implicitly drop the least significant bit in encodeB.
1169 wantEvenOffset(ctxt, ins.as, ins.imm)
1170 wantImmI(ctxt, ins.as, ins.imm, 13)
1171 wantNoneReg(ctxt, ins.as, "rd", ins.rd)
1172 wantIntReg(ctxt, ins.as, "rs1", ins.rs1)
1173 wantIntReg(ctxt, ins.as, "rs2", ins.rs2)
1174 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1177 func validateU(ctxt *obj.Link, ins *instruction) {
1178 wantImmI(ctxt, ins.as, ins.imm, 20)
1179 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1180 wantNoneReg(ctxt, ins.as, "rs1", ins.rs1)
1181 wantNoneReg(ctxt, ins.as, "rs2", ins.rs2)
1182 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1185 func validateJ(ctxt *obj.Link, ins *instruction) {
1186 // Offsets are multiples of two, so accept 21 bit immediates for the
1187 // 20 bit slot. We implicitly drop the least significant bit in encodeJ.
1188 wantEvenOffset(ctxt, ins.as, ins.imm)
1189 wantImmI(ctxt, ins.as, ins.imm, 21)
1190 wantIntReg(ctxt, ins.as, "rd", ins.rd)
1191 wantNoneReg(ctxt, ins.as, "rs1", ins.rs1)
1192 wantNoneReg(ctxt, ins.as, "rs2", ins.rs2)
1193 wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
1196 func validateRaw(ctxt *obj.Link, ins *instruction) {
1197 // Treat the raw value specially as a 32-bit unsigned integer.
1198 // Nobody wants to enter negative machine code.
1199 if ins.imm < 0 || 1<<32 <= ins.imm {
1200 ctxt.Diag("%v: immediate %d in raw position cannot be larger than 32 bits", ins.as, ins.imm)
1204 // extractBitAndShift extracts the specified bit from the given immediate,
1205 // before shifting it to the requested position and returning it.
1206 func extractBitAndShift(imm uint32, bit, pos int) uint32 {
1207 return ((imm >> bit) & 1) << pos
1210 // encodeR encodes an R-type RISC-V instruction.
1211 func encodeR(as obj.As, rs1, rs2, rd, funct3, funct7 uint32) uint32 {
1214 panic("encodeR: could not encode instruction")
1216 if enc.rs2 != 0 && rs2 != 0 {
1217 panic("encodeR: instruction uses rs2, but rs2 was nonzero")
1219 return funct7<<25 | enc.funct7<<25 | enc.rs2<<20 | rs2<<20 | rs1<<15 | enc.funct3<<12 | funct3<<12 | rd<<7 | enc.opcode
1222 // encodeR4 encodes an R4-type RISC-V instruction.
1223 func encodeR4(as obj.As, rs1, rs2, rs3, rd, funct3, funct2 uint32) uint32 {
1226 panic("encodeR4: could not encode instruction")
1229 panic("encodeR4: instruction uses rs2")
1231 funct2 |= enc.funct7
1233 panic("encodeR4: funct2 requires more than 2 bits")
1235 return rs3<<27 | funct2<<25 | rs2<<20 | rs1<<15 | enc.funct3<<12 | funct3<<12 | rd<<7 | enc.opcode
1238 func encodeRIII(ins *instruction) uint32 {
1239 return encodeR(ins.as, regI(ins.rs1), regI(ins.rs2), regI(ins.rd), ins.funct3, ins.funct7)
1242 func encodeRFFF(ins *instruction) uint32 {
1243 return encodeR(ins.as, regF(ins.rs1), regF(ins.rs2), regF(ins.rd), ins.funct3, ins.funct7)
1246 func encodeRFFFF(ins *instruction) uint32 {
1247 return encodeR4(ins.as, regF(ins.rs1), regF(ins.rs2), regF(ins.rs3), regF(ins.rd), ins.funct3, ins.funct7)
1250 func encodeRFFI(ins *instruction) uint32 {
1251 return encodeR(ins.as, regF(ins.rs1), regF(ins.rs2), regI(ins.rd), ins.funct3, ins.funct7)
1254 func encodeRFI(ins *instruction) uint32 {
1255 return encodeR(ins.as, regF(ins.rs2), 0, regI(ins.rd), ins.funct3, ins.funct7)
1258 func encodeRIF(ins *instruction) uint32 {
1259 return encodeR(ins.as, regI(ins.rs2), 0, regF(ins.rd), ins.funct3, ins.funct7)
1262 func encodeRFF(ins *instruction) uint32 {
1263 return encodeR(ins.as, regF(ins.rs2), 0, regF(ins.rd), ins.funct3, ins.funct7)
1266 // encodeI encodes an I-type RISC-V instruction.
1267 func encodeI(as obj.As, rs1, rd, imm uint32) uint32 {
1270 panic("encodeI: could not encode instruction")
1272 imm |= uint32(enc.csr)
1273 return imm<<20 | rs1<<15 | enc.funct3<<12 | rd<<7 | enc.opcode
1276 func encodeII(ins *instruction) uint32 {
1277 return encodeI(ins.as, regI(ins.rs1), regI(ins.rd), uint32(ins.imm))
1280 func encodeIF(ins *instruction) uint32 {
1281 return encodeI(ins.as, regI(ins.rs1), regF(ins.rd), uint32(ins.imm))
1284 // encodeS encodes an S-type RISC-V instruction.
1285 func encodeS(as obj.As, rs1, rs2, imm uint32) uint32 {
1288 panic("encodeS: could not encode instruction")
1290 return (imm>>5)<<25 | rs2<<20 | rs1<<15 | enc.funct3<<12 | (imm&0x1f)<<7 | enc.opcode
1293 func encodeSI(ins *instruction) uint32 {
1294 return encodeS(ins.as, regI(ins.rd), regI(ins.rs1), uint32(ins.imm))
1297 func encodeSF(ins *instruction) uint32 {
1298 return encodeS(ins.as, regI(ins.rd), regF(ins.rs1), uint32(ins.imm))
1301 // encodeBImmediate encodes an immediate for a B-type RISC-V instruction.
1302 func encodeBImmediate(imm uint32) uint32 {
1303 return (imm>>12)<<31 | ((imm>>5)&0x3f)<<25 | ((imm>>1)&0xf)<<8 | ((imm>>11)&0x1)<<7
1306 // encodeB encodes a B-type RISC-V instruction.
1307 func encodeB(ins *instruction) uint32 {
1308 imm := immI(ins.as, ins.imm, 13)
1309 rs2 := regI(ins.rs1)
1310 rs1 := regI(ins.rs2)
1311 enc := encode(ins.as)
1313 panic("encodeB: could not encode instruction")
1315 return encodeBImmediate(imm) | rs2<<20 | rs1<<15 | enc.funct3<<12 | enc.opcode
1318 // encodeU encodes a U-type RISC-V instruction.
1319 func encodeU(ins *instruction) uint32 {
1320 // The immediates for encodeU are the upper 20 bits of a 32 bit value.
1321 // Rather than have the user/compiler generate a 32 bit constant, the
1322 // bottommost bits of which must all be zero, instead accept just the
1324 imm := immI(ins.as, ins.imm, 20)
1326 enc := encode(ins.as)
1328 panic("encodeU: could not encode instruction")
1330 return imm<<12 | rd<<7 | enc.opcode
1333 // encodeJImmediate encodes an immediate for a J-type RISC-V instruction.
1334 func encodeJImmediate(imm uint32) uint32 {
1335 return (imm>>20)<<31 | ((imm>>1)&0x3ff)<<21 | ((imm>>11)&0x1)<<20 | ((imm>>12)&0xff)<<12
1338 // encodeJ encodes a J-type RISC-V instruction.
1339 func encodeJ(ins *instruction) uint32 {
1340 imm := immI(ins.as, ins.imm, 21)
1342 enc := encode(ins.as)
1344 panic("encodeJ: could not encode instruction")
1346 return encodeJImmediate(imm) | rd<<7 | enc.opcode
1349 // encodeCBImmediate encodes an immediate for a CB-type RISC-V instruction.
1350 func encodeCBImmediate(imm uint32) uint32 {
1351 // Bit order - [8|4:3|7:6|2:1|5]
1352 bits := extractBitAndShift(imm, 8, 7)
1353 bits |= extractBitAndShift(imm, 4, 6)
1354 bits |= extractBitAndShift(imm, 3, 5)
1355 bits |= extractBitAndShift(imm, 7, 4)
1356 bits |= extractBitAndShift(imm, 6, 3)
1357 bits |= extractBitAndShift(imm, 2, 2)
1358 bits |= extractBitAndShift(imm, 1, 1)
1359 bits |= extractBitAndShift(imm, 5, 0)
1360 return (bits>>5)<<10 | (bits&0x1f)<<2
1363 // encodeCJImmediate encodes an immediate for a CJ-type RISC-V instruction.
1364 func encodeCJImmediate(imm uint32) uint32 {
1365 // Bit order - [11|4|9:8|10|6|7|3:1|5]
1366 bits := extractBitAndShift(imm, 11, 10)
1367 bits |= extractBitAndShift(imm, 4, 9)
1368 bits |= extractBitAndShift(imm, 9, 8)
1369 bits |= extractBitAndShift(imm, 8, 7)
1370 bits |= extractBitAndShift(imm, 10, 6)
1371 bits |= extractBitAndShift(imm, 6, 5)
1372 bits |= extractBitAndShift(imm, 7, 4)
1373 bits |= extractBitAndShift(imm, 3, 3)
1374 bits |= extractBitAndShift(imm, 2, 2)
1375 bits |= extractBitAndShift(imm, 1, 1)
1376 bits |= extractBitAndShift(imm, 5, 0)
1380 func encodeRawIns(ins *instruction) uint32 {
1381 // Treat the raw value specially as a 32-bit unsigned integer.
1382 // Nobody wants to enter negative machine code.
1383 if ins.imm < 0 || 1<<32 <= ins.imm {
1384 panic(fmt.Sprintf("immediate %d cannot fit in 32 bits", ins.imm))
1386 return uint32(ins.imm)
1389 func EncodeBImmediate(imm int64) (int64, error) {
1390 if err := immIFits(imm, 13); err != nil {
1393 if err := immEven(imm); err != nil {
1396 return int64(encodeBImmediate(uint32(imm))), nil
1399 func EncodeCBImmediate(imm int64) (int64, error) {
1400 if err := immIFits(imm, 9); err != nil {
1403 if err := immEven(imm); err != nil {
1406 return int64(encodeCBImmediate(uint32(imm))), nil
1409 func EncodeCJImmediate(imm int64) (int64, error) {
1410 if err := immIFits(imm, 12); err != nil {
1413 if err := immEven(imm); err != nil {
1416 return int64(encodeCJImmediate(uint32(imm))), nil
1419 func EncodeIImmediate(imm int64) (int64, error) {
1420 if err := immIFits(imm, 12); err != nil {
1423 return imm << 20, nil
1426 func EncodeJImmediate(imm int64) (int64, error) {
1427 if err := immIFits(imm, 21); err != nil {
1430 if err := immEven(imm); err != nil {
1433 return int64(encodeJImmediate(uint32(imm))), nil
1436 func EncodeSImmediate(imm int64) (int64, error) {
1437 if err := immIFits(imm, 12); err != nil {
1440 return ((imm >> 5) << 25) | ((imm & 0x1f) << 7), nil
1443 func EncodeUImmediate(imm int64) (int64, error) {
1444 if err := immIFits(imm, 20); err != nil {
1447 return imm << 12, nil
1450 type encoding struct {
1451 encode func(*instruction) uint32 // encode returns the machine code for an instruction
1452 validate func(*obj.Link, *instruction) // validate validates an instruction
1453 length int // length of encoded instruction; 0 for pseudo-ops, 4 otherwise
1457 // Encodings have the following naming convention:
1459 // 1. the instruction encoding (R/I/S/B/U/J), in lowercase
1460 // 2. zero or more register operand identifiers (I = integer
1461 // register, F = float register), in uppercase
1462 // 3. the word "Encoding"
1464 // For example, rIIIEncoding indicates an R-type instruction with two
1465 // integer register inputs and an integer register output; sFEncoding
1466 // indicates an S-type instruction with rs2 being a float register.
1468 rIIIEncoding = encoding{encode: encodeRIII, validate: validateRIII, length: 4}
1469 rFFFEncoding = encoding{encode: encodeRFFF, validate: validateRFFF, length: 4}
1470 rFFFFEncoding = encoding{encode: encodeRFFFF, validate: validateRFFFF, length: 4}
1471 rFFIEncoding = encoding{encode: encodeRFFI, validate: validateRFFI, length: 4}
1472 rFIEncoding = encoding{encode: encodeRFI, validate: validateRFI, length: 4}
1473 rIFEncoding = encoding{encode: encodeRIF, validate: validateRIF, length: 4}
1474 rFFEncoding = encoding{encode: encodeRFF, validate: validateRFF, length: 4}
1476 iIEncoding = encoding{encode: encodeII, validate: validateII, length: 4}
1477 iFEncoding = encoding{encode: encodeIF, validate: validateIF, length: 4}
1479 sIEncoding = encoding{encode: encodeSI, validate: validateSI, length: 4}
1480 sFEncoding = encoding{encode: encodeSF, validate: validateSF, length: 4}
1482 bEncoding = encoding{encode: encodeB, validate: validateB, length: 4}
1483 uEncoding = encoding{encode: encodeU, validate: validateU, length: 4}
1484 jEncoding = encoding{encode: encodeJ, validate: validateJ, length: 4}
1486 // rawEncoding encodes a raw instruction byte sequence.
1487 rawEncoding = encoding{encode: encodeRawIns, validate: validateRaw, length: 4}
1489 // pseudoOpEncoding panics if encoding is attempted, but does no validation.
1490 pseudoOpEncoding = encoding{encode: nil, validate: func(*obj.Link, *instruction) {}, length: 0}
1492 // badEncoding is used when an invalid op is encountered.
1493 // An error has already been generated, so let anything else through.
1494 badEncoding = encoding{encode: func(*instruction) uint32 { return 0 }, validate: func(*obj.Link, *instruction) {}, length: 0}
1497 // encodings contains the encodings for RISC-V instructions.
1498 // Instructions are masked with obj.AMask to keep indices small.
1499 var encodings = [ALAST & obj.AMask]encoding{
1503 // 2.4: Integer Computational Instructions
1504 AADDI & obj.AMask: iIEncoding,
1505 ASLTI & obj.AMask: iIEncoding,
1506 ASLTIU & obj.AMask: iIEncoding,
1507 AANDI & obj.AMask: iIEncoding,
1508 AORI & obj.AMask: iIEncoding,
1509 AXORI & obj.AMask: iIEncoding,
1510 ASLLI & obj.AMask: iIEncoding,
1511 ASRLI & obj.AMask: iIEncoding,
1512 ASRAI & obj.AMask: iIEncoding,
1513 ALUI & obj.AMask: uEncoding,
1514 AAUIPC & obj.AMask: uEncoding,
1515 AADD & obj.AMask: rIIIEncoding,
1516 ASLT & obj.AMask: rIIIEncoding,
1517 ASLTU & obj.AMask: rIIIEncoding,
1518 AAND & obj.AMask: rIIIEncoding,
1519 AOR & obj.AMask: rIIIEncoding,
1520 AXOR & obj.AMask: rIIIEncoding,
1521 ASLL & obj.AMask: rIIIEncoding,
1522 ASRL & obj.AMask: rIIIEncoding,
1523 ASUB & obj.AMask: rIIIEncoding,
1524 ASRA & obj.AMask: rIIIEncoding,
1526 // 2.5: Control Transfer Instructions
1527 AJAL & obj.AMask: jEncoding,
1528 AJALR & obj.AMask: iIEncoding,
1529 ABEQ & obj.AMask: bEncoding,
1530 ABNE & obj.AMask: bEncoding,
1531 ABLT & obj.AMask: bEncoding,
1532 ABLTU & obj.AMask: bEncoding,
1533 ABGE & obj.AMask: bEncoding,
1534 ABGEU & obj.AMask: bEncoding,
1536 // 2.6: Load and Store Instructions
1537 ALW & obj.AMask: iIEncoding,
1538 ALWU & obj.AMask: iIEncoding,
1539 ALH & obj.AMask: iIEncoding,
1540 ALHU & obj.AMask: iIEncoding,
1541 ALB & obj.AMask: iIEncoding,
1542 ALBU & obj.AMask: iIEncoding,
1543 ASW & obj.AMask: sIEncoding,
1544 ASH & obj.AMask: sIEncoding,
1545 ASB & obj.AMask: sIEncoding,
1547 // 2.7: Memory Ordering
1548 AFENCE & obj.AMask: iIEncoding,
1550 // 5.2: Integer Computational Instructions (RV64I)
1551 AADDIW & obj.AMask: iIEncoding,
1552 ASLLIW & obj.AMask: iIEncoding,
1553 ASRLIW & obj.AMask: iIEncoding,
1554 ASRAIW & obj.AMask: iIEncoding,
1555 AADDW & obj.AMask: rIIIEncoding,
1556 ASLLW & obj.AMask: rIIIEncoding,
1557 ASRLW & obj.AMask: rIIIEncoding,
1558 ASUBW & obj.AMask: rIIIEncoding,
1559 ASRAW & obj.AMask: rIIIEncoding,
1561 // 5.3: Load and Store Instructions (RV64I)
1562 ALD & obj.AMask: iIEncoding,
1563 ASD & obj.AMask: sIEncoding,
1565 // 7.1: Multiplication Operations
1566 AMUL & obj.AMask: rIIIEncoding,
1567 AMULH & obj.AMask: rIIIEncoding,
1568 AMULHU & obj.AMask: rIIIEncoding,
1569 AMULHSU & obj.AMask: rIIIEncoding,
1570 AMULW & obj.AMask: rIIIEncoding,
1571 ADIV & obj.AMask: rIIIEncoding,
1572 ADIVU & obj.AMask: rIIIEncoding,
1573 AREM & obj.AMask: rIIIEncoding,
1574 AREMU & obj.AMask: rIIIEncoding,
1575 ADIVW & obj.AMask: rIIIEncoding,
1576 ADIVUW & obj.AMask: rIIIEncoding,
1577 AREMW & obj.AMask: rIIIEncoding,
1578 AREMUW & obj.AMask: rIIIEncoding,
1580 // 8.2: Load-Reserved/Store-Conditional
1581 ALRW & obj.AMask: rIIIEncoding,
1582 ALRD & obj.AMask: rIIIEncoding,
1583 ASCW & obj.AMask: rIIIEncoding,
1584 ASCD & obj.AMask: rIIIEncoding,
1586 // 8.3: Atomic Memory Operations
1587 AAMOSWAPW & obj.AMask: rIIIEncoding,
1588 AAMOSWAPD & obj.AMask: rIIIEncoding,
1589 AAMOADDW & obj.AMask: rIIIEncoding,
1590 AAMOADDD & obj.AMask: rIIIEncoding,
1591 AAMOANDW & obj.AMask: rIIIEncoding,
1592 AAMOANDD & obj.AMask: rIIIEncoding,
1593 AAMOORW & obj.AMask: rIIIEncoding,
1594 AAMOORD & obj.AMask: rIIIEncoding,
1595 AAMOXORW & obj.AMask: rIIIEncoding,
1596 AAMOXORD & obj.AMask: rIIIEncoding,
1597 AAMOMAXW & obj.AMask: rIIIEncoding,
1598 AAMOMAXD & obj.AMask: rIIIEncoding,
1599 AAMOMAXUW & obj.AMask: rIIIEncoding,
1600 AAMOMAXUD & obj.AMask: rIIIEncoding,
1601 AAMOMINW & obj.AMask: rIIIEncoding,
1602 AAMOMIND & obj.AMask: rIIIEncoding,
1603 AAMOMINUW & obj.AMask: rIIIEncoding,
1604 AAMOMINUD & obj.AMask: rIIIEncoding,
1606 // 10.1: Base Counters and Timers
1607 ARDCYCLE & obj.AMask: iIEncoding,
1608 ARDTIME & obj.AMask: iIEncoding,
1609 ARDINSTRET & obj.AMask: iIEncoding,
1611 // 11.5: Single-Precision Load and Store Instructions
1612 AFLW & obj.AMask: iFEncoding,
1613 AFSW & obj.AMask: sFEncoding,
1615 // 11.6: Single-Precision Floating-Point Computational Instructions
1616 AFADDS & obj.AMask: rFFFEncoding,
1617 AFSUBS & obj.AMask: rFFFEncoding,
1618 AFMULS & obj.AMask: rFFFEncoding,
1619 AFDIVS & obj.AMask: rFFFEncoding,
1620 AFMINS & obj.AMask: rFFFEncoding,
1621 AFMAXS & obj.AMask: rFFFEncoding,
1622 AFSQRTS & obj.AMask: rFFFEncoding,
1623 AFMADDS & obj.AMask: rFFFFEncoding,
1624 AFMSUBS & obj.AMask: rFFFFEncoding,
1625 AFNMSUBS & obj.AMask: rFFFFEncoding,
1626 AFNMADDS & obj.AMask: rFFFFEncoding,
1628 // 11.7: Single-Precision Floating-Point Conversion and Move Instructions
1629 AFCVTWS & obj.AMask: rFIEncoding,
1630 AFCVTLS & obj.AMask: rFIEncoding,
1631 AFCVTSW & obj.AMask: rIFEncoding,
1632 AFCVTSL & obj.AMask: rIFEncoding,
1633 AFCVTWUS & obj.AMask: rFIEncoding,
1634 AFCVTLUS & obj.AMask: rFIEncoding,
1635 AFCVTSWU & obj.AMask: rIFEncoding,
1636 AFCVTSLU & obj.AMask: rIFEncoding,
1637 AFSGNJS & obj.AMask: rFFFEncoding,
1638 AFSGNJNS & obj.AMask: rFFFEncoding,
1639 AFSGNJXS & obj.AMask: rFFFEncoding,
1640 AFMVXS & obj.AMask: rFIEncoding,
1641 AFMVSX & obj.AMask: rIFEncoding,
1642 AFMVXW & obj.AMask: rFIEncoding,
1643 AFMVWX & obj.AMask: rIFEncoding,
1645 // 11.8: Single-Precision Floating-Point Compare Instructions
1646 AFEQS & obj.AMask: rFFIEncoding,
1647 AFLTS & obj.AMask: rFFIEncoding,
1648 AFLES & obj.AMask: rFFIEncoding,
1650 // 11.9: Single-Precision Floating-Point Classify Instruction
1651 AFCLASSS & obj.AMask: rFIEncoding,
1653 // 12.3: Double-Precision Load and Store Instructions
1654 AFLD & obj.AMask: iFEncoding,
1655 AFSD & obj.AMask: sFEncoding,
1657 // 12.4: Double-Precision Floating-Point Computational Instructions
1658 AFADDD & obj.AMask: rFFFEncoding,
1659 AFSUBD & obj.AMask: rFFFEncoding,
1660 AFMULD & obj.AMask: rFFFEncoding,
1661 AFDIVD & obj.AMask: rFFFEncoding,
1662 AFMIND & obj.AMask: rFFFEncoding,
1663 AFMAXD & obj.AMask: rFFFEncoding,
1664 AFSQRTD & obj.AMask: rFFFEncoding,
1665 AFMADDD & obj.AMask: rFFFFEncoding,
1666 AFMSUBD & obj.AMask: rFFFFEncoding,
1667 AFNMSUBD & obj.AMask: rFFFFEncoding,
1668 AFNMADDD & obj.AMask: rFFFFEncoding,
1670 // 12.5: Double-Precision Floating-Point Conversion and Move Instructions
1671 AFCVTWD & obj.AMask: rFIEncoding,
1672 AFCVTLD & obj.AMask: rFIEncoding,
1673 AFCVTDW & obj.AMask: rIFEncoding,
1674 AFCVTDL & obj.AMask: rIFEncoding,
1675 AFCVTWUD & obj.AMask: rFIEncoding,
1676 AFCVTLUD & obj.AMask: rFIEncoding,
1677 AFCVTDWU & obj.AMask: rIFEncoding,
1678 AFCVTDLU & obj.AMask: rIFEncoding,
1679 AFCVTSD & obj.AMask: rFFEncoding,
1680 AFCVTDS & obj.AMask: rFFEncoding,
1681 AFSGNJD & obj.AMask: rFFFEncoding,
1682 AFSGNJND & obj.AMask: rFFFEncoding,
1683 AFSGNJXD & obj.AMask: rFFFEncoding,
1684 AFMVXD & obj.AMask: rFIEncoding,
1685 AFMVDX & obj.AMask: rIFEncoding,
1687 // 12.6: Double-Precision Floating-Point Compare Instructions
1688 AFEQD & obj.AMask: rFFIEncoding,
1689 AFLTD & obj.AMask: rFFIEncoding,
1690 AFLED & obj.AMask: rFFIEncoding,
1692 // 12.7: Double-Precision Floating-Point Classify Instruction
1693 AFCLASSD & obj.AMask: rFIEncoding,
1697 // 3.2.1: Environment Call and Breakpoint
1698 AECALL & obj.AMask: iIEncoding,
1699 AEBREAK & obj.AMask: iIEncoding,
1702 AWORD & obj.AMask: rawEncoding,
1704 // Pseudo-operations
1705 obj.AFUNCDATA: pseudoOpEncoding,
1706 obj.APCDATA: pseudoOpEncoding,
1707 obj.ATEXT: pseudoOpEncoding,
1708 obj.ANOP: pseudoOpEncoding,
1709 obj.ADUFFZERO: pseudoOpEncoding,
1710 obj.ADUFFCOPY: pseudoOpEncoding,
1713 // encodingForAs returns the encoding for an obj.As.
1714 func encodingForAs(as obj.As) (encoding, error) {
1715 if base := as &^ obj.AMask; base != obj.ABaseRISCV && base != 0 {
1716 return badEncoding, fmt.Errorf("encodingForAs: not a RISC-V instruction %s", as)
1718 asi := as & obj.AMask
1719 if int(asi) >= len(encodings) {
1720 return badEncoding, fmt.Errorf("encodingForAs: bad RISC-V instruction %s", as)
1722 enc := encodings[asi]
1723 if enc.validate == nil {
1724 return badEncoding, fmt.Errorf("encodingForAs: no encoding for instruction %s", as)
1729 type instruction struct {
1730 as obj.As // Assembler opcode
1731 rd uint32 // Destination register
1732 rs1 uint32 // Source register 1
1733 rs2 uint32 // Source register 2
1734 rs3 uint32 // Source register 3
1735 imm int64 // Immediate
1736 funct3 uint32 // Function 3
1737 funct7 uint32 // Function 7 (or Function 2)
1740 func (ins *instruction) encode() (uint32, error) {
1741 enc, err := encodingForAs(ins.as)
1745 if enc.length <= 0 {
1746 return 0, fmt.Errorf("%v: encoding called for a pseudo instruction", ins.as)
1748 return enc.encode(ins), nil
1751 func (ins *instruction) length() int {
1752 enc, err := encodingForAs(ins.as)
1759 func (ins *instruction) validate(ctxt *obj.Link) {
1760 enc, err := encodingForAs(ins.as)
1762 ctxt.Diag(err.Error())
1765 enc.validate(ctxt, ins)
1768 func (ins *instruction) usesRegTmp() bool {
1769 return ins.rd == REG_TMP || ins.rs1 == REG_TMP || ins.rs2 == REG_TMP
1772 // instructionForProg returns the default *obj.Prog to instruction mapping.
1773 func instructionForProg(p *obj.Prog) *instruction {
1774 ins := &instruction{
1776 rd: uint32(p.To.Reg),
1778 rs2: uint32(p.From.Reg),
1781 if len(p.RestArgs) == 1 {
1782 ins.rs3 = uint32(p.RestArgs[0].Reg)
1787 // instructionsForOpImmediate returns the machine instructions for an immediate
1788 // operand. The instruction is specified by as and the source register is
1789 // specified by rs, instead of the obj.Prog.
1790 func instructionsForOpImmediate(p *obj.Prog, as obj.As, rs int16) []*instruction {
1791 // <opi> $imm, REG, TO
1792 ins := instructionForProg(p)
1793 ins.as, ins.rs1, ins.rs2 = as, uint32(rs), obj.REG_NONE
1795 low, high, err := Split32BitImmediate(ins.imm)
1797 p.Ctxt.Diag("%v: constant %d too large", p, ins.imm, err)
1801 return []*instruction{ins}
1804 // Split into two additions, if possible.
1805 // Do not split SP-writing instructions, as otherwise the recorded SP delta may be wrong.
1806 if p.Spadj == 0 && ins.as == AADDI && ins.imm >= -(1<<12) && ins.imm < 1<<12-1 {
1808 imm1 := ins.imm - imm0
1810 // ADDI $(imm/2), REG, TO
1811 // ADDI $(imm-imm/2), TO, TO
1813 insADDI := &instruction{as: AADDI, rd: ins.rd, rs1: ins.rd, imm: imm1}
1814 return []*instruction{ins, insADDI}
1818 // ADDIW $low, TMP, TMP
1819 // <op> TMP, REG, TO
1820 insLUI := &instruction{as: ALUI, rd: REG_TMP, imm: high}
1821 insADDIW := &instruction{as: AADDIW, rd: REG_TMP, rs1: REG_TMP, imm: low}
1832 p.Ctxt.Diag("unsupported immediate instruction %v for splitting", p)
1837 return []*instruction{insLUI, ins}
1839 return []*instruction{insLUI, insADDIW, ins}
1842 // instructionsForLoad returns the machine instructions for a load. The load
1843 // instruction is specified by as and the base/source register is specified
1844 // by rs, instead of the obj.Prog.
1845 func instructionsForLoad(p *obj.Prog, as obj.As, rs int16) []*instruction {
1846 if p.From.Type != obj.TYPE_MEM {
1847 p.Ctxt.Diag("%v requires memory for source", p)
1852 case ALD, ALB, ALH, ALW, ALBU, ALHU, ALWU, AFLW, AFLD:
1854 p.Ctxt.Diag("%v: unknown load instruction %v", p, as)
1858 // <load> $imm, REG, TO (load $imm+(REG), TO)
1859 ins := instructionForProg(p)
1860 ins.as, ins.rs1, ins.rs2 = as, uint32(rs), obj.REG_NONE
1861 ins.imm = p.From.Offset
1863 low, high, err := Split32BitImmediate(ins.imm)
1865 p.Ctxt.Diag("%v: constant %d too large", p, ins.imm)
1869 return []*instruction{ins}
1873 // ADD TMP, REG, TMP
1874 // <load> $low, TMP, TO
1875 insLUI := &instruction{as: ALUI, rd: REG_TMP, imm: high}
1876 insADD := &instruction{as: AADD, rd: REG_TMP, rs1: REG_TMP, rs2: ins.rs1}
1877 ins.rs1, ins.imm = REG_TMP, low
1879 return []*instruction{insLUI, insADD, ins}
1882 // instructionsForStore returns the machine instructions for a store. The store
1883 // instruction is specified by as and the target/source register is specified
1884 // by rd, instead of the obj.Prog.
1885 func instructionsForStore(p *obj.Prog, as obj.As, rd int16) []*instruction {
1886 if p.To.Type != obj.TYPE_MEM {
1887 p.Ctxt.Diag("%v requires memory for destination", p)
1892 case ASW, ASH, ASB, ASD, AFSW, AFSD:
1894 p.Ctxt.Diag("%v: unknown store instruction %v", p, as)
1898 // <store> $imm, REG, TO (store $imm+(TO), REG)
1899 ins := instructionForProg(p)
1900 ins.as, ins.rd, ins.rs1, ins.rs2 = as, uint32(rd), uint32(p.From.Reg), obj.REG_NONE
1901 ins.imm = p.To.Offset
1903 low, high, err := Split32BitImmediate(ins.imm)
1905 p.Ctxt.Diag("%v: constant %d too large", p, ins.imm)
1909 return []*instruction{ins}
1914 // <store> $low, REG, TMP
1915 insLUI := &instruction{as: ALUI, rd: REG_TMP, imm: high}
1916 insADD := &instruction{as: AADD, rd: REG_TMP, rs1: REG_TMP, rs2: ins.rd}
1917 ins.rd, ins.imm = REG_TMP, low
1919 return []*instruction{insLUI, insADD, ins}
1922 func instructionsForTLS(p *obj.Prog, ins *instruction) []*instruction {
1923 insAddTP := &instruction{as: AADD, rd: REG_TMP, rs1: REG_TMP, rs2: REG_TP}
1925 var inss []*instruction
1926 if p.Ctxt.Flag_shared {
1927 // TLS initial-exec mode - load TLS offset from GOT, add the thread pointer
1928 // register, then load from or store to the resulting memory location.
1929 insAUIPC := &instruction{as: AAUIPC, rd: REG_TMP}
1930 insLoadTLSOffset := &instruction{as: ALD, rd: REG_TMP, rs1: REG_TMP}
1931 inss = []*instruction{insAUIPC, insLoadTLSOffset, insAddTP, ins}
1933 // TLS local-exec mode - load upper TLS offset, add the lower TLS offset,
1934 // add the thread pointer register, then load from or store to the resulting
1935 // memory location. Note that this differs from the suggested three
1936 // instruction sequence, as the Go linker does not currently have an
1937 // easy way to handle relocation across 12 bytes of machine code.
1938 insLUI := &instruction{as: ALUI, rd: REG_TMP}
1939 insADDIW := &instruction{as: AADDIW, rd: REG_TMP, rs1: REG_TMP}
1940 inss = []*instruction{insLUI, insADDIW, insAddTP, ins}
1945 func instructionsForTLSLoad(p *obj.Prog) []*instruction {
1946 if p.From.Sym.Type != objabi.STLSBSS {
1947 p.Ctxt.Diag("%v: %v is not a TLS symbol", p, p.From.Sym)
1951 ins := instructionForProg(p)
1952 ins.as, ins.rs1, ins.rs2, ins.imm = movToLoad(p.As), REG_TMP, obj.REG_NONE, 0
1954 return instructionsForTLS(p, ins)
1957 func instructionsForTLSStore(p *obj.Prog) []*instruction {
1958 if p.To.Sym.Type != objabi.STLSBSS {
1959 p.Ctxt.Diag("%v: %v is not a TLS symbol", p, p.To.Sym)
1963 ins := instructionForProg(p)
1964 ins.as, ins.rd, ins.rs1, ins.rs2, ins.imm = movToStore(p.As), REG_TMP, uint32(p.From.Reg), obj.REG_NONE, 0
1966 return instructionsForTLS(p, ins)
1969 // instructionsForMOV returns the machine instructions for an *obj.Prog that
1970 // uses a MOV pseudo-instruction.
1971 func instructionsForMOV(p *obj.Prog) []*instruction {
1972 ins := instructionForProg(p)
1973 inss := []*instruction{ins}
1976 p.Ctxt.Diag("%v: illegal MOV instruction", p)
1981 case p.From.Type == obj.TYPE_CONST && p.To.Type == obj.TYPE_REG:
1982 // Handle constant to register moves.
1984 p.Ctxt.Diag("%v: unsupported constant load", p)
1988 // For constants larger than 32 bits in size that have trailing zeros,
1989 // use the value with the trailing zeros removed and then use a SLLI
1990 // instruction to restore the original constant.
1992 // MOV $0x8000000000000000, X10
1995 // SLLI $63, X10, X10
1996 var insSLLI *instruction
1997 if err := immIFits(ins.imm, 32); err != nil {
1998 ctz := bits.TrailingZeros64(uint64(ins.imm))
1999 if err := immIFits(ins.imm>>ctz, 32); err == nil {
2000 ins.imm = ins.imm >> ctz
2001 insSLLI = &instruction{as: ASLLI, rd: ins.rd, rs1: ins.rd, imm: int64(ctz)}
2005 low, high, err := Split32BitImmediate(ins.imm)
2007 p.Ctxt.Diag("%v: constant %d too large: %v", p, ins.imm, err)
2011 // MOV $c, R -> ADD $c, ZERO, R
2012 ins.as, ins.rs1, ins.rs2, ins.imm = AADDI, REG_ZERO, obj.REG_NONE, low
2014 // LUI is only necessary if the constant does not fit in 12 bits.
2016 // LUI top20bits(c), R
2017 // ADD bottom12bits(c), R, R
2018 insLUI := &instruction{as: ALUI, rd: ins.rd, imm: high}
2019 inss = []*instruction{insLUI}
2021 ins.as, ins.rs1 = AADDIW, ins.rd
2022 inss = append(inss, ins)
2026 inss = append(inss, insSLLI)
2029 case p.From.Type == obj.TYPE_CONST && p.To.Type != obj.TYPE_REG:
2030 p.Ctxt.Diag("%v: constant load must target register", p)
2033 case p.From.Type == obj.TYPE_REG && p.To.Type == obj.TYPE_REG:
2034 // Handle register to register moves.
2036 case AMOV: // MOV Ra, Rb -> ADDI $0, Ra, Rb
2037 ins.as, ins.rs1, ins.rs2, ins.imm = AADDI, uint32(p.From.Reg), obj.REG_NONE, 0
2038 case AMOVW: // MOVW Ra, Rb -> ADDIW $0, Ra, Rb
2039 ins.as, ins.rs1, ins.rs2, ins.imm = AADDIW, uint32(p.From.Reg), obj.REG_NONE, 0
2040 case AMOVBU: // MOVBU Ra, Rb -> ANDI $255, Ra, Rb
2041 ins.as, ins.rs1, ins.rs2, ins.imm = AANDI, uint32(p.From.Reg), obj.REG_NONE, 255
2042 case AMOVF: // MOVF Ra, Rb -> FSGNJS Ra, Ra, Rb
2043 ins.as, ins.rs1 = AFSGNJS, uint32(p.From.Reg)
2044 case AMOVD: // MOVD Ra, Rb -> FSGNJD Ra, Ra, Rb
2045 ins.as, ins.rs1 = AFSGNJD, uint32(p.From.Reg)
2047 // Use SLLI/SRAI to extend.
2048 ins.as, ins.rs1, ins.rs2 = ASLLI, uint32(p.From.Reg), obj.REG_NONE
2051 } else if p.As == AMOVH {
2054 ins2 := &instruction{as: ASRAI, rd: ins.rd, rs1: ins.rd, imm: ins.imm}
2055 inss = append(inss, ins2)
2056 case AMOVHU, AMOVWU:
2057 // Use SLLI/SRLI to extend.
2058 ins.as, ins.rs1, ins.rs2 = ASLLI, uint32(p.From.Reg), obj.REG_NONE
2061 } else if p.As == AMOVWU {
2064 ins2 := &instruction{as: ASRLI, rd: ins.rd, rs1: ins.rd, imm: ins.imm}
2065 inss = append(inss, ins2)
2068 case p.From.Type == obj.TYPE_MEM && p.To.Type == obj.TYPE_REG:
2069 // Memory to register loads.
2070 switch p.From.Name {
2071 case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE:
2072 // MOV c(Rs), Rd -> L $c, Rs, Rd
2073 inss = instructionsForLoad(p, movToLoad(p.As), addrToReg(p.From))
2075 case obj.NAME_EXTERN, obj.NAME_STATIC:
2076 if p.From.Sym.Type == objabi.STLSBSS {
2077 return instructionsForTLSLoad(p)
2080 // Note that the values for $off_hi and $off_lo are currently
2081 // zero and will be assigned during relocation.
2083 // AUIPC $off_hi, Rd
2084 // L $off_lo, Rd, Rd
2085 insAUIPC := &instruction{as: AAUIPC, rd: ins.rd}
2086 ins.as, ins.rs1, ins.rs2, ins.imm = movToLoad(p.As), ins.rd, obj.REG_NONE, 0
2087 inss = []*instruction{insAUIPC, ins}
2090 p.Ctxt.Diag("unsupported name %d for %v", p.From.Name, p)
2094 case p.From.Type == obj.TYPE_REG && p.To.Type == obj.TYPE_MEM:
2095 // Register to memory stores.
2097 case AMOVBU, AMOVHU, AMOVWU:
2098 p.Ctxt.Diag("%v: unsupported unsigned store", p)
2102 case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE:
2103 // MOV Rs, c(Rd) -> S $c, Rs, Rd
2104 inss = instructionsForStore(p, movToStore(p.As), addrToReg(p.To))
2106 case obj.NAME_EXTERN, obj.NAME_STATIC:
2107 if p.To.Sym.Type == objabi.STLSBSS {
2108 return instructionsForTLSStore(p)
2111 // Note that the values for $off_hi and $off_lo are currently
2112 // zero and will be assigned during relocation.
2114 // AUIPC $off_hi, Rtmp
2115 // S $off_lo, Rtmp, Rd
2116 insAUIPC := &instruction{as: AAUIPC, rd: REG_TMP}
2117 ins.as, ins.rd, ins.rs1, ins.rs2, ins.imm = movToStore(p.As), REG_TMP, uint32(p.From.Reg), obj.REG_NONE, 0
2118 inss = []*instruction{insAUIPC, ins}
2121 p.Ctxt.Diag("unsupported name %d for %v", p.From.Name, p)
2125 case p.From.Type == obj.TYPE_ADDR && p.To.Type == obj.TYPE_REG:
2126 // MOV $sym+off(SP/SB), R
2128 p.Ctxt.Diag("%v: unsupported address load", p)
2131 switch p.From.Name {
2132 case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE:
2133 inss = instructionsForOpImmediate(p, AADDI, addrToReg(p.From))
2135 case obj.NAME_EXTERN, obj.NAME_STATIC:
2136 // Note that the values for $off_hi and $off_lo are currently
2137 // zero and will be assigned during relocation.
2141 insAUIPC := &instruction{as: AAUIPC, rd: ins.rd}
2142 ins.as, ins.rs1, ins.rs2, ins.imm = AADDI, ins.rd, obj.REG_NONE, 0
2143 inss = []*instruction{insAUIPC, ins}
2146 p.Ctxt.Diag("unsupported name %d for %v", p.From.Name, p)
2150 case p.From.Type == obj.TYPE_ADDR && p.To.Type != obj.TYPE_REG:
2151 p.Ctxt.Diag("%v: address load must target register", p)
2155 p.Ctxt.Diag("%v: unsupported MOV", p)
2162 // instructionsForProg returns the machine instructions for an *obj.Prog.
2163 func instructionsForProg(p *obj.Prog) []*instruction {
2164 ins := instructionForProg(p)
2165 inss := []*instruction{ins}
2167 if len(p.RestArgs) > 1 {
2168 p.Ctxt.Diag("too many source registers")
2174 ins.rd, ins.rs1, ins.rs2 = uint32(p.From.Reg), uint32(p.To.Reg), obj.REG_NONE
2175 ins.imm = p.To.Offset
2177 case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ:
2180 ins.as, ins.rs1, ins.rs2 = ABEQ, REG_ZERO, uint32(p.From.Reg)
2182 ins.as, ins.rs1, ins.rs2 = ABGE, REG_ZERO, uint32(p.From.Reg)
2184 ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), uint32(p.Reg)
2186 ins.as, ins.rs1, ins.rs2 = ABLTU, uint32(p.From.Reg), uint32(p.Reg)
2188 ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), REG_ZERO
2190 ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), uint32(p.Reg)
2192 ins.as, ins.rs1, ins.rs2 = ABGEU, uint32(p.From.Reg), uint32(p.Reg)
2194 ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), REG_ZERO
2196 ins.as, ins.rs1, ins.rs2 = ABLT, REG_ZERO, uint32(p.From.Reg)
2198 ins.as, ins.rs1, ins.rs2 = ABNE, REG_ZERO, uint32(p.From.Reg)
2200 ins.imm = p.To.Offset
2202 case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
2203 return instructionsForMOV(p)
2205 case ALW, ALWU, ALH, ALHU, ALB, ALBU, ALD, AFLW, AFLD:
2206 return instructionsForLoad(p, ins.as, p.From.Reg)
2208 case ASW, ASH, ASB, ASD, AFSW, AFSD:
2209 return instructionsForStore(p, ins.as, p.To.Reg)
2212 // Set aq to use acquire access ordering
2214 ins.rs1, ins.rs2 = uint32(p.From.Reg), REG_ZERO
2216 case AADDI, AANDI, AORI, AXORI:
2217 inss = instructionsForOpImmediate(p, ins.as, p.Reg)
2220 // Set release access ordering
2222 ins.rd, ins.rs1, ins.rs2 = uint32(p.RegTo2), uint32(p.To.Reg), uint32(p.From.Reg)
2224 case AAMOSWAPW, AAMOSWAPD, AAMOADDW, AAMOADDD, AAMOANDW, AAMOANDD, AAMOORW, AAMOORD,
2225 AAMOXORW, AAMOXORD, AAMOMINW, AAMOMIND, AAMOMINUW, AAMOMINUD, AAMOMAXW, AAMOMAXD, AAMOMAXUW, AAMOMAXUD:
2226 // Set aqrl to use acquire & release access ordering
2228 ins.rd, ins.rs1, ins.rs2 = uint32(p.RegTo2), uint32(p.To.Reg), uint32(p.From.Reg)
2230 case AECALL, AEBREAK, ARDCYCLE, ARDTIME, ARDINSTRET:
2231 insEnc := encode(p.As)
2232 if p.To.Type == obj.TYPE_NONE {
2236 ins.imm = insEnc.csr
2239 ins.rd, ins.rs1, ins.rs2 = REG_ZERO, REG_ZERO, obj.REG_NONE
2242 case AFCVTWS, AFCVTLS, AFCVTWUS, AFCVTLUS, AFCVTWD, AFCVTLD, AFCVTWUD, AFCVTLUD:
2243 // Set the rounding mode in funct3 to round to zero.
2247 // Replace FNE[SD] with FEQ[SD] and NOT.
2248 if p.To.Type != obj.TYPE_REG {
2249 p.Ctxt.Diag("%v needs an integer register output", ins.as)
2252 if ins.as == AFNES {
2257 ins2 := &instruction{
2258 as: AXORI, // [bit] xor 1 = not [bit]
2263 inss = append(inss, ins2)
2265 case AFSQRTS, AFSQRTD:
2266 // These instructions expect a zero (i.e. float register 0)
2267 // to be the second input operand.
2268 ins.rs1 = uint32(p.From.Reg)
2271 case AFMADDS, AFMSUBS, AFNMADDS, AFNMSUBS,
2272 AFMADDD, AFMSUBD, AFNMADDD, AFNMSUBD:
2273 // Swap the first two operands so that the operands are in the same
2274 // order as they are in the specification: RS1, RS2, RS3, RD.
2275 ins.rs1, ins.rs2 = ins.rs2, ins.rs1
2278 // NEG rs, rd -> SUB rs, X0, rd
2284 if ins.rd == obj.REG_NONE {
2289 // NOT rs, rd -> XORI $-1, rs, rd
2291 ins.rs1, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE
2292 if ins.rd == obj.REG_NONE {
2298 // SEQZ rs, rd -> SLTIU $1, rs, rd
2300 ins.rs1, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE
2304 // SNEZ rs, rd -> SLTU rs, x0, rd
2309 // FABSS rs, rd -> FSGNJXS rs, rs, rd
2311 ins.rs1 = uint32(p.From.Reg)
2314 // FABSD rs, rd -> FSGNJXD rs, rs, rd
2316 ins.rs1 = uint32(p.From.Reg)
2319 // FNEGS rs, rd -> FSGNJNS rs, rs, rd
2321 ins.rs1 = uint32(p.From.Reg)
2324 // FNEGD rs, rd -> FSGNJND rs, rs, rd
2326 ins.rs1 = uint32(p.From.Reg)
2328 case ASLLI, ASRLI, ASRAI:
2329 if ins.imm < 0 || ins.imm > 63 {
2330 p.Ctxt.Diag("%v: shift amount out of range 0 to 63", p)
2333 case ASLLIW, ASRLIW, ASRAIW:
2334 if ins.imm < 0 || ins.imm > 31 {
2335 p.Ctxt.Diag("%v: shift amount out of range 0 to 31", p)
2341 // assemble emits machine code.
2342 // It is called at the very end of the assembly process.
2343 func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
2345 ctxt.Diag("-spectre=ret not supported on riscv")
2346 ctxt.Retpoline = false // don't keep printing
2349 for p := cursym.Func().Text; p != nil; p = p.Link {
2352 if p.Mark&NEED_JAL_RELOC == NEED_JAL_RELOC {
2353 rel := obj.Addrel(cursym)
2354 rel.Off = int32(p.Pc)
2357 rel.Add = p.To.Offset
2358 rel.Type = objabi.R_RISCV_JAL
2361 if p.To.Sym != nil {
2362 ctxt.Diag("%v: unexpected AJALR with to symbol", p)
2365 case AAUIPC, AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
2367 var rt objabi.RelocType
2368 if p.Mark&NEED_CALL_RELOC == NEED_CALL_RELOC {
2369 rt = objabi.R_RISCV_CALL
2371 } else if p.Mark&NEED_PCREL_ITYPE_RELOC == NEED_PCREL_ITYPE_RELOC {
2372 rt = objabi.R_RISCV_PCREL_ITYPE
2374 } else if p.Mark&NEED_PCREL_STYPE_RELOC == NEED_PCREL_STYPE_RELOC {
2375 rt = objabi.R_RISCV_PCREL_STYPE
2382 ctxt.Diag("AUIPC needing PC-relative reloc missing following instruction")
2385 addr = &p.RestArgs[0].Addr
2387 if addr.Sym == nil {
2388 ctxt.Diag("PC-relative relocation missing symbol")
2391 if addr.Sym.Type == objabi.STLSBSS {
2392 if ctxt.Flag_shared {
2393 rt = objabi.R_RISCV_TLS_IE
2395 rt = objabi.R_RISCV_TLS_LE
2399 rel := obj.Addrel(cursym)
2400 rel.Off = int32(p.Pc)
2403 rel.Add = addr.Offset
2408 for _, ins := range instructionsForProg(p) {
2409 if ic, err := ins.encode(); err == nil {
2410 cursym.WriteInt(ctxt, offset, ins.length(), int64(ic))
2411 offset += int64(ins.length())
2413 if ins.usesRegTmp() {
2414 p.Mark |= USES_REG_TMP
2419 obj.MarkUnsafePoints(ctxt, cursym.Func().Text, newprog, isUnsafePoint, nil)
2422 func isUnsafePoint(p *obj.Prog) bool {
2423 return p.Mark&USES_REG_TMP == USES_REG_TMP || p.From.Reg == REG_TMP || p.To.Reg == REG_TMP || p.Reg == REG_TMP
2426 var LinkRISCV64 = obj.LinkArch{
2427 Arch: sys.ArchRISCV64,
2429 Preprocess: preprocess,
2433 DWARFRegisters: RISCV64DWARFRegisters,