Skip to content

Commit ad4c708

Browse files
committed
[RISCV] Teach RISCVMergeBaseOffset to merge %lo into load/store after folding arithmetic
1 parent 04dbbd4 commit ad4c708

25 files changed

+1976
-24
lines changed

lld/ELF/Arch/RISCV.cpp

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ class RISCV final : public TargetInfo {
7474
#define INTERNAL_R_RISCV_GPREL_S 257
7575
#define INTERNAL_R_RISCV_X0REL_I 258
7676
#define INTERNAL_R_RISCV_X0REL_S 259
77+
#define INTERNAL_R_RISCV_GPREL_ADD 260
78+
#define INTERNAL_R_RISCV_GPREL_SHXADD 261
79+
#define INTERNAL_R_RISCV_GPREL_ADD_I 262
80+
#define INTERNAL_R_RISCV_GPREL_ADD_S 263
7781

7882
const uint64_t dtpOffset = 0x800;
7983

@@ -344,6 +348,10 @@ void RISCV::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
344348
case R_RISCV_HI20:
345349
case R_RISCV_LO12_I:
346350
case R_RISCV_LO12_S:
351+
case R_RISCV_GPREL_ADD:
352+
case R_RISCV_GPREL_SHXADD:
353+
case R_RISCV_GPREL_LO12_I:
354+
case R_RISCV_GPREL_LO12_S:
347355
expr = R_ABS;
348356
break;
349357

@@ -586,7 +594,8 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
586594
case R_RISCV_TLSDESC_LOAD_LO12:
587595
case R_RISCV_TLSDESC_ADD_LO12:
588596
case R_RISCV_TPREL_LO12_I:
589-
case R_RISCV_LO12_I: {
597+
case R_RISCV_LO12_I:
598+
case R_RISCV_GPREL_LO12_I: {
590599
uint64_t hi = (val + 0x800) >> 12;
591600
uint64_t lo = val - (hi << 12);
592601
write32le(loc, setLO12_I(read32le(loc), lo & 0xfff));
@@ -595,12 +604,40 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
595604

596605
case R_RISCV_PCREL_LO12_S:
597606
case R_RISCV_TPREL_LO12_S:
598-
case R_RISCV_LO12_S: {
607+
case R_RISCV_LO12_S:
608+
case R_RISCV_GPREL_LO12_S: {
599609
uint64_t hi = (val + 0x800) >> 12;
600610
uint64_t lo = val - (hi << 12);
601611
write32le(loc, setLO12_S(read32le(loc), lo));
602612
return;
603613
}
614+
case R_RISCV_GPREL_ADD:
615+
case R_RISCV_GPREL_SHXADD: {
616+
write32le(loc, read32le(loc));
617+
return;
618+
}
619+
620+
case INTERNAL_R_RISCV_GPREL_ADD:
621+
case INTERNAL_R_RISCV_GPREL_SHXADD: {
622+
uint32_t insn = (read32le(loc) & ~(31 << 20)) | (X_GP << 20);
623+
write32le(loc, insn);
624+
return;
625+
}
626+
627+
case INTERNAL_R_RISCV_GPREL_ADD_I:
628+
case INTERNAL_R_RISCV_GPREL_ADD_S: {
629+
Defined *gp = ctx.sym.riscvGlobalPointer;
630+
int64_t displace = SignExtend64(val - gp->getVA(ctx), bits);
631+
checkInt(ctx, loc, displace, 12, rel);
632+
uint32_t insn = read32le(loc);
633+
if (rel.type == INTERNAL_R_RISCV_GPREL_ADD_I)
634+
insn = setLO12_I(insn, displace);
635+
else
636+
insn = setLO12_S(insn, displace);
637+
638+
write32le(loc, insn);
639+
return;
640+
}
604641

605642
case INTERNAL_R_RISCV_X0REL_I:
606643
case INTERNAL_R_RISCV_X0REL_S: {
@@ -986,6 +1023,19 @@ static void relaxHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
9861023
case R_RISCV_LO12_S:
9871024
sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_S;
9881025
break;
1026+
1027+
case R_RISCV_GPREL_ADD:
1028+
sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_ADD;
1029+
break;
1030+
case R_RISCV_GPREL_SHXADD:
1031+
sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_SHXADD;
1032+
break;
1033+
case R_RISCV_GPREL_LO12_I:
1034+
sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_ADD_I;
1035+
break;
1036+
case R_RISCV_GPREL_LO12_S:
1037+
sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_ADD_S;
1038+
break;
9891039
}
9901040
}
9911041

@@ -1041,6 +1091,10 @@ static bool relax(Ctx &ctx, int pass, InputSection &sec) {
10411091
case R_RISCV_HI20:
10421092
case R_RISCV_LO12_I:
10431093
case R_RISCV_LO12_S:
1094+
case R_RISCV_GPREL_ADD:
1095+
case R_RISCV_GPREL_SHXADD:
1096+
case R_RISCV_GPREL_LO12_I:
1097+
case R_RISCV_GPREL_LO12_S:
10441098
if (relaxable(relocs, i))
10451099
relaxHi20Lo12(ctx, sec, i, loc, r, remove);
10461100
break;
@@ -1284,6 +1338,10 @@ void RISCV::finalizeRelax(int passes) const {
12841338
case INTERNAL_R_RISCV_GPREL_S:
12851339
case INTERNAL_R_RISCV_X0REL_I:
12861340
case INTERNAL_R_RISCV_X0REL_S:
1341+
case INTERNAL_R_RISCV_GPREL_ADD:
1342+
case INTERNAL_R_RISCV_GPREL_SHXADD:
1343+
case INTERNAL_R_RISCV_GPREL_ADD_I:
1344+
case INTERNAL_R_RISCV_GPREL_ADD_S:
12871345
break;
12881346
case R_RISCV_RELAX:
12891347
// Used by relaxTlsLe to indicate the relocation is ignored.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# REQUIRES: riscv
2+
# RUN: rm -rf %t && split-file %s %t && cd %t
3+
4+
# RUN: llvm-mc -filetype=obj -triple=riscv32-unknown-elf -mattr=+relax a.s -o rv32.o
5+
# RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf -mattr=+relax a.s -o rv64.o
6+
7+
# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv32.o lds -o rv32
8+
# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv64.o lds -o rv64
9+
# RUN: llvm-objdump -td -M no-aliases --no-show-raw-insn rv32 | FileCheck %s
10+
# RUN: llvm-objdump -td -M no-aliases --no-show-raw-insn rv64 | FileCheck %s
11+
12+
# CHECK: 00000000 l .text {{0*}}0 $x
13+
14+
# CHECK-NOT: lui
15+
# CHECK: addi a1, a1, -0x800
16+
# CHECK-NEXT: add a0, a0, gp
17+
# CHECK-NEXT: lw a0, -0x800(a0)
18+
# CHECK-NEXT: sw a0, -0x800(a0)
19+
# CHECK-NOT: lui
20+
# CHECK-NEXT: addi a1, a1, 0x7fa
21+
# CHECK-NEXT: add a0, a0, gp
22+
# CHECK-NEXT: lw a0, 0x7fa(a0)
23+
# CHECK-NEXT: sw a0, 0x7fa(a0)
24+
# CHECK-NEXT: lui a1, 0x201
25+
# CHECK-NEXT: addi a1, a1, 0xe
26+
# CHECK-NEXT: add a0, a0, a1
27+
# CHECK-NEXT: lw a0, 0xe(a0)
28+
# CHECK-NEXT: sw a0, 0xe(a0)
29+
# CHECK-EMPTY:
30+
# CHECK-NEXT: <a>:
31+
# CHECK-NEXT: addi a0, a0, 0x1
32+
33+
#--- a.s
34+
.global _start
35+
_start:
36+
slli a0, a0, 2
37+
lui a1, %hi(array)
38+
addi a1, a1, %gprel_lo(array)
39+
add a0, a0, a1, %gprel_add(array)
40+
lw a0, %gprel_lo(array)(a0)
41+
sw a0, %gprel_lo(array)(a0)
42+
lui a1, %hi(array1+10)
43+
addi a1, a1, %gprel_lo(array1+10)
44+
add a0, a0, a1, %gprel_add(array1+10)
45+
lw a0, %gprel_lo(array1+10)(a0)
46+
sw a0, %gprel_lo(array1+10)(a0)
47+
lui a1, %hi(norelax+10)
48+
addi a1, a1, %gprel_lo(norelax+10)
49+
add a0, a0, a1, %gprel_add(norelax+10)
50+
lw a0, %gprel_lo(norelax+10)(a0)
51+
sw a0, %gprel_lo(norelax+10)(a0)
52+
a:
53+
addi a0, a0, 1
54+
55+
.section .sdata,"aw"
56+
array:
57+
.zero 4080
58+
.size array, 4080
59+
array1:
60+
.zero 20
61+
.size array, 20
62+
norelax:
63+
.zero 6
64+
.size array, 6
65+
66+
#--- lds
67+
SECTIONS {
68+
.text : {*(.text) }
69+
.sdata 0x200000 : { }
70+
}
71+
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# REQUIRES: riscv
2+
# RUN: rm -rf %t && split-file %s %t && cd %t
3+
4+
# RUN: llvm-mc -filetype=obj -triple=riscv32-unknown-elf -mattr=+relax,+zba a.s -o rv32.o
5+
# RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf -mattr=+relax,+zba a.s -o rv64.o
6+
7+
# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv32.o lds -o rv32
8+
# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv64.o lds -o rv64
9+
# RUN: llvm-objdump --mattr=+zba -td -M no-aliases --no-show-raw-insn rv32 | FileCheck %s
10+
# RUN: llvm-objdump --mattr=+zba -td -M no-aliases --no-show-raw-insn rv64 | FileCheck %s
11+
12+
# CHECK: 00000000 l .text {{0*}}0 $x
13+
14+
# CHECK-NOT: lui
15+
# CHECK: addi a1, a1, -0x800
16+
# CHECK-NEXT: sh1add a0, a0, gp
17+
# CHECK-NEXT: lw a0, -0x800(a0)
18+
# CHECK-NEXT: sw a0, -0x800(a0)
19+
# CHECK-NOT: lui
20+
# CHECK-NEXT: addi a1, a1, 0x7fa
21+
# CHECK-NEXT: sh1add a0, a0, gp
22+
# CHECK-NEXT: lw a0, 0x7fa(a0)
23+
# CHECK-NEXT: sw a0, 0x7fa(a0)
24+
# CHECK-NEXT: lui a1, 0x201
25+
# CHECK-NEXT: addi a1, a1, 0xe
26+
# CHECK-NEXT: sh1add a0, a0, a1
27+
# CHECK-NEXT: lw a0, 0xe(a0)
28+
# CHECK-NEXT: sw a0, 0xe(a0)
29+
# CHECK-EMPTY:
30+
# CHECK-NEXT: <a>:
31+
# CHECK-NEXT: addi a0, a0, 0x1
32+
33+
#--- a.s
34+
.global _start
35+
_start:
36+
lui a1, %hi(array)
37+
addi a1, a1, %gprel_lo(array)
38+
sh1add a0, a0, a1, %gprel_shxadd(array)
39+
lw a0, %gprel_lo(array)(a0)
40+
sw a0, %gprel_lo(array)(a0)
41+
lui a1, %hi(array1+10)
42+
addi a1, a1, %gprel_lo(array1+10)
43+
sh1add a0, a0, a1, %gprel_shxadd(array1+10)
44+
lw a0, %gprel_lo(array1+10)(a0)
45+
sw a0, %gprel_lo(array1+10)(a0)
46+
lui a1, %hi(norelax+10)
47+
addi a1, a1, %gprel_lo(norelax+10)
48+
sh1add a0, a0, a1, %gprel_shxadd(norelax+10)
49+
lw a0, %gprel_lo(norelax+10)(a0)
50+
sw a0, %gprel_lo(norelax+10)(a0)
51+
a:
52+
addi a0, a0, 1
53+
54+
.section .sdata,"aw"
55+
array:
56+
.zero 4080
57+
.size array, 4080
58+
array1:
59+
.zero 20
60+
.size array, 20
61+
norelax:
62+
.zero 6
63+
.size array, 6
64+
65+
#--- lds
66+
SECTIONS {
67+
.text : {*(.text) }
68+
.sdata 0x200000 : { }
69+
}
70+

llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ ELF_RELOC(R_RISCV_TLSDESC_HI20, 62)
6060
ELF_RELOC(R_RISCV_TLSDESC_LOAD_LO12, 63)
6161
ELF_RELOC(R_RISCV_TLSDESC_ADD_LO12, 64)
6262
ELF_RELOC(R_RISCV_TLSDESC_CALL, 65)
63+
ELF_RELOC(R_RISCV_GPREL_LO12_I, 66)
64+
ELF_RELOC(R_RISCV_GPREL_LO12_S, 67)
65+
ELF_RELOC(R_RISCV_GPREL_ADD, 68)
66+
ELF_RELOC(R_RISCV_GPREL_SHXADD, 69)
6367
ELF_RELOC(R_RISCV_VENDOR, 191)
6468
ELF_RELOC(R_RISCV_CUSTOM192, 192)
6569
ELF_RELOC(R_RISCV_CUSTOM193, 193)

llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,17 @@ struct RISCVOperand final : public MCParsedAsmOperand {
608608
VK == ELF::R_RISCV_TPREL_ADD;
609609
}
610610

611+
bool isGPRelAddSymbol() const {
612+
int64_t Imm;
613+
// Must be of 'immediate' type but not a constant.
614+
if (!isExpr() || evaluateConstantExpr(getExpr(), Imm))
615+
return false;
616+
617+
RISCV::Specifier VK = RISCV::S_None;
618+
return RISCVAsmParser::classifySymbolRef(getExpr(), VK) &&
619+
(VK == ELF::R_RISCV_GPREL_ADD || VK == ELF::R_RISCV_GPREL_SHXADD);
620+
}
621+
611622
bool isTLSDESCCallSymbol() const {
612623
int64_t Imm;
613624
// Must be of 'immediate' type but not a constant.
@@ -870,7 +881,8 @@ struct RISCVOperand final : public MCParsedAsmOperand {
870881
RISCV::Specifier VK = RISCV::S_None;
871882
return RISCVAsmParser::classifySymbolRef(getExpr(), VK) &&
872883
(VK == RISCV::S_LO || VK == RISCV::S_PCREL_LO ||
873-
VK == RISCV::S_TPREL_LO || VK == ELF::R_RISCV_TLSDESC_LOAD_LO12 ||
884+
VK == RISCV::S_GPREL_LO || VK == RISCV::S_TPREL_LO ||
885+
VK == ELF::R_RISCV_TLSDESC_LOAD_LO12 ||
874886
VK == ELF::R_RISCV_TLSDESC_ADD_LO12);
875887
}
876888

llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ MCFixupKindInfo RISCVAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
7777
{"fixup_riscv_lo12_i", 20, 12, 0},
7878
{"fixup_riscv_12_i", 20, 12, 0},
7979
{"fixup_riscv_lo12_s", 0, 32, 0},
80+
{"fixup_riscv_gprel_lo12_i", 20, 12, 0},
81+
{"fixup_riscv_gprel_lo12_s", 0, 32, 0},
82+
{"fixup_riscv_gprel_add", 0, 0, 0},
83+
{"fixup_riscv_gprel_shxadd", 0, 0, 0},
8084
{"fixup_riscv_pcrel_hi20", 12, 20, 0},
8185
{"fixup_riscv_pcrel_lo12_i", 20, 12, 0},
8286
{"fixup_riscv_pcrel_lo12_s", 0, 32, 0},
@@ -506,6 +510,7 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
506510
case FK_Data_leb128:
507511
return Value;
508512
case RISCV::fixup_riscv_lo12_i:
513+
case RISCV::fixup_riscv_gprel_lo12_i:
509514
case RISCV::fixup_riscv_pcrel_lo12_i:
510515
return Value & 0xfff;
511516
case RISCV::fixup_riscv_12_i:
@@ -515,6 +520,7 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
515520
}
516521
return Value & 0xfff;
517522
case RISCV::fixup_riscv_lo12_s:
523+
case RISCV::fixup_riscv_gprel_lo12_s:
518524
case RISCV::fixup_riscv_pcrel_lo12_s:
519525
return (((Value >> 5) & 0x7f) << 25) | ((Value & 0x1f) << 7);
520526
case RISCV::fixup_riscv_hi20:

llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,10 @@ enum {
470470
MO_TLSDESC_ADD_LO = 15,
471471
MO_TLSDESC_CALL = 16,
472472

473+
MO_GPREL_LO = 17,
474+
MO_GPREL_ADD = 18,
475+
MO_GPREL_SHXADD = 19,
476+
473477
// Used to differentiate between target-specific "direct" flags and "bitmask"
474478
// flags. A machine operand can only have one "direct" flag, but can have
475479
// multiple "bitmask" flags.

llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,14 @@ unsigned RISCVELFObjectWriter::getRelocType(const MCFixup &Fixup,
135135
return ELF::R_RISCV_LO12_I;
136136
case RISCV::fixup_riscv_lo12_s:
137137
return ELF::R_RISCV_LO12_S;
138+
case RISCV::fixup_riscv_gprel_lo12_i:
139+
return ELF::R_RISCV_GPREL_LO12_I;
140+
case RISCV::fixup_riscv_gprel_lo12_s:
141+
return ELF::R_RISCV_GPREL_LO12_S;
142+
case RISCV::fixup_riscv_gprel_add:
143+
return ELF::R_RISCV_GPREL_ADD;
144+
case RISCV::fixup_riscv_gprel_shxadd:
145+
return ELF::R_RISCV_GPREL_SHXADD;
138146
case RISCV::fixup_riscv_rvc_imm:
139147
reportError(Fixup.getLoc(), "No relocation for CI-type instructions");
140148
return ELF::R_RISCV_NONE;

llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,18 @@ enum Fixups {
2424
fixup_riscv_12_i,
2525
// 12-bit fixup corresponding to %lo(foo) for the S-type store instructions
2626
fixup_riscv_lo12_s,
27+
// 12-bit fixup corresponding to %gprel_lo(foo) for instructions like addi
28+
fixup_riscv_gprel_lo12_i,
29+
// 12-bit fixup corresponding to %gprel_lo(foo) for the S-type store
30+
// instructions
31+
fixup_riscv_gprel_lo12_s,
32+
// Fixup corresponding to %gprel_add(foo) for PseudoAddGPRel/PseudoAddUWGPRel,
33+
// used as a linker hint
34+
fixup_riscv_gprel_add,
35+
// Fixup corresponding to %gprel_shxadd(foo) for
36+
// PseudoSh1AddGPRel/PseudoSh2AddGPRel/PseudoSh3AddGPRel/PseudoSh1AddUWGPRel/PseudoSh2AddUWGPRel/PseudoSh3AddUWGPRel,
37+
// used as a linker hint
38+
fixup_riscv_gprel_shxadd,
2739
// 20-bit fixup corresponding to %pcrel_hi(foo) for instructions like auipc
2840
fixup_riscv_pcrel_hi20,
2941
// 12-bit fixup corresponding to %pcrel_lo(foo) for instructions like addi

llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ enum {
4545
S_TPREL_LO,
4646
S_CALL_PLT,
4747
S_GOT_HI,
48+
S_GPREL_LO,
4849
// Vendor-specific relocation types might conflict across vendors.
4950
// Refer to them using Specifier constants.
5051
S_QC_ABS20,

0 commit comments

Comments
 (0)