[lld] [llvm] [RISCV] add new relocation type for global array accesses with non-constant indices (PR #207901)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 28 23:09:51 PDT 2026
https://github.com/LiqinWeng updated https://github.com/llvm/llvm-project/pull/207901
>From 98cdf6d0e8189cd9b1b0cf2d516daf00a2fcd49b Mon Sep 17 00:00:00 2001
From: wengliqin <liqin.weng at spacemit.com>
Date: Tue, 7 Jul 2026 11:07:34 +0800
Subject: [PATCH 1/3] [RISCV] add new relocation type for global array accesses
with non-constant indices
psABI: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/489
---
lld/ELF/Arch/RISCV.cpp | 49 +++++++++
lld/test/ELF/riscv-base-idx-add.s | 71 ++++++++++++
lld/test/ELF/riscv-base-idx-shxadd.s | 69 ++++++++++++
.../llvm/BinaryFormat/ELFRelocs/RISCV.def | 3 +
.../Target/RISCV/AsmParser/RISCVAsmParser.cpp | 14 ++-
.../Target/RISCV/MCTargetDesc/RISCVBaseInfo.h | 2 +
.../RISCV/MCTargetDesc/RISCVMCAsmInfo.h | 1 +
.../RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp | 101 +++++++++++++++++-
.../Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp | 6 ++
llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp | 6 ++
llvm/lib/Target/RISCV/RISCVInstrFormats.td | 11 ++
llvm/lib/Target/RISCV/RISCVInstrInfo.cpp | 2 +
llvm/lib/Target/RISCV/RISCVInstrInfo.td | 22 +++-
llvm/lib/Target/RISCV/RISCVInstrInfoZb.td | 17 +++
llvm/test/MC/RISCV/Relocations/mc-dump.s | 2 +-
llvm/test/MC/RISCV/Relocations/relocations.s | 54 +++++++++-
llvm/test/MC/RISCV/rv32zba-invalid.s | 16 +++
llvm/test/MC/RISCV/rv64zba-invalid.s | 36 +++++++
18 files changed, 471 insertions(+), 11 deletions(-)
create mode 100644 lld/test/ELF/riscv-base-idx-add.s
create mode 100644 lld/test/ELF/riscv-base-idx-shxadd.s
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 49c41ff9ebe84..cc233f357e2dc 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -74,6 +74,9 @@ class RISCV final : public TargetInfo {
#define INTERNAL_R_RISCV_GPREL_S 257
#define INTERNAL_R_RISCV_X0REL_I 258
#define INTERNAL_R_RISCV_X0REL_S 259
+#define INTERNAL_R_RISCV_BASE_IDX_ADD 260
+#define INTERNAL_R_RISCV_BASE_IDX_LO12_I 261
+#define INTERNAL_R_RISCV_BASE_IDX_LO12_S 262
const uint64_t dtpOffset = 0x800;
@@ -381,6 +384,9 @@ void RISCV::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels,
case R_RISCV_HI20:
case R_RISCV_LO12_I:
case R_RISCV_LO12_S:
+ case R_RISCV_BASE_IDX_ADD:
+ case R_RISCV_BASE_IDX_LO12_I:
+ case R_RISCV_BASE_IDX_LO12_S:
expr = R_ABS;
break;
@@ -623,6 +629,7 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
case R_RISCV_TLSDESC_LOAD_LO12:
case R_RISCV_TLSDESC_ADD_LO12:
case R_RISCV_TPREL_LO12_I:
+ case R_RISCV_BASE_IDX_LO12_I:
case R_RISCV_LO12_I: {
uint64_t hi = (val + 0x800) >> 12;
uint64_t lo = val - (hi << 12);
@@ -632,6 +639,7 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
case R_RISCV_PCREL_LO12_S:
case R_RISCV_TPREL_LO12_S:
+ case R_RISCV_BASE_IDX_LO12_S:
case R_RISCV_LO12_S: {
uint64_t hi = (val + 0x800) >> 12;
uint64_t lo = val - (hi << 12);
@@ -639,6 +647,32 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
return;
}
+ case R_RISCV_BASE_IDX_ADD: {
+ write32le(loc, read32le(loc));
+ return;
+ }
+
+ case INTERNAL_R_RISCV_BASE_IDX_ADD: {
+ uint32_t insn = (read32le(loc) & ~(31 << 20)) | (X_GP << 20);
+ write32le(loc, insn);
+ return;
+ }
+
+ case INTERNAL_R_RISCV_BASE_IDX_LO12_I:
+ case INTERNAL_R_RISCV_BASE_IDX_LO12_S: {
+ Defined *gp = ctx.sym.riscvGlobalPointer;
+ int64_t displace = SignExtend64(val - gp->getVA(ctx), bits);
+ checkInt(ctx, loc, displace, 12, rel);
+ uint32_t insn = read32le(loc);
+ if (rel.type == INTERNAL_R_RISCV_BASE_IDX_LO12_I)
+ insn = setLO12_I(insn, displace);
+ else
+ insn = setLO12_S(insn, displace);
+
+ write32le(loc, insn);
+ return;
+ }
+
case INTERNAL_R_RISCV_X0REL_I:
case INTERNAL_R_RISCV_X0REL_S: {
checkInt(ctx, loc, val, 12, rel);
@@ -1027,6 +1061,15 @@ static void relaxHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
case R_RISCV_LO12_S:
sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_S;
break;
+ case R_RISCV_BASE_IDX_ADD:
+ sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_BASE_IDX_ADD;
+ break;
+ case R_RISCV_BASE_IDX_LO12_I:
+ sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_BASE_IDX_LO12_I;
+ break;
+ case R_RISCV_BASE_IDX_LO12_S:
+ sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_BASE_IDX_LO12_S;
+ break;
}
}
@@ -1082,6 +1125,9 @@ static bool relax(Ctx &ctx, int pass, InputSection &sec) {
case R_RISCV_HI20:
case R_RISCV_LO12_I:
case R_RISCV_LO12_S:
+ case R_RISCV_BASE_IDX_ADD:
+ case R_RISCV_BASE_IDX_LO12_I:
+ case R_RISCV_BASE_IDX_LO12_S:
if (relaxable(relocs, i))
relaxHi20Lo12(ctx, sec, i, loc, r, remove);
break;
@@ -1335,6 +1381,9 @@ void RISCV::finalizeRelax(int passes) const {
case INTERNAL_R_RISCV_GPREL_S:
case INTERNAL_R_RISCV_X0REL_I:
case INTERNAL_R_RISCV_X0REL_S:
+ case INTERNAL_R_RISCV_BASE_IDX_ADD:
+ case INTERNAL_R_RISCV_BASE_IDX_LO12_I:
+ case INTERNAL_R_RISCV_BASE_IDX_LO12_S:
break;
case R_RISCV_RELAX:
// Used by relaxTlsLe to indicate the relocation is ignored.
diff --git a/lld/test/ELF/riscv-base-idx-add.s b/lld/test/ELF/riscv-base-idx-add.s
new file mode 100644
index 0000000000000..17db2ce3e0a3a
--- /dev/null
+++ b/lld/test/ELF/riscv-base-idx-add.s
@@ -0,0 +1,71 @@
+# REQUIRES: riscv
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+# RUN: llvm-mc -filetype=obj -triple=riscv32-unknown-elf -mattr=+relax a.s -o rv32.o
+# RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf -mattr=+relax a.s -o rv64.o
+
+# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv32.o lds -o rv32
+# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv64.o lds -o rv64
+# RUN: llvm-objdump -td -M no-aliases --no-show-raw-insn rv32 | FileCheck %s
+# RUN: llvm-objdump -td -M no-aliases --no-show-raw-insn rv64 | FileCheck %s
+
+# CHECK: 00000000 l .text {{0*}}0 $x
+
+# CHECK-NOT: lui
+# CHECK: addi a1, a1, -0x800
+# CHECK-NEXT: add a0, a0, gp
+# CHECK-NEXT: lw a0, -0x800(a0)
+# CHECK-NEXT: sw a0, -0x800(a0)
+# CHECK-NOT: lui
+# CHECK-NEXT: addi a1, a1, 0x7fa
+# CHECK-NEXT: add a0, a0, gp
+# CHECK-NEXT: lw a0, 0x7fa(a0)
+# CHECK-NEXT: sw a0, 0x7fa(a0)
+# CHECK-NEXT: lui a1, 0x201
+# CHECK-NEXT: addi a1, a1, 0xe
+# CHECK-NEXT: add a0, a0, a1
+# CHECK-NEXT: lw a0, 0xe(a0)
+# CHECK-NEXT: sw a0, 0xe(a0)
+# CHECK-EMPTY:
+# CHECK-NEXT: <a>:
+# CHECK-NEXT: addi a0, a0, 0x1
+
+#--- a.s
+.global _start
+_start:
+ slli a0, a0, 2
+ lui a1, %hi(array)
+ addi a1, a1, %base_idx_lo(array)
+ add a0, a0, a1, %base_idx_add(array)
+ lw a0, %base_idx_lo(array)(a0)
+ sw a0, %base_idx_lo(array)(a0)
+ lui a1, %hi(array1+10)
+ addi a1, a1, %base_idx_lo(array1+10)
+ add a0, a0, a1, %base_idx_add(array1+10)
+ lw a0, %base_idx_lo(array1+10)(a0)
+ sw a0, %base_idx_lo(array1+10)(a0)
+ lui a1, %hi(norelax+10)
+ addi a1, a1, %base_idx_lo(norelax+10)
+ add a0, a0, a1, %base_idx_add(norelax+10)
+ lw a0, %base_idx_lo(norelax+10)(a0)
+ sw a0, %base_idx_lo(norelax+10)(a0)
+a:
+ addi a0, a0, 1
+
+.section .sdata,"aw"
+array:
+ .zero 4080
+ .size array, 4080
+array1:
+ .zero 20
+ .size array, 20
+norelax:
+ .zero 6
+ .size array, 6
+
+#--- lds
+SECTIONS {
+ .text : {*(.text) }
+ .sdata 0x200000 : { }
+}
+
diff --git a/lld/test/ELF/riscv-base-idx-shxadd.s b/lld/test/ELF/riscv-base-idx-shxadd.s
new file mode 100644
index 0000000000000..32f2d97e668df
--- /dev/null
+++ b/lld/test/ELF/riscv-base-idx-shxadd.s
@@ -0,0 +1,69 @@
+# REQUIRES: riscv
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+# RUN: llvm-mc -filetype=obj -triple=riscv32-unknown-elf -mattr=+relax,+zba a.s -o rv32.o
+# RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf -mattr=+relax,+zba a.s -o rv64.o
+
+# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv32.o lds -o rv32
+# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv64.o lds -o rv64
+# RUN: llvm-objdump --mattr=+zba -td -M no-aliases --no-show-raw-insn rv32 | FileCheck %s
+# RUN: llvm-objdump --mattr=+zba -td -M no-aliases --no-show-raw-insn rv64 | FileCheck %s
+
+# CHECK: 00000000 l .text {{0*}}0 $x
+
+# CHECK-NOT: lui
+# CHECK: addi a1, a1, -0x800
+# CHECK-NEXT: sh1add a0, a0, gp
+# CHECK-NEXT: lw a0, -0x800(a0)
+# CHECK-NEXT: sw a0, -0x800(a0)
+# CHECK-NOT: lui
+# CHECK-NEXT: addi a1, a1, 0x7fa
+# CHECK-NEXT: sh1add a0, a0, gp
+# CHECK-NEXT: lw a0, 0x7fa(a0)
+# CHECK-NEXT: sw a0, 0x7fa(a0)
+# CHECK-NEXT: lui a1, 0x201
+# CHECK-NEXT: addi a1, a1, 0xe
+# CHECK-NEXT: sh1add a0, a0, a1
+# CHECK-NEXT: lw a0, 0xe(a0)
+# CHECK-NEXT: sw a0, 0xe(a0)
+# CHECK-EMPTY:
+# CHECK-NEXT: <a>:
+# CHECK-NEXT: addi a0, a0, 0x1
+
+#--- a.s
+.global _start
+_start:
+ lui a1, %hi(array)
+ addi a1, a1, %base_idx_lo(array)
+ sh1add a0, a0, a1, %base_idx_add(array)
+ lw a0, %base_idx_lo(array)(a0)
+ sw a0, %base_idx_lo(array)(a0)
+ lui a1, %hi(array1+10)
+ addi a1, a1, %base_idx_lo(array1+10)
+ sh1add a0, a0, a1, %base_idx_add(array1+10)
+ lw a0, %base_idx_lo(array1+10)(a0)
+ sw a0, %base_idx_lo(array1+10)(a0)
+ lui a1, %hi(norelax+10)
+ addi a1, a1, %base_idx_lo(norelax+10)
+ sh1add a0, a0, a1, %base_idx_add(norelax+10)
+ lw a0, %base_idx_lo(norelax+10)(a0)
+ sw a0, %base_idx_lo(norelax+10)(a0)
+a:
+ addi a0, a0, 1
+
+.section .sdata,"aw"
+array:
+ .zero 4080
+ .size array, 4080
+array1:
+ .zero 20
+ .size array, 20
+norelax:
+ .zero 6
+ .size array, 6
+
+#--- lds
+SECTIONS {
+ .text : {*(.text) }
+ .sdata 0x200000 : { }
+}
diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def
index ac9a089e853a6..1e9610ea1fe67 100644
--- a/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def
+++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def
@@ -60,6 +60,9 @@ ELF_RELOC(R_RISCV_TLSDESC_HI20, 62)
ELF_RELOC(R_RISCV_TLSDESC_LOAD_LO12, 63)
ELF_RELOC(R_RISCV_TLSDESC_ADD_LO12, 64)
ELF_RELOC(R_RISCV_TLSDESC_CALL, 65)
+ELF_RELOC(R_RISCV_BASE_IDX_LO12_I, 77)
+ELF_RELOC(R_RISCV_BASE_IDX_LO12_S, 78)
+ELF_RELOC(R_RISCV_BASE_IDX_ADD, 79)
ELF_RELOC(R_RISCV_VENDOR, 191)
ELF_RELOC(R_RISCV_CUSTOM192, 192)
ELF_RELOC(R_RISCV_CUSTOM193, 193)
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 8563f678464a6..428b08a4527f4 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -640,6 +640,17 @@ struct RISCVOperand final : public MCParsedAsmOperand {
VK == ELF::R_RISCV_TPREL_ADD;
}
+ bool isBaseIdxAddSymbol() const {
+ int64_t Imm;
+ // Must be of 'immediate' type but not a constant.
+ if (!isExpr() || evaluateConstantExpr(getExpr(), Imm))
+ return false;
+
+ RISCV::Specifier VK = RISCV::S_None;
+ return RISCVAsmParser::classifySymbolRef(getExpr(), VK) &&
+ (VK == ELF::R_RISCV_BASE_IDX_ADD);
+ }
+
bool isTLSDESCCallSymbol() const {
int64_t Imm;
// Must be of 'immediate' type but not a constant.
@@ -952,7 +963,8 @@ struct RISCVOperand final : public MCParsedAsmOperand {
RISCV::Specifier VK = RISCV::S_None;
return RISCVAsmParser::classifySymbolRef(getExpr(), VK) &&
(VK == RISCV::S_LO || VK == RISCV::S_PCREL_LO ||
- VK == RISCV::S_TPREL_LO || VK == ELF::R_RISCV_TLSDESC_LOAD_LO12 ||
+ VK == RISCV::S_BASE_IDX_LO || VK == RISCV::S_TPREL_LO ||
+ VK == ELF::R_RISCV_TLSDESC_LOAD_LO12 ||
VK == ELF::R_RISCV_TLSDESC_ADD_LO12);
}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
index e54d57d9f4451..b75ac8a6b3618 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
@@ -483,6 +483,8 @@ enum {
MO_TLSDESC_ADD_LO = 15,
MO_TLSDESC_CALL = 16,
MO_QC_ACCESS = 17,
+ MO_BASE_IDX_LO = 18,
+ MO_BASE_IDX_ADD = 19,
// Used to differentiate between target-specific "direct" flags and "bitmask"
// flags. A machine operand can only have one "direct" flag, but can have
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h
index cb966c56035a3..49c384d19b22b 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h
@@ -41,6 +41,7 @@ enum {
S_LO = FirstTargetFixupKind,
S_PCREL_LO,
S_PCREL_HI,
+ S_BASE_IDX_LO,
S_TPREL_LO,
S_CALL_PLT,
S_GOT_HI,
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
index 23cbbf0954cd7..d53fcd9c3d6fc 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
@@ -64,6 +64,10 @@ class RISCVMCCodeEmitter : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+ void expandAddBaseIdx(const MCInst &MI, SmallVectorImpl<char> &CB,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
void expandLongCondBr(const MCInst &MI, SmallVectorImpl<char> &CB,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
@@ -321,6 +325,68 @@ void RISCVMCCodeEmitter::expandAddTPRel(const MCInst &MI,
support::endian::write(CB, Binary, llvm::endianness::little);
}
+static unsigned getAddOpAndFixups(unsigned AddOp) {
+ switch (AddOp) {
+ default:
+ llvm_unreachable("Unexpected ADD or SHXADD Opcode on GP-relative!");
+ case RISCV::PseudoAddBaseIdx:
+ return RISCV::ADD;
+ case RISCV::PseudoAddUWBaseIdx:
+ return RISCV::ADD_UW;
+ case RISCV::PseudoSh1AddBaseIdx:
+ return RISCV::SH1ADD;
+ case RISCV::PseudoSh2AddBaseIdx:
+ return RISCV::SH2ADD;
+ case RISCV::PseudoSh3AddBaseIdx:
+ return RISCV::SH3ADD;
+ case RISCV::PseudoSh1AddUWBaseIdx:
+ return RISCV::SH1ADD_UW;
+ case RISCV::PseudoSh2AddUWBaseIdx:
+ return RISCV::SH2ADD_UW;
+ case RISCV::PseudoSh3AddUWBaseIdx:
+ return RISCV::SH3ADD_UW;
+ }
+}
+
+// Pseudo ADD/SHXADD (base-index variant) to a simple ADD or SHXADD with the
+// correct relocation.
+void RISCVMCCodeEmitter::expandAddBaseIdx(const MCInst &MI,
+ SmallVectorImpl<char> &CB,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ MCOperand DestReg = MI.getOperand(0);
+ // At link time rs2 of the add/shXadd may be rewritten to gp (or zero for
+ // abs-near) when the symbol can be reached via gp-relative addressing.
+ MCOperand Src1 = MI.getOperand(1);
+ MCOperand Src2 = MI.getOperand(2);
+
+ MCOperand SrcSymbol = MI.getOperand(3);
+ assert(SrcSymbol.isExpr() &&
+ "Expected expression as third input to GP-relative add");
+
+ const auto *Expr = dyn_cast<MCSpecifierExpr>(SrcSymbol.getExpr());
+ assert(Expr && (Expr->getSpecifier() == ELF::R_RISCV_BASE_IDX_ADD) &&
+ "Expected expression as third input to base+index add");
+
+ unsigned BuildOpcode = getAddOpAndFixups(MI.getOpcode());
+
+ // Emit the correct base_idx_add relocation for the symbol.
+ addFixup(Fixups, 0, Expr, ELF::R_RISCV_BASE_IDX_ADD);
+
+ // Emit base_idx_add where the relax feature is enabled.
+ if (STI.hasFeature(RISCV::FeatureRelax)) {
+ Fixups.back().setLinkerRelaxable();
+ }
+
+ // Emit a normal ADD or SHXADD instruction with the given operands.
+ MCInst TmpInst = MCInstBuilder(BuildOpcode)
+ .addOperand(DestReg)
+ .addOperand(Src1)
+ .addOperand(Src2);
+ uint32_t Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI);
+ support::endian::write(CB, Binary, llvm::endianness::little);
+}
+
static unsigned getInvertedBranchOp(unsigned BrOp) {
switch (BrOp) {
default:
@@ -589,6 +655,17 @@ void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI,
expandAddTPRel(MI, CB, Fixups, STI);
MCNumEmitted += 1;
return;
+ case RISCV::PseudoAddBaseIdx:
+ case RISCV::PseudoAddUWBaseIdx:
+ case RISCV::PseudoSh1AddBaseIdx:
+ case RISCV::PseudoSh2AddBaseIdx:
+ case RISCV::PseudoSh3AddBaseIdx:
+ case RISCV::PseudoSh1AddUWBaseIdx:
+ case RISCV::PseudoSh2AddUWBaseIdx:
+ case RISCV::PseudoSh3AddUWBaseIdx:
+ expandAddBaseIdx(MI, CB, Fixups, STI);
+ MCNumEmitted += 1;
+ return;
case RISCV::PseudoLongBEQ:
case RISCV::PseudoLongBNE:
case RISCV::PseudoLongBEQI:
@@ -807,12 +884,16 @@ uint64_t RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo,
"invalid specifier");
break;
case ELF::R_RISCV_TPREL_ADD:
- // tprel_add is only used to indicate that a relocation should be emitted
- // for an add instruction used in TP-relative addressing. It should not be
- // expanded as if representing an actual instruction operand and so to
- // encounter it here is an error.
+ case ELF::R_RISCV_BASE_IDX_ADD:
+ // tprel_add / base_idx_add are only used to indicate that a relocation
+ // should be emitted for an add instruction used in TP-relative or
+ // base+index addressing. They should not be expanded as if representing
+ // an actual instruction operand and so to encounter them here is an
+ // error.
+
llvm_unreachable(
- "ELF::R_RISCV_TPREL_ADD should not represent an instruction operand");
+ "R_RISCV_TPREL_ADD or R_RISCV_BASE_IDX_ADD should not represent "
+ "an instruction operand");
case RISCV::S_QC_ACCESS:
// The same logic for tprel_add applies to S_QC_ACCESS, for similar
// reasons, but we use a specifier becuase %qc.access() gets expanded
@@ -832,6 +913,16 @@ uint64_t RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo,
FixupKind = RISCV::fixup_riscv_hi20;
RelaxCandidate = true;
break;
+ case RISCV::S_BASE_IDX_LO:
+ if (MIFrm == RISCVII::InstFormatI)
+ FixupKind = ELF::R_RISCV_BASE_IDX_LO12_I;
+ else if (MIFrm == RISCVII::InstFormatS)
+ FixupKind = ELF::R_RISCV_BASE_IDX_LO12_S;
+ else
+ llvm_unreachable(
+ "S_BASE_IDX_LO used with unexpected instruction format");
+ RelaxCandidate = true;
+ break;
case RISCV::S_PCREL_LO:
if (MIFrm == RISCVII::InstFormatI)
FixupKind = RISCV::fixup_riscv_pcrel_lo12_i;
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
index cf9db21a47dcb..8781906b46e83 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
@@ -24,6 +24,8 @@ RISCV::Specifier RISCV::parseSpecifierName(StringRef name) {
return StringSwitch<RISCV::Specifier>(name)
.Case("lo", RISCV::S_LO)
.Case("hi", ELF::R_RISCV_HI20)
+ .Case("base_idx_lo", RISCV::S_BASE_IDX_LO)
+ .Case("base_idx_add", ELF::R_RISCV_BASE_IDX_ADD)
.Case("pcrel_lo", RISCV::S_PCREL_LO)
.Case("pcrel_hi", RISCV::S_PCREL_HI)
.Case("got_pcrel_hi", RISCV::S_GOT_HI)
@@ -52,6 +54,10 @@ StringRef RISCV::getSpecifierName(Specifier S) {
return "lo";
case ELF::R_RISCV_HI20:
return "hi";
+ case RISCV::S_BASE_IDX_LO:
+ return "base_idx_lo";
+ case ELF::R_RISCV_BASE_IDX_ADD:
+ return "base_idx_add";
case RISCV::S_PCREL_LO:
return "pcrel_lo";
case RISCV::S_PCREL_HI:
diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
index e37ea27364e6e..e0c4cb85431d0 100644
--- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
+++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
@@ -1079,6 +1079,12 @@ static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym,
case RISCVII::MO_HI:
Kind = ELF::R_RISCV_HI20;
break;
+ case RISCVII::MO_BASE_IDX_LO:
+ Kind = RISCV::S_BASE_IDX_LO;
+ break;
+ case RISCVII::MO_BASE_IDX_ADD:
+ Kind = ELF::R_RISCV_BASE_IDX_ADD;
+ break;
case RISCVII::MO_PCREL_LO:
Kind = RISCV::S_PCREL_LO;
break;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrFormats.td b/llvm/lib/Target/RISCV/RISCVInstrFormats.td
index b945fa957072e..2a6080721f92f 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrFormats.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrFormats.td
@@ -365,6 +365,17 @@ class PseudoStore<string opcodestr, DAGOperand rsty = GPR>
let isCodeGenOnly = 0;
}
+// Pseudo add or shxadd instructions.
+class PseudoBaseIdx<string opcodestr>
+ : Pseudo<(outs GPR:$rd),
+ (ins GPR:$rs1, GPR:$rs2, base_idx_add_symbol:$src), [], opcodestr,
+ "$rd, $rs1, $rs2, $src"> {
+ let hasSideEffects = 0;
+ let mayLoad = 1;
+ let mayStore = 0;
+ let isCodeGenOnly = 0;
+}
+
// Instruction formats are listed in the order they appear in the RISC-V
// instruction set manual (R, R4, I, S, B, U, J).
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index 50f548857a97b..976bec1cace5d 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -3613,6 +3613,8 @@ RISCVInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
{MO_CALL, "riscv-call"},
{MO_LO, "riscv-lo"},
{MO_HI, "riscv-hi"},
+ {MO_BASE_IDX_LO, "riscv-base-idx-lo"},
+ {MO_BASE_IDX_ADD, "riscv-base-idx-add"},
{MO_PCREL_LO, "riscv-pcrel-lo"},
{MO_PCREL_HI, "riscv-pcrel-hi"},
{MO_GOT_HI, "riscv-got-hi"},
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index ca506b8013212..317caf688e00a 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -486,6 +486,19 @@ def tprel_add_symbol : Operand<XLenVT> {
let ParserMatchClass = TPRelAddSymbol;
}
+def BaseIdxAddSymbol : AsmOperandClass {
+ let Name = "BaseIdxAddSymbol";
+ let RenderMethod = "addImmOperands";
+ let DiagnosticType = "InvalidBaseIdxAddSymbol";
+ let DiagnosticString = "operand must be a symbol with %base_idx_add specifier";
+ let ParserMethod = "parseOperandWithSpecifier";
+}
+
+// A symbol with the %base_idx_add variant.
+def base_idx_add_symbol : Operand<XLenVT> {
+ let ParserMatchClass = BaseIdxAddSymbol;
+}
+
def CSRSystemRegister : AsmOperandClass {
let Name = "CSRSystemRegister";
let ParserMethod = "parseCSRSystemRegister";
@@ -1545,11 +1558,18 @@ def : PatGprShiftMaskXLen<sra, SRA>;
// fourth operand to emit a relocation on a symbol relating to this instruction.
// The relocation does not affect any bits of the instruction itself but is used
// as a hint to the linker.
-let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 0 in
+let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 0 in {
def PseudoAddTPRel : Pseudo<(outs GPR:$rd),
(ins GPR:$rs1, GPR:$rs2, tprel_add_symbol:$src), [],
"add", "$rd, $rs1, $rs2, $src">;
+// This is a special case of the ADD instruction used to facilitate the use of a
+// fourth operand to emit a relocation on a symbol relating to this instruction.
+// The relocation does not affect any bits of the instruction itself but is used
+// as a hint to the linker.
+def PseudoAddBaseIdx : PseudoBaseIdx<"add">;
+}
+
/// FrameIndex calculations
def : Pat<(frameindex:$fi), (ADDI (iPTR (to_tframeindex $fi)), 0)>;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td
index 418efefe58318..5491e0cbd193c 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td
@@ -258,6 +258,23 @@ class RVBShift_ri<bits<5> imm11_7, bits<3> funct3, RISCVOpcode opcode,
(ins GPR:$rs1, uimmlog2xlen:$shamt), opcodestr,
"$rd, $rs1, $shamt">;
+// This is a special case of the SH1ADD/SH2ADD/SH3ADD instruction used to
+// facilitate the use of a fourth operand to emit a relocation on a symbol
+// relating to this instruction. The relocation does not affect any bits of the
+// instruction itself but is used as a hint to the linker.
+let Predicates = [HasStdExtZba] in {
+ def PseudoSh1AddBaseIdx : PseudoBaseIdx<"sh1add">;
+ def PseudoSh2AddBaseIdx : PseudoBaseIdx<"sh2add">;
+ def PseudoSh3AddBaseIdx : PseudoBaseIdx<"sh3add">;
+}
+
+let Predicates = [HasStdExtZba, IsRV64] in {
+ def PseudoAddUWBaseIdx : PseudoBaseIdx<"add.uw">;
+ def PseudoSh1AddUWBaseIdx : PseudoBaseIdx<"sh1add.uw">;
+ def PseudoSh2AddUWBaseIdx : PseudoBaseIdx<"sh2add.uw">;
+ def PseudoSh3AddUWBaseIdx : PseudoBaseIdx<"sh3add.uw">;
+}
+
//===----------------------------------------------------------------------===//
// Instructions
//===----------------------------------------------------------------------===//
diff --git a/llvm/test/MC/RISCV/Relocations/mc-dump.s b/llvm/test/MC/RISCV/Relocations/mc-dump.s
index 82b30aabdb781..c6f7a4a231084 100644
--- a/llvm/test/MC/RISCV/Relocations/mc-dump.s
+++ b/llvm/test/MC/RISCV/Relocations/mc-dump.s
@@ -7,7 +7,7 @@
# CHECK-NEXT: Align:4 Fill:0 FillLen:1 MaxBytesToEmit:4 Nops
# CHECK-NEXT: Symbol @0 .text
# CHECK-NEXT:0 Data LinkerRelaxable Size:8 [97,00,00,00,e7,80,00,00]
-# CHECK-NEXT: Fixup @0 Value:specifier(4014,ext) Kind:4023 LinkerRelaxable
+# CHECK-NEXT: Fixup @0 Value:specifier(4015,ext) Kind:4023 LinkerRelaxable
# CHECK-NEXT: Symbol @0 $x
# CHECK-NEXT:8 Align LinkerRelaxable Size:0+6 []
# CHECK-NEXT: Align:8 Fill:0 FillLen:1 MaxBytesToEmit:8 Nops
diff --git a/llvm/test/MC/RISCV/Relocations/relocations.s b/llvm/test/MC/RISCV/Relocations/relocations.s
index 42cdfe338fe54..caf722202d022 100644
--- a/llvm/test/MC/RISCV/Relocations/relocations.s
+++ b/llvm/test/MC/RISCV/Relocations/relocations.s
@@ -1,8 +1,8 @@
-# RUN: llvm-mc -triple riscv32 -M no-aliases %s -show-encoding \
+# RUN: llvm-mc -triple riscv64 -mattr=+zba -M no-aliases %s -show-encoding \
# RUN: | FileCheck -check-prefix=INSTR %s
-# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+c %s \
+# RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+c,+zba %s \
# RUN: | llvm-readobj -r - | FileCheck -check-prefix=RELOC %s
-# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+c,+relax %s \
+# RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+c,+zba,+relax %s \
# RUN: | llvm-readobj -r - | FileCheck -check-prefix=RELOC-RELAX %s
# Check prefixes:
@@ -51,6 +51,14 @@ addi t1, t1, %tprel_lo(foo+4)
# RELOC: R_RISCV_TPREL_LO12_I foo 0x4
# INSTR: addi t1, t1, %tprel_lo(foo+4)
+addi t1, t1, %base_idx_lo(foo)
+# RELOC: R_RISCV_BASE_IDX_LO12_I foo 0x0
+# INSTR: addi t1, t1, %base_idx_lo(foo)
+
+addi t1, t1, %base_idx_lo(foo+4)
+# RELOC: R_RISCV_BASE_IDX_LO12_I foo 0x4
+# INSTR: addi t1, t1, %base_idx_lo(foo+4)
+
sb t1, %lo(foo)(a2)
# RELOC: R_RISCV_LO12_S foo 0x0
# INSTR: sb t1, %lo(foo)(a2)
@@ -67,6 +75,14 @@ sb t1, %tprel_lo(foo+4)(a2)
# RELOC: R_RISCV_TPREL_LO12_S foo 0x4
# INSTR: sb t1, %tprel_lo(foo+4)(a2)
+sb t1, %base_idx_lo(foo)(a2)
+# RELOC: R_RISCV_BASE_IDX_LO12_S foo 0x0
+# INSTR: sb t1, %base_idx_lo(foo)(a2)
+
+sb t1, %base_idx_lo(foo+4)(a2)
+# RELOC: R_RISCV_BASE_IDX_LO12_S foo 0x4
+# INSTR: sb t1, %base_idx_lo(foo+4)(a2)
+
.L0:
auipc t1, %pcrel_hi(foo)
# RELOC: R_RISCV_PCREL_HI20 foo 0x0
@@ -142,6 +158,38 @@ add t1, t1, tp, %tprel_add(foo)
# RELOC: R_RISCV_TPREL_ADD foo 0x0
# INSTR: add t1, t1, tp, %tprel_add(foo)
+add t1, t1, t2, %base_idx_add(foo)
+# RELOC: R_RISCV_BASE_IDX_ADD foo 0x0
+# INSTR: add t1, t1, t2, %base_idx_add(foo)
+
+add.uw t1, t1, t2, %base_idx_add(foo)
+# RELOC: R_RISCV_BASE_IDX_ADD foo 0x0
+# INSTR: add.uw t1, t1, t2, %base_idx_add(foo)
+
+sh1add t1, t1, t2, %base_idx_add(foo)
+# RELOC: R_RISCV_BASE_IDX_ADD foo 0x0
+# INSTR: sh1add t1, t1, t2, %base_idx_add(foo)
+
+sh1add.uw t1, t1, t2, %base_idx_add(foo)
+# RELOC: R_RISCV_BASE_IDX_ADD foo 0x0
+# INSTR: sh1add.uw t1, t1, t2, %base_idx_add(foo)
+
+sh2add t1, t1, t2, %base_idx_add(foo)
+# RELOC: R_RISCV_BASE_IDX_ADD foo 0x0
+# INSTR: sh2add t1, t1, t2, %base_idx_add(foo)
+
+sh2add.uw t1, t1, t2, %base_idx_add(foo)
+# RELOC: R_RISCV_BASE_IDX_ADD foo 0x0
+# INSTR: sh2add.uw t1, t1, t2, %base_idx_add(foo)
+
+sh3add t1, t1, t2, %base_idx_add(foo)
+# RELOC: R_RISCV_BASE_IDX_ADD foo 0x0
+# INSTR: sh3add t1, t1, t2, %base_idx_add(foo)
+
+sh3add.uw t1, t1, t2, %base_idx_add(foo)
+# RELOC: R_RISCV_BASE_IDX_ADD foo 0x0
+# INSTR: sh3add.uw t1, t1, t2, %base_idx_add(foo)
+
jal zero, foo
# RELOC: R_RISCV_JAL
# INSTR: jal zero, foo
diff --git a/llvm/test/MC/RISCV/rv32zba-invalid.s b/llvm/test/MC/RISCV/rv32zba-invalid.s
index 41e8076f49572..a1f9d5cd20368 100644
--- a/llvm/test/MC/RISCV/rv32zba-invalid.s
+++ b/llvm/test/MC/RISCV/rv32zba-invalid.s
@@ -11,3 +11,19 @@ add.uw t0, t1, t2 # CHECK: :[[@LINE]]:1: error: instruction requires the followi
sh1add.uw t0, t1, t2 # CHECK: :[[@LINE]]:1: error: instruction requires the following: RV64I Base Instruction Set{{$}}
sh2add.uw t0, t1, t2 # CHECK: :[[@LINE]]:1: error: instruction requires the following: RV64I Base Instruction Set{{$}}
sh3add.uw t0, t1, t2 # CHECK: :[[@LINE]]:1: error: instruction requires the following: RV64I Base Instruction Set{{$}}
+
+# Base+index symbol names require a %base_idx_add modifier.
+sh1add a0, a0, a1, %hi(foo)
+# CHECK: :[[@LINE-1]]:1: error: invalid instruction, any one of the following would fix this:
+# CHECK: :[[@LINE-2]]:20: note: invalid operand for instruction
+# CHECK: :[[@LINE-3]]:20: note: operand must be a symbol with %base_idx_add specifier
+
+sh2add a0, a0, a1, %hi(foo)
+# CHECK: :[[@LINE-1]]:1: error: invalid instruction, any one of the following would fix this:
+# CHECK: :[[@LINE-2]]:20: note: invalid operand for instruction
+# CHECK: :[[@LINE-3]]:20: note: operand must be a symbol with %base_idx_add specifier
+
+sh3add a0, a0, a1, %hi(foo)
+# CHECK: :[[@LINE-1]]:1: error: invalid instruction, any one of the following would fix this:
+# CHECK: :[[@LINE-2]]:20: note: invalid operand for instruction
+# CHECK: :[[@LINE-3]]:20: note: operand must be a symbol with %base_idx_add specifier
diff --git a/llvm/test/MC/RISCV/rv64zba-invalid.s b/llvm/test/MC/RISCV/rv64zba-invalid.s
index 8dbea991950b4..bece86a76d9ef 100644
--- a/llvm/test/MC/RISCV/rv64zba-invalid.s
+++ b/llvm/test/MC/RISCV/rv64zba-invalid.s
@@ -13,3 +13,39 @@ sh1add.uw t0, t1 # CHECK: :[[@LINE]]:17: error: too few operands for instruction
sh2add.uw t0, t1 # CHECK: :[[@LINE]]:17: error: too few operands for instruction
# Too few operands
sh3add.uw t0, t1 # CHECK: :[[@LINE]]:17: error: too few operands for instruction
+
+# Base+index symbol names require a %base_idx_add modifier.
+sh1add a0, a0, a1, %hi(foo)
+# CHECK: :[[@LINE-1]]:1: error: invalid instruction, any one of the following would fix this:
+# CHECK: :[[@LINE-2]]:20: note: invalid operand for instruction
+# CHECK: :[[@LINE-3]]:20: note: operand must be a symbol with %base_idx_add specifier
+
+sh2add a0, a0, a1, %hi(foo)
+# CHECK: :[[@LINE-1]]:1: error: invalid instruction, any one of the following would fix this:
+# CHECK: :[[@LINE-2]]:20: note: invalid operand for instruction
+# CHECK: :[[@LINE-3]]:20: note: operand must be a symbol with %base_idx_add specifier
+
+sh3add a0, a0, a1, %hi(foo)
+# CHECK: :[[@LINE-1]]:1: error: invalid instruction, any one of the following would fix this:
+# CHECK: :[[@LINE-2]]:20: note: invalid operand for instruction
+# CHECK: :[[@LINE-3]]:20: note: operand must be a symbol with %base_idx_add specifier
+
+add.uw a0, a0, a1, %hi(foo)
+# CHECK: :[[@LINE-1]]:1: error: invalid instruction, any one of the following would fix this:
+# CHECK: :[[@LINE-2]]:20: note: invalid operand for instruction
+# CHECK: :[[@LINE-3]]:20: note: operand must be a symbol with %base_idx_add specifier
+
+sh1add.uw a0, a0, a1, %hi(foo)
+# CHECK: :[[@LINE-1]]:1: error: invalid instruction, any one of the following would fix this:
+# CHECK: :[[@LINE-2]]:23: note: invalid operand for instruction
+# CHECK: :[[@LINE-3]]:23: note: operand must be a symbol with %base_idx_add specifier
+
+sh2add.uw a0, a0, a1, %hi(foo)
+# CHECK: :[[@LINE-1]]:1: error: invalid instruction, any one of the following would fix this:
+# CHECK: :[[@LINE-2]]:23: note: invalid operand for instruction
+# CHECK: :[[@LINE-3]]:23: note: operand must be a symbol with %base_idx_add specifier
+
+sh3add.uw a0, a0, a1, %hi(foo)
+# CHECK: :[[@LINE-1]]:1: error: invalid instruction, any one of the following would fix this:
+# CHECK: :[[@LINE-2]]:23: note: invalid operand for instruction
+# CHECK: :[[@LINE-3]]:23: note: operand must be a symbol with %base_idx_add specifier
\ No newline at end of file
>From ea2d0c067b68f970cae2fafd484b8883ee0dd9fd Mon Sep 17 00:00:00 2001
From: wengliqin <liqin.weng at spacemit.com>
Date: Wed, 8 Jul 2026 15:36:48 +0800
Subject: [PATCH 2/3] fix the comments
---
.../RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp | 18 +++++++++---------
llvm/lib/Target/RISCV/RISCVInstrFormats.td | 2 +-
llvm/lib/Target/RISCV/RISCVInstrInfo.td | 3 +--
3 files changed, 11 insertions(+), 12 deletions(-)
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
index d53fcd9c3d6fc..4ac9cf9dd5006 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
@@ -328,7 +328,7 @@ void RISCVMCCodeEmitter::expandAddTPRel(const MCInst &MI,
static unsigned getAddOpAndFixups(unsigned AddOp) {
switch (AddOp) {
default:
- llvm_unreachable("Unexpected ADD or SHXADD Opcode on GP-relative!");
+ llvm_unreachable("Unexpected ADD or SHXADD Opcode on base+idx!");
case RISCV::PseudoAddBaseIdx:
return RISCV::ADD;
case RISCV::PseudoAddUWBaseIdx:
@@ -348,21 +348,21 @@ static unsigned getAddOpAndFixups(unsigned AddOp) {
}
}
-// Pseudo ADD/SHXADD (base-index variant) to a simple ADD or SHXADD with the
-// correct relocation.
+// Expand pseudo ADD/SHXADD (base-index variant) to a simple ADD or SHXADD with
+// the correct relocation.
void RISCVMCCodeEmitter::expandAddBaseIdx(const MCInst &MI,
SmallVectorImpl<char> &CB,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
- MCOperand DestReg = MI.getOperand(0);
+ const MCOperand &Dest = MI.getOperand(0);
// At link time rs2 of the add/shXadd may be rewritten to gp (or zero for
// abs-near) when the symbol can be reached via gp-relative addressing.
- MCOperand Src1 = MI.getOperand(1);
- MCOperand Src2 = MI.getOperand(2);
+ const MCOperand &Src1 = MI.getOperand(1);
+ const MCOperand &Src2 = MI.getOperand(2);
- MCOperand SrcSymbol = MI.getOperand(3);
+ const MCOperand &SrcSymbol = MI.getOperand(3);
assert(SrcSymbol.isExpr() &&
- "Expected expression as third input to GP-relative add");
+ "Expected expression as third input to base+idx add");
const auto *Expr = dyn_cast<MCSpecifierExpr>(SrcSymbol.getExpr());
assert(Expr && (Expr->getSpecifier() == ELF::R_RISCV_BASE_IDX_ADD) &&
@@ -380,7 +380,7 @@ void RISCVMCCodeEmitter::expandAddBaseIdx(const MCInst &MI,
// Emit a normal ADD or SHXADD instruction with the given operands.
MCInst TmpInst = MCInstBuilder(BuildOpcode)
- .addOperand(DestReg)
+ .addOperand(Dest)
.addOperand(Src1)
.addOperand(Src2);
uint32_t Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI);
diff --git a/llvm/lib/Target/RISCV/RISCVInstrFormats.td b/llvm/lib/Target/RISCV/RISCVInstrFormats.td
index 2a6080721f92f..e2b3ccc94253c 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrFormats.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrFormats.td
@@ -371,7 +371,7 @@ class PseudoBaseIdx<string opcodestr>
(ins GPR:$rs1, GPR:$rs2, base_idx_add_symbol:$src), [], opcodestr,
"$rd, $rs1, $rs2, $src"> {
let hasSideEffects = 0;
- let mayLoad = 1;
+ let mayLoad = 0;
let mayStore = 0;
let isCodeGenOnly = 0;
}
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index 317caf688e00a..0456b7e3cf5d3 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -1558,7 +1558,7 @@ def : PatGprShiftMaskXLen<sra, SRA>;
// fourth operand to emit a relocation on a symbol relating to this instruction.
// The relocation does not affect any bits of the instruction itself but is used
// as a hint to the linker.
-let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 0 in {
+let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 0 in
def PseudoAddTPRel : Pseudo<(outs GPR:$rd),
(ins GPR:$rs1, GPR:$rs2, tprel_add_symbol:$src), [],
"add", "$rd, $rs1, $rs2, $src">;
@@ -1568,7 +1568,6 @@ def PseudoAddTPRel : Pseudo<(outs GPR:$rd),
// The relocation does not affect any bits of the instruction itself but is used
// as a hint to the linker.
def PseudoAddBaseIdx : PseudoBaseIdx<"add">;
-}
/// FrameIndex calculations
>From 3f2d76887a4f500dbb0c0f3c3e1dee42d3893aee Mon Sep 17 00:00:00 2001
From: wengliqin <liqin.weng at spacemit.com>
Date: Tue, 28 Jul 2026 17:43:51 +0800
Subject: [PATCH 3/3] 1. Add relaxation for absolute int12 for
R_RISCV_BASE_IDX* 2. change INTERNAL_R_RISCV_VASE_IDX_* to
INTERNAL_R_RISCV_BASE_IDX_GPREL*
---
lld/ELF/Arch/RISCV.cpp | 67 ++++++++++++++++++++++------
lld/test/ELF/riscv-base-idx-add.s | 25 ++++++++++-
lld/test/ELF/riscv-base-idx-shxadd.s | 25 ++++++++++-
llvm/test/MC/RISCV/rv32zba-invalid.s | 6 +--
llvm/test/MC/RISCV/rv64zba-invalid.s | 14 +++---
5 files changed, 110 insertions(+), 27 deletions(-)
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index cc233f357e2dc..c85d4d086fa00 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -74,9 +74,12 @@ class RISCV final : public TargetInfo {
#define INTERNAL_R_RISCV_GPREL_S 257
#define INTERNAL_R_RISCV_X0REL_I 258
#define INTERNAL_R_RISCV_X0REL_S 259
-#define INTERNAL_R_RISCV_BASE_IDX_ADD 260
-#define INTERNAL_R_RISCV_BASE_IDX_LO12_I 261
-#define INTERNAL_R_RISCV_BASE_IDX_LO12_S 262
+#define INTERNAL_R_RISCV_BASE_IDX_X0REL_I 260
+#define INTERNAL_R_RISCV_BASE_IDX_X0REL_S 261
+#define INTERNAL_R_RISCV_BASE_IDX_X0REL_ADD 262
+#define INTERNAL_R_RISCV_BASE_IDX_GPREL_I 263
+#define INTERNAL_R_RISCV_BASE_IDX_GPREL_S 264
+#define INTERNAL_R_RISCV_BASE_IDX_GPREL_ADD 265
const uint64_t dtpOffset = 0x800;
@@ -652,19 +655,37 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
return;
}
- case INTERNAL_R_RISCV_BASE_IDX_ADD: {
+ case INTERNAL_R_RISCV_BASE_IDX_X0REL_ADD: {
+ uint32_t insn = (read32le(loc) & ~(31 << 20)) | (X_X0 << 20);
+ write32le(loc, insn);
+ return;
+ }
+
+ case INTERNAL_R_RISCV_BASE_IDX_X0REL_I:
+ case INTERNAL_R_RISCV_BASE_IDX_X0REL_S: {
+ checkInt(ctx, loc, val, 12, rel);
+ uint32_t insn = read32le(loc);
+ if (rel.type == INTERNAL_R_RISCV_BASE_IDX_X0REL_I)
+ insn = setLO12_I(insn, val);
+ else
+ insn = setLO12_S(insn, val);
+ write32le(loc, insn);
+ return;
+ }
+
+ case INTERNAL_R_RISCV_BASE_IDX_GPREL_ADD: {
uint32_t insn = (read32le(loc) & ~(31 << 20)) | (X_GP << 20);
write32le(loc, insn);
return;
}
- case INTERNAL_R_RISCV_BASE_IDX_LO12_I:
- case INTERNAL_R_RISCV_BASE_IDX_LO12_S: {
+ case INTERNAL_R_RISCV_BASE_IDX_GPREL_I:
+ case INTERNAL_R_RISCV_BASE_IDX_GPREL_S: {
Defined *gp = ctx.sym.riscvGlobalPointer;
int64_t displace = SignExtend64(val - gp->getVA(ctx), bits);
checkInt(ctx, loc, displace, 12, rel);
uint32_t insn = read32le(loc);
- if (rel.type == INTERNAL_R_RISCV_BASE_IDX_LO12_I)
+ if (rel.type == INTERNAL_R_RISCV_BASE_IDX_GPREL_I)
insn = setLO12_I(insn, displace);
else
insn = setLO12_S(insn, displace);
@@ -1038,6 +1059,23 @@ static void relaxHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
case R_RISCV_LO12_S:
sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_X0REL_S;
break;
+ case R_RISCV_BASE_IDX_ADD: {
+ uint32_t insn = read32le(sec.content().data() + r.offset) & 0xFE000000;
+ if (insn == 0) {
+ // remove add a0, a0, zero
+ sec.relaxAux->relocTypes[i] = R_RISCV_RELAX;
+ remove = 4;
+ } else {
+ sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_BASE_IDX_X0REL_ADD;
+ }
+ break;
+ }
+ case R_RISCV_BASE_IDX_LO12_I:
+ sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_BASE_IDX_X0REL_I;
+ break;
+ case R_RISCV_BASE_IDX_LO12_S:
+ sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_BASE_IDX_X0REL_S;
+ break;
}
return;
}
@@ -1062,13 +1100,13 @@ static void relaxHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_S;
break;
case R_RISCV_BASE_IDX_ADD:
- sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_BASE_IDX_ADD;
+ sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_BASE_IDX_GPREL_ADD;
break;
case R_RISCV_BASE_IDX_LO12_I:
- sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_BASE_IDX_LO12_I;
+ sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_BASE_IDX_GPREL_I;
break;
case R_RISCV_BASE_IDX_LO12_S:
- sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_BASE_IDX_LO12_S;
+ sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_BASE_IDX_GPREL_S;
break;
}
}
@@ -1381,9 +1419,12 @@ void RISCV::finalizeRelax(int passes) const {
case INTERNAL_R_RISCV_GPREL_S:
case INTERNAL_R_RISCV_X0REL_I:
case INTERNAL_R_RISCV_X0REL_S:
- case INTERNAL_R_RISCV_BASE_IDX_ADD:
- case INTERNAL_R_RISCV_BASE_IDX_LO12_I:
- case INTERNAL_R_RISCV_BASE_IDX_LO12_S:
+ case INTERNAL_R_RISCV_BASE_IDX_X0REL_I:
+ case INTERNAL_R_RISCV_BASE_IDX_X0REL_S:
+ case INTERNAL_R_RISCV_BASE_IDX_X0REL_ADD:
+ case INTERNAL_R_RISCV_BASE_IDX_GPREL_I:
+ case INTERNAL_R_RISCV_BASE_IDX_GPREL_S:
+ case INTERNAL_R_RISCV_BASE_IDX_GPREL_ADD:
break;
case R_RISCV_RELAX:
// Used by relaxTlsLe to indicate the relocation is ignored.
diff --git a/lld/test/ELF/riscv-base-idx-add.s b/lld/test/ELF/riscv-base-idx-add.s
index 17db2ce3e0a3a..04ede4a4d9197 100644
--- a/lld/test/ELF/riscv-base-idx-add.s
+++ b/lld/test/ELF/riscv-base-idx-add.s
@@ -4,8 +4,8 @@
# RUN: llvm-mc -filetype=obj -triple=riscv32-unknown-elf -mattr=+relax a.s -o rv32.o
# RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf -mattr=+relax a.s -o rv64.o
-# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv32.o lds -o rv32
-# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv64.o lds -o rv64
+# RUN: ld.lld --relax-gp --undefined=__global_pointer$ --defsym baz=420 rv32.o lds -o rv32
+# RUN: ld.lld --relax-gp --undefined=__global_pointer$ --defsym baz=420 rv64.o lds -o rv64
# RUN: llvm-objdump -td -M no-aliases --no-show-raw-insn rv32 | FileCheck %s
# RUN: llvm-objdump -td -M no-aliases --no-show-raw-insn rv64 | FileCheck %s
@@ -26,6 +26,16 @@
# CHECK-NEXT: add a0, a0, a1
# CHECK-NEXT: lw a0, 0xe(a0)
# CHECK-NEXT: sw a0, 0xe(a0)
+# CHECK-NOT: lui
+# CHECK-NEXT: addi a1, a1, 0x0
+# CHECK-NOT: add a0, a0, zero
+# CHECK-NEXT: lw a0, 0x0(a0)
+# CHECK-NEXT: sw a0, 0x0(a0)
+# CHECK-NOT: lui
+# CHECK-NEXT: addi a1, a1, 0x1a4
+# CHECK-NOT: add a0, a0, zero
+# CHECK-NEXT: lw a0, 0x1a4(a0)
+# CHECK-NEXT: sw a0, 0x1a4(a0)
# CHECK-EMPTY:
# CHECK-NEXT: <a>:
# CHECK-NEXT: addi a0, a0, 0x1
@@ -49,6 +59,16 @@ _start:
add a0, a0, a1, %base_idx_add(norelax+10)
lw a0, %base_idx_lo(norelax+10)(a0)
sw a0, %base_idx_lo(norelax+10)(a0)
+ lui a1, %hi(undefined_weak)
+ addi a1, a1, %base_idx_lo(undefined_weak)
+ add a0, a0, a1, %base_idx_add(undefined_weak)
+ lw a0, %base_idx_lo(undefined_weak)(a0)
+ sw a0, %base_idx_lo(undefined_weak)(a0)
+ lui a1, %hi(baz)
+ addi a1, a1, %base_idx_lo(baz)
+ add a0, a0, a1, %base_idx_add(baz)
+ lw a0, %base_idx_lo(baz)(a0)
+ sw a0, %base_idx_lo(baz)(a0)
a:
addi a0, a0, 1
@@ -62,6 +82,7 @@ array1:
norelax:
.zero 6
.size array, 6
+.weak undefined_weak
#--- lds
SECTIONS {
diff --git a/lld/test/ELF/riscv-base-idx-shxadd.s b/lld/test/ELF/riscv-base-idx-shxadd.s
index 32f2d97e668df..e9e71871ece3e 100644
--- a/lld/test/ELF/riscv-base-idx-shxadd.s
+++ b/lld/test/ELF/riscv-base-idx-shxadd.s
@@ -4,8 +4,8 @@
# RUN: llvm-mc -filetype=obj -triple=riscv32-unknown-elf -mattr=+relax,+zba a.s -o rv32.o
# RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf -mattr=+relax,+zba a.s -o rv64.o
-# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv32.o lds -o rv32
-# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv64.o lds -o rv64
+# RUN: ld.lld --relax-gp --undefined=__global_pointer$ --defsym baz=420 rv32.o lds -o rv32
+# RUN: ld.lld --relax-gp --undefined=__global_pointer$ --defsym baz=420 rv64.o lds -o rv64
# RUN: llvm-objdump --mattr=+zba -td -M no-aliases --no-show-raw-insn rv32 | FileCheck %s
# RUN: llvm-objdump --mattr=+zba -td -M no-aliases --no-show-raw-insn rv64 | FileCheck %s
@@ -26,6 +26,16 @@
# CHECK-NEXT: sh1add a0, a0, a1
# CHECK-NEXT: lw a0, 0xe(a0)
# CHECK-NEXT: sw a0, 0xe(a0)
+# CHECK-NOT: lui
+# CHECK-NEXT: addi a1, a1, 0x0
+# CHECK-NEXT: sh2add a0, a0, zero
+# CHECK-NEXT: lw a0, 0x0(a0)
+# CHECK-NEXT: sw a0, 0x0(a0)
+# CHECK-NOT: lui
+# CHECK-NEXT: addi a1, a1, 0x1a4
+# CHECK-NEXT: sh3add a0, a0, zero
+# CHECK-NEXT: lw a0, 0x1a4(a0)
+# CHECK-NEXT: sw a0, 0x1a4(a0)
# CHECK-EMPTY:
# CHECK-NEXT: <a>:
# CHECK-NEXT: addi a0, a0, 0x1
@@ -48,6 +58,16 @@ _start:
sh1add a0, a0, a1, %base_idx_add(norelax+10)
lw a0, %base_idx_lo(norelax+10)(a0)
sw a0, %base_idx_lo(norelax+10)(a0)
+ lui a1, %hi(undefined_weak)
+ addi a1, a1, %base_idx_lo(undefined_weak)
+ sh2add a0, a0, a1, %base_idx_add(undefined_weak)
+ lw a0, %base_idx_lo(undefined_weak)(a0)
+ sw a0, %base_idx_lo(undefined_weak)(a0)
+ lui a1, %hi(baz)
+ addi a1, a1, %base_idx_lo(baz)
+ sh3add a0, a0, a1, %base_idx_add(baz)
+ lw a0, %base_idx_lo(baz)(a0)
+ sw a0, %base_idx_lo(baz)(a0)
a:
addi a0, a0, 1
@@ -61,6 +81,7 @@ array1:
norelax:
.zero 6
.size array, 6
+.weak undefined_weak
#--- lds
SECTIONS {
diff --git a/llvm/test/MC/RISCV/rv32zba-invalid.s b/llvm/test/MC/RISCV/rv32zba-invalid.s
index a1f9d5cd20368..bac22926f233d 100644
--- a/llvm/test/MC/RISCV/rv32zba-invalid.s
+++ b/llvm/test/MC/RISCV/rv32zba-invalid.s
@@ -15,15 +15,15 @@ sh3add.uw t0, t1, t2 # CHECK: :[[@LINE]]:1: error: instruction requires the foll
# Base+index symbol names require a %base_idx_add modifier.
sh1add a0, a0, a1, %hi(foo)
# CHECK: :[[@LINE-1]]:1: error: invalid instruction, any one of the following would fix this:
-# CHECK: :[[@LINE-2]]:20: note: invalid operand for instruction
+# CHECK: :[[@LINE-2]]:20: note: unexpected extra operand for instruction
# CHECK: :[[@LINE-3]]:20: note: operand must be a symbol with %base_idx_add specifier
sh2add a0, a0, a1, %hi(foo)
# CHECK: :[[@LINE-1]]:1: error: invalid instruction, any one of the following would fix this:
-# CHECK: :[[@LINE-2]]:20: note: invalid operand for instruction
+# CHECK: :[[@LINE-2]]:20: note: unexpected extra operand for instruction
# CHECK: :[[@LINE-3]]:20: note: operand must be a symbol with %base_idx_add specifier
sh3add a0, a0, a1, %hi(foo)
# CHECK: :[[@LINE-1]]:1: error: invalid instruction, any one of the following would fix this:
-# CHECK: :[[@LINE-2]]:20: note: invalid operand for instruction
+# CHECK: :[[@LINE-2]]:20: note: unexpected extra operand for instruction
# CHECK: :[[@LINE-3]]:20: note: operand must be a symbol with %base_idx_add specifier
diff --git a/llvm/test/MC/RISCV/rv64zba-invalid.s b/llvm/test/MC/RISCV/rv64zba-invalid.s
index bece86a76d9ef..a5bc9863cc1c6 100644
--- a/llvm/test/MC/RISCV/rv64zba-invalid.s
+++ b/llvm/test/MC/RISCV/rv64zba-invalid.s
@@ -17,35 +17,35 @@ sh3add.uw t0, t1 # CHECK: :[[@LINE]]:17: error: too few operands for instruction
# Base+index symbol names require a %base_idx_add modifier.
sh1add a0, a0, a1, %hi(foo)
# CHECK: :[[@LINE-1]]:1: error: invalid instruction, any one of the following would fix this:
-# CHECK: :[[@LINE-2]]:20: note: invalid operand for instruction
+# CHECK: :[[@LINE-2]]:20: note: unexpected extra operand for instruction
# CHECK: :[[@LINE-3]]:20: note: operand must be a symbol with %base_idx_add specifier
sh2add a0, a0, a1, %hi(foo)
# CHECK: :[[@LINE-1]]:1: error: invalid instruction, any one of the following would fix this:
-# CHECK: :[[@LINE-2]]:20: note: invalid operand for instruction
+# CHECK: :[[@LINE-2]]:20: note: unexpected extra operand for instruction
# CHECK: :[[@LINE-3]]:20: note: operand must be a symbol with %base_idx_add specifier
sh3add a0, a0, a1, %hi(foo)
# CHECK: :[[@LINE-1]]:1: error: invalid instruction, any one of the following would fix this:
-# CHECK: :[[@LINE-2]]:20: note: invalid operand for instruction
+# CHECK: :[[@LINE-2]]:20: note: unexpected extra operand for instruction
# CHECK: :[[@LINE-3]]:20: note: operand must be a symbol with %base_idx_add specifier
add.uw a0, a0, a1, %hi(foo)
# CHECK: :[[@LINE-1]]:1: error: invalid instruction, any one of the following would fix this:
-# CHECK: :[[@LINE-2]]:20: note: invalid operand for instruction
+# CHECK: :[[@LINE-2]]:20: note: unexpected extra operand for instruction
# CHECK: :[[@LINE-3]]:20: note: operand must be a symbol with %base_idx_add specifier
sh1add.uw a0, a0, a1, %hi(foo)
# CHECK: :[[@LINE-1]]:1: error: invalid instruction, any one of the following would fix this:
-# CHECK: :[[@LINE-2]]:23: note: invalid operand for instruction
+# CHECK: :[[@LINE-2]]:23: note: unexpected extra operand for instruction
# CHECK: :[[@LINE-3]]:23: note: operand must be a symbol with %base_idx_add specifier
sh2add.uw a0, a0, a1, %hi(foo)
# CHECK: :[[@LINE-1]]:1: error: invalid instruction, any one of the following would fix this:
-# CHECK: :[[@LINE-2]]:23: note: invalid operand for instruction
+# CHECK: :[[@LINE-2]]:23: note: unexpected extra operand for instruction
# CHECK: :[[@LINE-3]]:23: note: operand must be a symbol with %base_idx_add specifier
sh3add.uw a0, a0, a1, %hi(foo)
# CHECK: :[[@LINE-1]]:1: error: invalid instruction, any one of the following would fix this:
-# CHECK: :[[@LINE-2]]:23: note: invalid operand for instruction
+# CHECK: :[[@LINE-2]]:23: note: unexpected extra operand for instruction
# CHECK: :[[@LINE-3]]:23: note: operand must be a symbol with %base_idx_add specifier
\ No newline at end of file
More information about the llvm-commits
mailing list