[RISCV] Teach RISCVMergeBaseOffset to merge %lo into load/store folding arithmetic#185353
[RISCV] Teach RISCVMergeBaseOffset to merge %lo into load/store folding arithmetic#185353
Conversation
|
@llvm/pr-subscribers-llvm-binary-utilities @llvm/pr-subscribers-lld-elf Author: LiqinWeng (LiqinWeng) ChangesIt's possible we have:
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:
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]
|
… folding arithmetic
|
I don't really get the usage scenarios of these new relocations, I think we should discuss this in psabi first. |
spec 2006 gcc +4%, perlbench 3%, xalan + 3% in spacmiT X60. There are still issues with the current branch; more detailed information will be provided later. C code like as: |
|
Considering that some users will use clang + gnu ld, I have also implemented it in binutils, and I will upload a commit later. |
🐧 Linux x64 Test Results
Failed Tests(click on a test name to see its output) LLVMLLVM.CodeGen/RISCV/GlobalISel/add-imm.llLLVM.MC/RISCV/Relocations/mc-dump.sLLVM.MC/RISCV/Relocations/relocations.sIf these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the |
🪟 Windows x64 Test Results
Failed Tests(click on a test name to see its output) LLVMLLVM.CodeGen/RISCV/GlobalISel/add-imm.llLLVM.MC/RISCV/Relocations/mc-dump.sLLVM.MC/RISCV/Relocations/relocations.sIf these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the |
|
Can we split the llvm and lld parts into separate PRs? |
| MadeChange |= foldShxaddIntoScaledMemory(Hi, *Lo); | ||
| // Non-constant addressing of global array subscripts, which can be | ||
| // increase the optimization scenarios of gp-relax | ||
| if (Hi.getOpcode() != RISCV::AUIPC && Hi.getOperand(1).isGlobal() && Lo) |
There was a problem hiding this comment.
Move this check into foldGPIntoMemoryOps to keep this code clean?
| if (!isInt<32>(NewOffset)) | ||
| return false; | ||
|
|
||
| // Remove of the addi from add or shxadd, as: |
There was a problem hiding this comment.
"Remove of the addi" is not grammatically correct.
| MachineInstr &AddiOfAdd = *MRI->getVRegDef(Reg); | ||
| if (MRI->hasOneUse(Reg) && Reg.isVirtual() && | ||
| (AddiOfAdd.getOpcode() == RISCV::ADDI || | ||
| AddiOfAdd.getOpcode() == RISCV::ADDIW) && |
There was a problem hiding this comment.
How do we know it's safe to skip the sign extending behavior of ADDIW?
| case R_RISCV_LO12_S: | ||
| sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_S; | ||
| break; | ||
|
|
| 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) |
There was a problem hiding this comment.
Is there a PR to add these numbers to the psABI?
There was a problem hiding this comment.
|
Is there a patch for the binutils linker to add these new relocations? |
|
Broadly, before we can start to accept this, I'd prefer we had a psABI Pull Request with definitions of any new relocations, and examples of the specific relaxations. I think I did get confused when you started calling these "gprel", as we used to have some "gprel" relocations which were GP-relative. In this case, they're just relative to any other GPR, rather than Similarly, I think you're using
This is reasonably close to the I don't have a problem sticking a relocation on the What's the expectation for how the transformed sequence will be relaxed in the linker? Presumably we can delete the What's the intention behind supporting
This feels similar, I have lots of the same questions about:
Yes, it does seem reasonable to look at (and delete) the |
Pls see issue: #185586 |
| // 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, |
There was a problem hiding this comment.
If the relocation specifier always leads to relocations, we don't need these fixups. Just emit the ELF relocations in the first place.
only the first scenario is supported.Pls see: riscv-non-isa/riscv-elf-psabi-doc#489 want to wait until the standards are finalized before updating the current code. |
|
|
How do we prevent the compiler from generating these relocations if binutils (or a version of binutils without support) is being used as the linker. |



It's possible we have: