diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -19,6 +19,7 @@ #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCValue.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Endian.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/ErrorHandling.h" @@ -27,6 +28,9 @@ using namespace llvm; +static cl::opt RelaxBranches("riscv-asm-relax-branches", cl::init(true), + cl::Hidden); + std::optional RISCVAsmBackend::getFixupKind(StringRef Name) const { if (STI.getTargetTriple().isOSBinFormatELF()) { unsigned Type; @@ -144,6 +148,9 @@ const MCRelaxableFragment *DF, const MCAsmLayout &Layout, const bool WasForced) const { + if (!RelaxBranches) + return false; + int64_t Offset = int64_t(Value); unsigned Kind = Fixup.getTargetKind(); @@ -483,6 +490,8 @@ return UpperImm | ((LowerImm << 20) << 32); } case RISCV::fixup_riscv_rvc_jump: { + if (!isInt<12>(Value)) + Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); // Need to produce offset[11|4|9:8|10|6|7|3:1|5] from the 11-bit Value. unsigned Bit11 = (Value >> 11) & 0x1; unsigned Bit4 = (Value >> 4) & 0x1; @@ -497,6 +506,8 @@ return Value; } case RISCV::fixup_riscv_rvc_branch: { + if (!isInt<9>(Value)) + Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); // Need to produce offset[8|4:3], [reg 3 bit], offset[7:6|2:1|5] unsigned Bit8 = (Value >> 8) & 0x1; unsigned Bit7_6 = (Value >> 6) & 0x3; diff --git a/llvm/test/MC/RISCV/long-jump-disable-relax.s b/llvm/test/MC/RISCV/long-jump-disable-relax.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/long-jump-disable-relax.s @@ -0,0 +1,47 @@ +## Test that long branches are not relaxed with -riscv-asm-relax-branches=0 +# RUN: split-file %s %t +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c \ +# RUN: -riscv-asm-relax-branches=0 %t/pass.s \ +# RUN: | llvm-objdump -dr -M no-aliases - \ +# RUN: | FileCheck %t/pass.s +# RUN: not llvm-mc -filetype=obj -triple=riscv64 -mattr=+c -o /dev/null \ +# RUN: -riscv-asm-relax-branches=0 %t/fail.s 2>&1 \ +# RUN: | FileCheck %t/fail.s + +#--- pass.s + .text +test_undefined: +## Branches to undefined symbols should not be relaxed +# CHECK: bne a0, a1, {{.*}} +# CHECK-NEXT: R_RISCV_BRANCH foo + bne a0, a1, foo +# CHECK: c.beqz a0, {{.*}} +# CHECK-NEXT: R_RISCV_RVC_BRANCH foo + c.beqz a0, foo +# CHECK: c.j {{.*}} +# CHECK-NEXT: R_RISCV_RVC_JUMP foo + c.j foo + +## Branches to defined in-range symbols should work normally +test_defined_in_range: +# CHECK: bne a0, a1, {{.*}} + bne a0, a1, bar +# CHECK: c.beqz a0, {{.*}} + c.beqz a0, bar +# CHECK: c.j {{.*}} + c.j bar +bar: + +#--- fail.s + .text +## Branches to defined out-of-range symbols should report an error +test_defined_out_of_range: + bne a0, a1, 1f # CHECK: :[[#@LINE]]:3: error: fixup value out of range + .skip (1 << 12) +1: + c.beqz a0, 1f # CHECK: :[[#@LINE]]:3: error: fixup value out of range + .skip (1 << 8) +1: + c.j 1f # CHECK: :[[#@LINE]]:3: error: fixup value out of range + .skip (1 << 11) +1: