diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/riscv.h b/llvm/include/llvm/ExecutionEngine/JITLink/riscv.h --- a/llvm/include/llvm/ExecutionEngine/JITLink/riscv.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/riscv.h @@ -37,6 +37,13 @@ /// R_RISCV_64, + /// Low 12 bits of PC-relative branch pointer value relocation + /// + /// Fixup expression: + /// Fixup <- (Target - Fixup + Addend) & 0xFFF + /// + R_RISCV_BRANCH, + /// High 20 bits of 32-bit pointer value relocation /// /// Fixup expression diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp --- a/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp @@ -162,6 +162,17 @@ return (Num & (((1ULL << (Size + 1)) - 1) << Low)) >> Low; } +inline Error checkAlignment(llvm::orc::ExecutorAddr loc, uint64_t v, int n, + const Edge &E) { + if (v & (n - 1)) + return make_error("0x" + llvm::utohexstr(loc.getValue()) + + " improper alignment for relocation " + + formatv("{0:d}", E.getKind()) + ": 0x" + + llvm::utohexstr(v) + " is not aligned to " + + Twine(n) + " bytes"); + return Error::success(); +} + static inline bool isInRangeForImmS32(int64_t Value) { return (Value >= std::numeric_limits::min() && Value <= std::numeric_limits::max()); @@ -194,6 +205,21 @@ *(little64_t *)FixupPtr = static_cast(Value); break; } + case R_RISCV_BRANCH: { + int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress; + Error AlignmentIssue = checkAlignment(FixupAddress, Value, 2, E); + if (AlignmentIssue) { + return AlignmentIssue; + } + int64_t Lo = Value & 0xFFF; + uint32_t Imm31_25 = extractBits(Lo, 5, 6) << 25 | extractBits(Lo, 12, 1) + << 31; + uint32_t Imm11_7 = extractBits(Lo, 1, 4) << 8 | extractBits(Lo, 11, 1) + << 7; + uint32_t RawInstr = *(little32_t *)FixupPtr; + *(little32_t *)FixupPtr = (RawInstr & 0x1FFF07F) | Imm31_25 | Imm11_7; + break; + } case R_RISCV_HI20: { int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue(); int64_t Hi = Value + 0x800; @@ -284,6 +310,8 @@ return EdgeKind_riscv::R_RISCV_32; case ELF::R_RISCV_64: return EdgeKind_riscv::R_RISCV_64; + case ELF::R_RISCV_BRANCH: + return EdgeKind_riscv::R_RISCV_BRANCH; case ELF::R_RISCV_HI20: return EdgeKind_riscv::R_RISCV_HI20; case ELF::R_RISCV_LO12_I: diff --git a/llvm/lib/ExecutionEngine/JITLink/riscv.cpp b/llvm/lib/ExecutionEngine/JITLink/riscv.cpp --- a/llvm/lib/ExecutionEngine/JITLink/riscv.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/riscv.cpp @@ -24,6 +24,8 @@ return "R_RISCV_32"; case R_RISCV_64: return "R_RISCV_64"; + case R_RISCV_BRANCH: + return "R_RISCV_BRANCH"; case R_RISCV_HI20: return "R_RISCV_HI20"; case R_RISCV_LO12_I: diff --git a/llvm/test/ExecutionEngine/JITLink/RISCV/ELF_branch.s b/llvm/test/ExecutionEngine/JITLink/RISCV/ELF_branch.s new file mode 100644 --- /dev/null +++ b/llvm/test/ExecutionEngine/JITLink/RISCV/ELF_branch.s @@ -0,0 +1,37 @@ +# RUN: rm -rf %t && mkdir -p %t +# RUN: llvm-mc -triple=riscv64 -filetype=obj \ +# RUN: -o %t/elf_riscv64_branch.o %s +# RUN: llvm-mc -triple=riscv32 -filetype=obj \ +# RUN: -o %t/elf_riscv32_branch.o %s +# RUN: llvm-jitlink -noexec \ +# RUN: -slab-allocate 100Kb -slab-address 0xfff00000 -slab-page-size 4096 \ +# RUN: -define-abs external_func=0xfe \ +# RUN: -check %s %t/elf_riscv64_branch.o +# RUN: llvm-jitlink -noexec \ +# RUN: -slab-allocate 100Kb -slab-address 0xfff00000 -slab-page-size 4096 \ +# RUN: -define-abs external_func=0xfe \ +# RUN: -check %s %t/elf_riscv32_branch.o +# + + .text + .file "testcase.c" + +# Empty main entry point. + .globl main + .p2align 1 + .type main,@function +main: + ret + + .size main, .-main + +# Test R_RISCV_BRANCH + +# jitlink-check: decode_operand(test_branch, 2)[11:0] = (external_func - test_branch)[11:0] + .globl test_branch + .p2align 1 + .type test_branch,@function +test_branch: + bge a0, a1, external_func + + .size test_branch, .-test_branch