[lld] [llvm] [RISCV] Teach RISCVMergeBaseOffset to merge %lo into load/store folding arithmetic (PR #185353)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Mar 8 23:22:47 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lld-elf
Author: LiqinWeng (LiqinWeng)
<details>
<summary>Changes</summary>
It's possible we have:
1. first scenarios, the add opcode can be add or add.uw
```
lui vr1, %hi(sym)
addi vr1, vr1, %lo(sym)
add vr2, vrx, vr1
lbu vr3, off(vr2)
-----Transform-----
lui vr1, %hi(sym+off)
add vr2, vrx, vr1, %gprel_add(sym+off)
lbu vr3, %gprel_lo(sym+off)(vr2)
```
2. second scenarios, the add opcode can be sh1add/sh2add/sh3add/sh1add.uw/sh2add.uw/sh3add.uw
```
lui vr1, %hi(sym)
addi vr1, vr1, %lo(sym)
sh1add vr2, vrx, vr1
lbu vr3, off(vr2)
-----Transform-----
lui vr1, %hi(sym+off)
sh1add vr2, vrx, vr1, %gprel_shxadd(sym+off)
lbu vr3, %gprel_lo(sym+off)(vr2)
```
3. third scenarios, same as shxadd
```
addi vrx, vr0, offAddi
lui vr1, %hi(sym)
addi vr1, vr1, %lo(sym)
add vr2, vrx, vr1
lbu vr3, off(vr2)
-----Transform-----
lui vr1, %hi(sym+off+offAddi)
add vr2, vr0, vr1, %gprel_add(sym+off+offAddi)
lbu vr3, %gprel_lo(sym+off+offAddi)(vr2)
```
---
Patch is 87.80 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/185353.diff
25 Files Affected:
- (modified) lld/ELF/Arch/RISCV.cpp (+60-2)
- (added) lld/test/ELF/riscv-relax-gprel-add.s (+71)
- (added) lld/test/ELF/riscv-relax-gprel-shxadd.s (+70)
- (modified) llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def (+4)
- (modified) llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp (+12-1)
- (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp (+6)
- (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h (+4)
- (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp (+8)
- (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h (+9)
- (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h (+1)
- (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp (+91-2)
- (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp (+9)
- (modified) llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp (+9)
- (modified) llvm/lib/Target/RISCV/RISCVInstrFormats.td (+11)
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfo.cpp (+3)
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfo.td (+19)
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfoZb.td (+17)
- (modified) llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp (+260-1)
- (added) llvm/test/CodeGen/RISCV/fold-addi-with-add-into-memops.ll (+1232)
- (modified) llvm/test/CodeGen/RISCV/loop-strength-reduce-add-cheaper-than-mul.ll (+4-6)
- (modified) llvm/test/CodeGen/RISCV/lpad.ll (+8-12)
- (modified) llvm/test/MC/RISCV/Relocations/relocations.s (+48)
- (modified) llvm/test/MC/RISCV/rv32zba-invalid.s (+5)
- (modified) llvm/test/MC/RISCV/rv64zba-invalid.s (+9)
- (modified) llvm/test/MC/RISCV/rv64zbb-invalid.s (+1-1)
``````````diff
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 85f49c9260565..ccaed6b675d7b 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -74,6 +74,10 @@ 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_GPREL_ADD 260
+#define INTERNAL_R_RISCV_GPREL_SHXADD 261
+#define INTERNAL_R_RISCV_GPREL_ADD_I 262
+#define INTERNAL_R_RISCV_GPREL_ADD_S 263
const uint64_t dtpOffset = 0x800;
@@ -289,6 +293,10 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
case R_RISCV_HI20:
case R_RISCV_LO12_I:
case R_RISCV_LO12_S:
+ case R_RISCV_GPREL_ADD:
+ case R_RISCV_GPREL_SHXADD:
+ case R_RISCV_GPREL_LO12_I:
+ case R_RISCV_GPREL_LO12_S:
return R_ABS;
case R_RISCV_ADD8:
case R_RISCV_ADD16:
@@ -499,7 +507,8 @@ 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_LO12_I: {
+ case R_RISCV_LO12_I:
+ case R_RISCV_GPREL_LO12_I: {
uint64_t hi = (val + 0x800) >> 12;
uint64_t lo = val - (hi << 12);
write32le(loc, setLO12_I(read32le(loc), lo & 0xfff));
@@ -508,12 +517,40 @@ 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_LO12_S: {
+ case R_RISCV_LO12_S:
+ case R_RISCV_GPREL_LO12_S: {
uint64_t hi = (val + 0x800) >> 12;
uint64_t lo = val - (hi << 12);
write32le(loc, setLO12_S(read32le(loc), lo));
return;
}
+ case R_RISCV_GPREL_ADD:
+ case R_RISCV_GPREL_SHXADD: {
+ write32le(loc, read32le(loc));
+ return;
+ }
+
+ case INTERNAL_R_RISCV_GPREL_ADD:
+ case INTERNAL_R_RISCV_GPREL_SHXADD: {
+ uint32_t insn = (read32le(loc) & ~(31 << 20)) | (X_GP << 20);
+ write32le(loc, insn);
+ return;
+ }
+
+ case INTERNAL_R_RISCV_GPREL_ADD_I:
+ case INTERNAL_R_RISCV_GPREL_ADD_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_GPREL_ADD_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: {
@@ -895,6 +932,19 @@ 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_GPREL_ADD:
+ sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_ADD;
+ break;
+ case R_RISCV_GPREL_SHXADD:
+ sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_SHXADD;
+ break;
+ case R_RISCV_GPREL_LO12_I:
+ sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_ADD_I;
+ break;
+ case R_RISCV_GPREL_LO12_S:
+ sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_ADD_S;
+ break;
}
}
@@ -950,6 +1000,10 @@ 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_GPREL_ADD:
+ case R_RISCV_GPREL_SHXADD:
+ case R_RISCV_GPREL_LO12_I:
+ case R_RISCV_GPREL_LO12_S:
if (relaxable(relocs, i))
relaxHi20Lo12(ctx, sec, i, loc, r, remove);
break;
@@ -1193,6 +1247,10 @@ 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_GPREL_ADD:
+ case INTERNAL_R_RISCV_GPREL_SHXADD:
+ case INTERNAL_R_RISCV_GPREL_ADD_I:
+ case INTERNAL_R_RISCV_GPREL_ADD_S:
break;
case R_RISCV_RELAX:
// Used by relaxTlsLe to indicate the relocation is ignored.
diff --git a/lld/test/ELF/riscv-relax-gprel-add.s b/lld/test/ELF/riscv-relax-gprel-add.s
new file mode 100644
index 0000000000000..67c74db3c2f9d
--- /dev/null
+++ b/lld/test/ELF/riscv-relax-gprel-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, %gprel_lo(array)
+ add a0, a0, a1, %gprel_add(array)
+ lw a0, %gprel_lo(array)(a0)
+ sw a0, %gprel_lo(array)(a0)
+ lui a1, %hi(array1+10)
+ addi a1, a1, %gprel_lo(array1+10)
+ add a0, a0, a1, %gprel_add(array1+10)
+ lw a0, %gprel_lo(array1+10)(a0)
+ sw a0, %gprel_lo(array1+10)(a0)
+ lui a1, %hi(norelax+10)
+ addi a1, a1, %gprel_lo(norelax+10)
+ add a0, a0, a1, %gprel_add(norelax+10)
+ lw a0, %gprel_lo(norelax+10)(a0)
+ sw a0, %gprel_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-relax-gprel-shxadd.s b/lld/test/ELF/riscv-relax-gprel-shxadd.s
new file mode 100644
index 0000000000000..9dab44b6baa26
--- /dev/null
+++ b/lld/test/ELF/riscv-relax-gprel-shxadd.s
@@ -0,0 +1,70 @@
+# 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, %gprel_lo(array)
+ sh1add a0, a0, a1, %gprel_shxadd(array)
+ lw a0, %gprel_lo(array)(a0)
+ sw a0, %gprel_lo(array)(a0)
+ lui a1, %hi(array1+10)
+ addi a1, a1, %gprel_lo(array1+10)
+ sh1add a0, a0, a1, %gprel_shxadd(array1+10)
+ lw a0, %gprel_lo(array1+10)(a0)
+ sw a0, %gprel_lo(array1+10)(a0)
+ lui a1, %hi(norelax+10)
+ addi a1, a1, %gprel_lo(norelax+10)
+ sh1add a0, a0, a1, %gprel_shxadd(norelax+10)
+ lw a0, %gprel_lo(norelax+10)(a0)
+ sw a0, %gprel_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..a3d8743523ca9 100644
--- a/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def
+++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def
@@ -60,6 +60,10 @@ 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_GPREL_LO12_I, 66)
+ELF_RELOC(R_RISCV_GPREL_LO12_S, 67)
+ELF_RELOC(R_RISCV_GPREL_ADD, 68)
+ELF_RELOC(R_RISCV_GPREL_SHXADD, 69)
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 443b0b5f3c04b..1468ae35cb96e 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -608,6 +608,17 @@ struct RISCVOperand final : public MCParsedAsmOperand {
VK == ELF::R_RISCV_TPREL_ADD;
}
+ bool isGPRelAddSymbol() 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_GPREL_ADD || VK == ELF::R_RISCV_GPREL_SHXADD);
+ }
+
bool isTLSDESCCallSymbol() const {
int64_t Imm;
// Must be of 'immediate' type but not a constant.
@@ -869,7 +880,7 @@ 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_LO || VK == RISCV::S_PCREL_LO || VK == RISCV::S_GPREL_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/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
index 0f63b02b54c74..04852901d57b3 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
@@ -77,6 +77,10 @@ MCFixupKindInfo RISCVAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
{"fixup_riscv_lo12_i", 20, 12, 0},
{"fixup_riscv_12_i", 20, 12, 0},
{"fixup_riscv_lo12_s", 0, 32, 0},
+ {"fixup_riscv_gprel_lo12_i", 20, 12, 0},
+ {"fixup_riscv_gprel_lo12_s", 0, 32, 0},
+ {"fixup_riscv_gprel_add", 0, 0, 0},
+ {"fixup_riscv_gprel_shxadd", 0, 0, 0},
{"fixup_riscv_pcrel_hi20", 12, 20, 0},
{"fixup_riscv_pcrel_lo12_i", 20, 12, 0},
{"fixup_riscv_pcrel_lo12_s", 0, 32, 0},
@@ -506,6 +510,7 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
case FK_Data_leb128:
return Value;
case RISCV::fixup_riscv_lo12_i:
+ case RISCV::fixup_riscv_gprel_lo12_i:
case RISCV::fixup_riscv_pcrel_lo12_i:
return Value & 0xfff;
case RISCV::fixup_riscv_12_i:
@@ -515,6 +520,7 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
}
return Value & 0xfff;
case RISCV::fixup_riscv_lo12_s:
+ case RISCV::fixup_riscv_gprel_lo12_s:
case RISCV::fixup_riscv_pcrel_lo12_s:
return (((Value >> 5) & 0x7f) << 25) | ((Value & 0x1f) << 7);
case RISCV::fixup_riscv_hi20:
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
index c4d54bdd60737..01b16cee5c599 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
@@ -470,6 +470,10 @@ enum {
MO_TLSDESC_ADD_LO = 15,
MO_TLSDESC_CALL = 16,
+ MO_GPREL_LO = 17,
+ MO_GPREL_ADD = 18,
+ MO_GPREL_SHXADD = 19,
+
// Used to differentiate between target-specific "direct" flags and "bitmask"
// flags. A machine operand can only have one "direct" flag, but can have
// multiple "bitmask" flags.
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
index 2885e3cca8722..613c8b1c8ac3c 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
@@ -135,6 +135,14 @@ unsigned RISCVELFObjectWriter::getRelocType(const MCFixup &Fixup,
return ELF::R_RISCV_LO12_I;
case RISCV::fixup_riscv_lo12_s:
return ELF::R_RISCV_LO12_S;
+ case RISCV::fixup_riscv_gprel_lo12_i:
+ return ELF::R_RISCV_GPREL_LO12_I;
+ case RISCV::fixup_riscv_gprel_lo12_s:
+ return ELF::R_RISCV_GPREL_LO12_S;
+ case RISCV::fixup_riscv_gprel_add:
+ return ELF::R_RISCV_GPREL_ADD;
+ case RISCV::fixup_riscv_gprel_shxadd:
+ return ELF::R_RISCV_GPREL_SHXADD;
case RISCV::fixup_riscv_rvc_imm:
reportError(Fixup.getLoc(), "No relocation for CI-type instructions");
return ELF::R_RISCV_NONE;
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
index a2b75e4a42e76..f56d54d8fb3f4 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
@@ -24,6 +24,15 @@ enum Fixups {
fixup_riscv_12_i,
// 12-bit fixup corresponding to %lo(foo) for the S-type store instructions
fixup_riscv_lo12_s,
+ // 12-bit fixup corresponding to %gprel_lo(foo) for instructions like addi
+ fixup_riscv_gprel_lo12_i,
+ // 12-bit fixup corresponding to %gprel_lo(foo) for the S-type store
+ // instructions
+ fixup_riscv_gprel_lo12_s,
+ // Fixup corresponding to %gprel_add(foo) for PseudoAddGPRel/PseudoAddUWGPRel, used as a linker hint
+ fixup_riscv_gprel_add,
+ // Fixup corresponding to %gprel_shxadd(foo) for PseudoSh1AddGPRel/PseudoSh2AddGPRel/PseudoSh3AddGPRel/PseudoSh1AddUWGPRel/PseudoSh2AddUWGPRel/PseudoSh3AddUWGPRel, used as a linker hint
+ fixup_riscv_gprel_shxadd,
// 20-bit fixup corresponding to %pcrel_hi(foo) for instructions like auipc
fixup_riscv_pcrel_hi20,
// 12-bit fixup corresponding to %pcrel_lo(foo) for instructions like addi
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h
index d030c3b5cf867..69823c5adc1a2 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h
@@ -45,6 +45,7 @@ enum {
S_TPREL_LO,
S_CALL_PLT,
S_GOT_HI,
+ S_GPREL_LO,
// Vendor-specific relocation types might conflict across vendors.
// Refer to them using Specifier constants.
S_QC_ABS20,
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
index 4304a1e651ca5..4cead8bf751cf 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
@@ -64,6 +64,9 @@ class RISCVMCCodeEmitter : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+ void expandAddGPRel(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;
@@ -260,6 +263,68 @@ void RISCVMCCodeEmitter::expandAddTPRel(const MCInst &MI,
support::endian::write(CB, Binary, llvm::endianness::little);
}
+static std::pair<unsigned, uint16_t> getAddOpAndFixups(unsigned AddOp) {
+ switch (AddOp) {
+ default:
+ llvm_unreachable("Unexpected ADD or SHXADD Opcode on GP-relative!");
+ case RISCV::PseudoAddGPRel:
+ return std::make_pair(RISCV::ADD, ELF::R_RISCV_GPREL_ADD);
+ case RISCV::PseudoAddUWGPRel:
+ return std::make_pair(RISCV::ADD_UW, ELF::R_RISCV_GPREL_ADD);
+ case RISCV::PseudoSh1AddGPRel:
+ return std::make_pair(RISCV::SH1ADD, ELF::R_RISCV_GPREL_SHXADD);
+ case RISCV::PseudoSh2AddGPRel:
+ return std::make_pair(RISCV::SH2ADD, ELF::R_RISCV_GPREL_SHXADD);
+ case RISCV::PseudoSh3AddGPRel:
+ return std::make_pair(RISCV::SH3ADD, ELF::R_RISCV_GPREL_SHXADD);
+ case RISCV::PseudoSh1AddUWGPRel:
+ return std::make_pair(RISCV::SH1ADD_UW, ELF::R_RISCV_GPREL_SHXADD);
+ case RISCV::PseudoSh2AddUWGPRel:
+ return std::make_pair(RISCV::SH2ADD_UW, ELF::R_RISCV_GPREL_SHXADD);
+ case RISCV::PseudoSh3AddUWGPRel:
+ return std::make_pair(RISCV::SH3ADD_UW, ELF::R_RISCV_GPREL_SHXADD);
+ }
+}
+
+// PseudoAddGPRel/PseudoAddUWGPRel/PseudoSh1AddGPRel/PseudoSh2AddGPRel/PseudoSh3AddGPRel/PseudoSh1AddUWGPRel/PseudoSh2AddUWGPRel/PseudoSh3AddUWGPRel to a simple ADD or SHXADD with the correct relocation.
+void RISCVMCCodeEmitter::expandAddGPRel(const MCInst &MI,
+ SmallVectorImpl<char> &CB,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ MCOperand DestReg = MI.getOperand(0);
+ // If the global array can be accessed by GP, src1 or src2 needs to be
+ // replaced with X3 reg in link time.
+ 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_GPREL_ADD ||
+ Expr->getSpecifier() == ELF::R_RISCV_GPREL_SHXADD) &&
+ "Expected gprel_add or gprel_shxadd relocation on GP-relative symbol");
+
+ std::pair<unsigned, uint16_t> Res = getAddOpAndFixups(MI.getOpcode());
+
+ // Emit the correct gprel_add or gprel_shxadd relocation for the symbol.
+ addFixup(Fixups, 0, Expr, Res.second);
+
+ // Emit fixup_riscv_relax for gprel_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(Res.first).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:
@@ -440,6 +505,17 @@ void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI,
expandAddTPRel(MI, CB, Fixups, STI);
MCNumEmitted += 1;
return;
+ case RISCV::PseudoAddGPRel:
+ case RISCV::PseudoAddUWGPRel:
+ case RISCV::PseudoSh1AddGPRel:
+ case RISCV::PseudoSh2AddGPRel:
+ case RISCV::PseudoSh3AddGPRel:
+ case RISCV::PseudoSh1AddUWGPRel:
+ case RISCV::PseudoSh2AddUWGPRel:
+ case RISCV::PseudoSh3AddUWGPRel:
+ expandAddGPRel(MI, CB, Fixups, STI);
+ MCNumEmitted += 1;
+ return;
case RISCV::PseudoLongBEQ:
case RISCV::PseudoLongBNE:
case RISCV::PseudoLongBLT:
@@ -636,12 +712,16 @@ uint64_t RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo,
"invalid specifier");
break;
case ELF::R_RISCV_TPREL_ADD:
+ case ELF::R_RISCV_GPREL_ADD:
+ case ELF::R_RISCV_GPREL_SHXADD:
// 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 he...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/185353
More information about the llvm-commits
mailing list