Skip to content

Commit a8081ed

Browse files
authored
[LoongArch] Allow delayed decision for ADD/SUB relocations (llvm#72960)
Refer to RISCV [1], LoongArch also need delayed decision for ADD/SUB relocations. In handleAddSubRelocations, just return directly if SecA != SecB, handleFixup usually will finish the the rest of creating PCRel relocations works. Otherwise we emit relocs depends on whether relaxation is enabled. If not, we return true and avoid record ADD/SUB relocations. Now the two symbols separated by alignment directive will return without folding symbol offset in AttemptToFoldSymbolOffsetDifference, which has the same effect when relaxation is enabled. [1] https://reviews.llvm.org/D155357
1 parent e6a7175 commit a8081ed

File tree

6 files changed

+196
-4
lines changed

6 files changed

+196
-4
lines changed

llvm/lib/MC/MCExpr.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,8 @@ static void AttemptToFoldSymbolOffsetDifference(
632632
// instructions and InSet is false (not expressions in directive like
633633
// .size/.fill), disable the fast path.
634634
if (Layout && (InSet || !SecA.hasInstructions() ||
635-
!Asm->getContext().getTargetTriple().isRISCV())) {
635+
!(Asm->getContext().getTargetTriple().isRISCV() ||
636+
Asm->getContext().getTargetTriple().isLoongArch()))) {
636637
// If both symbols are in the same fragment, return the difference of their
637638
// offsets. canGetFragmentOffset(FA) may be false.
638639
if (FA == FB && !SA.isVariable() && !SB.isVariable()) {

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,34 @@ bool LoongArchAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
177177
}
178178
}
179179

180+
static inline std::pair<MCFixupKind, MCFixupKind>
181+
getRelocPairForSize(unsigned Size) {
182+
switch (Size) {
183+
default:
184+
llvm_unreachable("unsupported fixup size");
185+
case 6:
186+
return std::make_pair(
187+
MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_ADD6),
188+
MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_SUB6));
189+
case 8:
190+
return std::make_pair(
191+
MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_ADD8),
192+
MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_SUB8));
193+
case 16:
194+
return std::make_pair(
195+
MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_ADD16),
196+
MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_SUB16));
197+
case 32:
198+
return std::make_pair(
199+
MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_ADD32),
200+
MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_SUB32));
201+
case 64:
202+
return std::make_pair(
203+
MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_ADD64),
204+
MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_SUB64));
205+
}
206+
}
207+
180208
bool LoongArchAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
181209
const MCSubtargetInfo *STI) const {
182210
// We mostly follow binutils' convention here: align to 4-byte boundary with a
@@ -191,6 +219,56 @@ bool LoongArchAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
191219
return true;
192220
}
193221

222+
bool LoongArchAsmBackend::handleAddSubRelocations(const MCAsmLayout &Layout,
223+
const MCFragment &F,
224+
const MCFixup &Fixup,
225+
const MCValue &Target,
226+
uint64_t &FixedValue) const {
227+
std::pair<MCFixupKind, MCFixupKind> FK;
228+
uint64_t FixedValueA, FixedValueB;
229+
const MCSection &SecA = Target.getSymA()->getSymbol().getSection();
230+
const MCSection &SecB = Target.getSymB()->getSymbol().getSection();
231+
232+
// We need record relocation if SecA != SecB. Usually SecB is same as the
233+
// section of Fixup, which will be record the relocation as PCRel. If SecB
234+
// is not same as the section of Fixup, it will report error. Just return
235+
// false and then this work can be finished by handleFixup.
236+
if (&SecA != &SecB)
237+
return false;
238+
239+
// In SecA == SecB case. If the linker relaxation is enabled, we need record
240+
// the ADD, SUB relocations. Otherwise the FixedValue has already been
241+
// calculated out in evaluateFixup, return true and avoid record relocations.
242+
if (!STI.hasFeature(LoongArch::FeatureRelax))
243+
return true;
244+
245+
switch (Fixup.getKind()) {
246+
case llvm::FK_Data_1:
247+
FK = getRelocPairForSize(8);
248+
break;
249+
case llvm::FK_Data_2:
250+
FK = getRelocPairForSize(16);
251+
break;
252+
case llvm::FK_Data_4:
253+
FK = getRelocPairForSize(32);
254+
break;
255+
case llvm::FK_Data_8:
256+
FK = getRelocPairForSize(64);
257+
break;
258+
default:
259+
llvm_unreachable("unsupported fixup size");
260+
}
261+
MCValue A = MCValue::get(Target.getSymA(), nullptr, Target.getConstant());
262+
MCValue B = MCValue::get(Target.getSymB());
263+
auto FA = MCFixup::create(Fixup.getOffset(), nullptr, std::get<0>(FK));
264+
auto FB = MCFixup::create(Fixup.getOffset(), nullptr, std::get<1>(FK));
265+
auto &Asm = Layout.getAssembler();
266+
Asm.getWriter().recordRelocation(Asm, Layout, &F, FA, A, FixedValueA);
267+
Asm.getWriter().recordRelocation(Asm, Layout, &F, FB, B, FixedValueB);
268+
FixedValue = FixedValueA - FixedValueB;
269+
return true;
270+
}
271+
194272
std::unique_ptr<MCObjectTargetWriter>
195273
LoongArchAsmBackend::createObjectTargetWriter() const {
196274
return createLoongArchELFObjectWriter(

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,15 @@ class LoongArchAsmBackend : public MCAsmBackend {
3131
public:
3232
LoongArchAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI, bool Is64Bit,
3333
const MCTargetOptions &Options)
34-
: MCAsmBackend(llvm::endianness::little), STI(STI), OSABI(OSABI),
35-
Is64Bit(Is64Bit), TargetOptions(Options) {}
34+
: MCAsmBackend(llvm::endianness::little,
35+
LoongArch::fixup_loongarch_relax),
36+
STI(STI), OSABI(OSABI), Is64Bit(Is64Bit), TargetOptions(Options) {}
3637
~LoongArchAsmBackend() override {}
3738

39+
bool handleAddSubRelocations(const MCAsmLayout &Layout, const MCFragment &F,
40+
const MCFixup &Fixup, const MCValue &Target,
41+
uint64_t &FixedValue) const override;
42+
3843
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
3944
const MCValue &Target, MutableArrayRef<char> Data,
4045
uint64_t Value, bool IsResolved,

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchFixupKinds.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,9 @@ enum Fixups {
106106
// 20-bit fixup corresponding to %gd_pc_hi20(foo) for instruction pcalau12i.
107107
fixup_loongarch_tls_gd_pc_hi20,
108108
// 20-bit fixup corresponding to %gd_hi20(foo) for instruction lu12i.w.
109-
fixup_loongarch_tls_gd_hi20
109+
fixup_loongarch_tls_gd_hi20,
110+
// Generate an R_LARCH_RELAX which indicates the linker may relax here.
111+
fixup_loongarch_relax = FirstLiteralRelocationKind + ELF::R_LARCH_RELAX
110112
};
111113
} // end namespace LoongArch
112114
} // end namespace llvm
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# RUN: not llvm-mc --filetype=obj --triple=loongarch64 --mattr=-relax %s -o /dev/null 2>&1 | FileCheck %s --check-prefixes=ERR,NORELAX --implicit-check-not=error:
2+
## TODO: not llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o /dev/null 2>&1 | FileCheck %s --check-prefixes=ERR,RELAX --implicit-check-not=error:
3+
4+
a:
5+
nop
6+
b:
7+
la.pcrel $t0, a
8+
c:
9+
nop
10+
d:
11+
12+
.data
13+
## Positive subsection numbers
14+
## With relaxation, report an error as c-b is not an assemble-time constant.
15+
# RELAX: :[[#@LINE+1]]:14: error: cannot evaluate subsection number
16+
.subsection c-b
17+
# RELAX: :[[#@LINE+1]]:14: error: cannot evaluate subsection number
18+
.subsection d-b
19+
# RELAX: :[[#@LINE+1]]:14: error: cannot evaluate subsection number
20+
.subsection c-a
21+
22+
.subsection b-a
23+
.subsection d-c
24+
25+
## Negative subsection numbers
26+
# NORELAX: :[[#@LINE+2]]:14: error: subsection number -8 is not within [0,2147483647]
27+
# RELAX: :[[#@LINE+1]]:14: error: cannot evaluate subsection number
28+
.subsection b-c
29+
# NORELAX: :[[#@LINE+2]]:14: error: subsection number -12 is not within [0,2147483647]
30+
# RELAX: :[[#@LINE+1]]:14: error: cannot evaluate subsection number
31+
.subsection b-d
32+
# NORELAX: :[[#@LINE+2]]:14: error: subsection number -12 is not within [0,2147483647]
33+
# RELAX: :[[#@LINE+1]]:14: error: cannot evaluate subsection number
34+
.subsection a-c
35+
# ERR: :[[#@LINE+1]]:14: error: subsection number -4 is not within [0,2147483647]
36+
.subsection a-b
37+
# ERR: :[[#@LINE+1]]:14: error: subsection number -4 is not within [0,2147483647]
38+
.subsection c-d
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=-relax %s \
2+
# RUN: | llvm-readobj -r -x .data - | FileCheck %s --check-prefix=NORELAX
3+
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s \
4+
# RUN: | llvm-readobj -r -x .data - | FileCheck %s --check-prefix=RELAX
5+
6+
# NORELAX: Relocations [
7+
# NORELAX-NEXT: Section ({{.*}}) .rela.text {
8+
# NORELAX-NEXT: 0x10 R_LARCH_PCALA_HI20 .text 0x0
9+
# NORELAX-NEXT: 0x14 R_LARCH_PCALA_LO12 .text 0x0
10+
# NORELAX-NEXT: }
11+
# NORELAX-NEXT: ]
12+
13+
# NORELAX: Hex dump of section '.data':
14+
# NORELAX-NEXT: 0x00000000 04040004 00000004 00000000 0000000c
15+
# NORELAX-NEXT: 0x00000010 0c000c00 00000c00 00000000 00000808
16+
# NORELAX-NEXT: 0x00000020 00080000 00080000 00000000 00
17+
18+
# RELAX: Relocations [
19+
# RELAX-NEXT: Section ({{.*}}) .rela.text {
20+
# RELAX-NEXT: 0x10 R_LARCH_PCALA_HI20 .L1 0x0
21+
# RELAX-NEXT: 0x14 R_LARCH_PCALA_LO12 .L1 0x0
22+
# RELAX-NEXT: }
23+
# RELAX-NEXT: Section ({{.*}}) .rela.data {
24+
# RELAX-NEXT: 0xF R_LARCH_ADD8 .L3 0x0
25+
# RELAX-NEXT: 0xF R_LARCH_SUB8 .L2 0x0
26+
# RELAX-NEXT: 0x10 R_LARCH_ADD16 .L3 0x0
27+
# RELAX-NEXT: 0x10 R_LARCH_SUB16 .L2 0x0
28+
# RELAX-NEXT: 0x12 R_LARCH_ADD32 .L3 0x0
29+
# RELAX-NEXT: 0x12 R_LARCH_SUB32 .L2 0x0
30+
# RELAX-NEXT: 0x16 R_LARCH_ADD64 .L3 0x0
31+
# RELAX-NEXT: 0x16 R_LARCH_SUB64 .L2 0x0
32+
# RELAX-NEXT: }
33+
# RELAX-NEXT: ]
34+
35+
# RELAX: Hex dump of section '.data':
36+
# RELAX-NEXT: 0x00000000 04040004 00000004 00000000 00000000
37+
# RELAX-NEXT: 0x00000010 00000000 00000000 00000000 00000808
38+
# RELAX-NEXT: 0x00000020 00080000 00080000 00000000 00
39+
40+
.text
41+
.L1:
42+
nop
43+
.L2:
44+
.align 4
45+
.L3:
46+
la.pcrel $t0, .L1
47+
.L4:
48+
ret
49+
50+
.data
51+
## Not emit relocs
52+
.byte .L2 - .L1
53+
.short .L2 - .L1
54+
.word .L2 - .L1
55+
.dword .L2 - .L1
56+
## With relaxation, emit relocs because of the .align making the diff variable.
57+
## TODO Handle alignment directive. Why they emit relocs now? They returns
58+
## without folding symbols offset in AttemptToFoldSymbolOffsetDifference().
59+
.byte .L3 - .L2
60+
.short .L3 - .L2
61+
.word .L3 - .L2
62+
.dword .L3 - .L2
63+
## TODO
64+
## With relaxation, emit relocs because la.pcrel is a linker-relaxable inst.
65+
.byte .L4 - .L3
66+
.short .L4 - .L3
67+
.word .L4 - .L3
68+
.dword .L4 - .L3

0 commit comments

Comments
 (0)