[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
Mon Jul 6 23:07:58 PDT 2026
https://github.com/LiqinWeng updated https://github.com/llvm/llvm-project/pull/207901
>From 92c333530b7684589ba5ade8d98fc7073c39e0f6 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] [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 +++
14 files changed, 367 insertions(+), 7 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 576e7a4614572..0f540845932f3 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;
@@ -344,6 +347,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;
@@ -586,6 +592,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);
@@ -595,6 +602,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);
@@ -602,6 +610,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);
@@ -990,6 +1024,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;
}
}
@@ -1045,6 +1088,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;
@@ -1298,6 +1344,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 605a155f20e71..af71d95ff1689 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -629,6 +629,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.
@@ -930,7 +941,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 adf5d5d8b3759..d0f3d248bcdfa 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
@@ -478,6 +478,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 ee1fffc4886c8..834ea4cb248c7 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h
@@ -43,6 +43,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 e3c93dc93a686..5bc8890777177 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrFormats.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrFormats.td
@@ -353,6 +353,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 4de0a27790eca..84232d0459853 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -3598,6 +3598,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 e10ee7389db0e..9154fa92d155e 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
// Transforms frameindex -> tframeindex.
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
//===----------------------------------------------------------------------===//
More information about the llvm-commits
mailing list