[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 22:57:20 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-risc-v

Author: LiqinWeng (LiqinWeng)

<details>
<summary>Changes</summary>

psABI: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/489

This MR is split from: https://github.com/llvm/llvm-project/pull/185353

---

Patch is 23.24 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/207901.diff


14 Files Affected:

- (modified) lld/ELF/Arch/RISCV.cpp (+47) 
- (added) lld/test/ELF/riscv-base-idx-add.s (+71) 
- (added) lld/test/ELF/riscv-base-idx-shxadd.s (+69) 
- (modified) llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def (+3) 
- (modified) llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp (+13-1) 
- (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h (+2) 
- (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h (+1) 
- (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp (+94-5) 
- (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp (+6) 
- (modified) llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp (+6) 
- (modified) llvm/lib/Target/RISCV/RISCVInstrFormats.td (+11) 
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfo.cpp (+2) 
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfo.td (+21-1) 
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfoZb.td (+17) 


``````````diff
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 576e7a4614572..a91c7bcb99224 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,31 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
     return;
   }
 
+  case R_RISCV_BASE_IDX_ADD: {
+    write32le(loc, read32le(loc));
+  }
+
+  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);
@@ -989,6 +1022,14 @@ static void relaxHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
     break;
   case R_RISCV_LO12_S:
     sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_S;
+  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 +1086,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 +1342,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..21c431030a6d9 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,14 @@ 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");
     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, ...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/207901


More information about the llvm-commits mailing list