Skip to content

Commit b4216f1

Browse files
committed
[MachineOutliner] Don't outline ADRP pair to avoid incorrect ICF
Fixes llvm#131660 Earlier attempts to fix this in the linker were not accepted. Current attempts is pending at llvm#139493
1 parent 6a43c66 commit b4216f1

File tree

2 files changed

+156
-4
lines changed

2 files changed

+156
-4
lines changed

llvm/lib/Target/AArch64/AArch64InstrInfo.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10179,11 +10179,33 @@ AArch64InstrInfo::getOutliningTypeImpl(const MachineModuleInfo &MMI,
1017910179
return outliner::InstrType::Illegal;
1018010180
}
1018110181

10182-
// Special cases for instructions that can always be outlined, but will fail
10183-
// the later tests. e.g, ADRPs, which are PC-relative use LR, but can always
10184-
// be outlined because they don't require a *specific* value to be in LR.
10185-
if (MI.getOpcode() == AArch64::ADRP)
10182+
// An ADRP instruction referencing a GOT should not be outlined.
10183+
// This is to avoid splitting ADRP/(LDR/ADD/etc.) pair into different
10184+
// functions which can lead to linker ICF merging sections incorrectly.
10185+
if (MI.getOpcode() == AArch64::ADRP) {
10186+
bool IsPage = (MI.getOperand(1).getTargetFlags() & AArch64II::MO_PAGE) != 0;
10187+
bool IsGot = (MI.getOperand(1).getTargetFlags() & AArch64II::MO_GOT) != 0;
10188+
if (IsPage && IsGot)
10189+
return outliner::InstrType::Illegal;
10190+
10191+
// Special cases for instructions that can always be outlined, but will fail
10192+
// the later tests. e.g, ADRPs, which are PC-relative use LR, but can always
10193+
// be outlined because they don't require a *specific* value to be in LR.
1018610194
return outliner::InstrType::Legal;
10195+
}
10196+
10197+
// Similarly, any user of ADRP instruction referencing a GOT should not be
10198+
// outlined. It's hard/costly to check exact users of ADRP. So we use check
10199+
// all operands and reject any that's a page offset and references a GOT.
10200+
const auto &F = MI.getMF()->getFunction();
10201+
for (const auto &MO : MI.operands()) {
10202+
bool IsPageOff = (MO.getTargetFlags() & AArch64II::MO_PAGEOFF) != 0;
10203+
bool IsGot = (MO.getTargetFlags() & AArch64II::MO_GOT) != 0;
10204+
if (IsPageOff && IsGot &&
10205+
(MI.getMF()->getTarget().getFunctionSections() || F.hasComdat() ||
10206+
F.hasSection() || F.getSectionPrefix()))
10207+
return outliner::InstrType::Illegal;
10208+
}
1018710209

1018810210
// If MI is a call we might be able to outline it. We don't want to outline
1018910211
// any calls that rely on the position of items on the stack. When we outline
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# RUN: llc -mtriple=aarch64--- -run-pass=machine-outliner -verify-machineinstrs %s -o - | FileCheck %s
2+
--- |
3+
4+
@x = common global i32 0, align 4
5+
6+
define i32 @adrp_add() #0 {
7+
ret i32 0
8+
}
9+
10+
define i32 @adrp_ldr() #0 {
11+
ret i32 0
12+
}
13+
14+
define void @bar(i32 %a) #0 {
15+
ret void
16+
}
17+
18+
attributes #0 = { noinline noredzone }
19+
...
20+
---
21+
# This test ensures that we do not outline ADRP / ADD pair when it's referencing
22+
# a GOT entry.
23+
#
24+
# CHECK-LABEL: name: adrp_add
25+
# CHECK-DAG: bb.0:
26+
# CHECK: $x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
27+
# CHECK: $x12 = ADDXri $x9, target-flags(aarch64-pageoff, aarch64-got) @x, 0
28+
29+
# CHECK-DAG: bb.1
30+
# CHECK: $x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
31+
# CHECK: $x12 = ADDXri $x9, target-flags(aarch64-pageoff, aarch64-got) @x, 0
32+
33+
# CHECK-DAG: bb.2
34+
# CHECK: $x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
35+
# CHECK: $x12 = ADDXri $x9, target-flags(aarch64-pageoff, aarch64-got) @x, 0
36+
name: adrp_add
37+
tracksRegLiveness: true
38+
body: |
39+
bb.0:
40+
liveins: $lr
41+
$w12 = ORRWri $wzr, 1
42+
$w12 = ORRWri $wzr, 1
43+
$w12 = ORRWri $wzr, 1
44+
$w12 = ORRWri $wzr, 1
45+
$w12 = ORRWri $wzr, 1
46+
$w12 = ORRWri $wzr, 1
47+
$x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
48+
$x12 = ADDXri $x9, target-flags(aarch64-pageoff, aarch64-got) @x, 0
49+
$lr = ORRXri $xzr, 1
50+
bb.1:
51+
liveins: $lr
52+
$w12 = ORRWri $wzr, 1
53+
$w12 = ORRWri $wzr, 1
54+
$w12 = ORRWri $wzr, 1
55+
$w12 = ORRWri $wzr, 1
56+
$w12 = ORRWri $wzr, 1
57+
$w12 = ORRWri $wzr, 1
58+
$x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
59+
$x12 = ADDXri $x9, target-flags(aarch64-pageoff, aarch64-got) @x, 0
60+
$lr = ORRXri $xzr, 1
61+
bb.2:
62+
liveins: $lr
63+
$w12 = ORRWri $wzr, 1
64+
$w12 = ORRWri $wzr, 1
65+
$w12 = ORRWri $wzr, 1
66+
$w12 = ORRWri $wzr, 1
67+
$w12 = ORRWri $wzr, 1
68+
$w12 = ORRWri $wzr, 1
69+
$x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
70+
$x12 = ADDXri $x9, target-flags(aarch64-pageoff, aarch64-got) @x, 0
71+
$lr = ORRXri $xzr, 1
72+
bb.3:
73+
liveins: $lr
74+
RET undef $lr
75+
...
76+
---
77+
# This test ensures that we do not outline ADRP / LDR pair when it's referencing
78+
# a GOT entry.
79+
#
80+
# CHECK-LABEL: name: adrp_ldr
81+
# CHECK-DAG: bb.0:
82+
# CHECK: $x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
83+
# CHECK: $x12 = LDRXui $x9, target-flags(aarch64-pageoff, aarch64-got) @x
84+
85+
# CHECK-DAG: bb.1
86+
# CHECK: $x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
87+
# CHECK: $x12 = LDRXui $x9, target-flags(aarch64-pageoff, aarch64-got) @x
88+
89+
# CHECK-DAG: bb.2
90+
# CHECK: $x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
91+
# CHECK: $x12 = LDRXui $x9, target-flags(aarch64-pageoff, aarch64-got) @x
92+
name: adrp_ldr
93+
tracksRegLiveness: true
94+
body: |
95+
bb.0:
96+
liveins: $lr
97+
$w12 = ORRWri $wzr, 1
98+
$w12 = ORRWri $wzr, 1
99+
$w12 = ORRWri $wzr, 1
100+
$w12 = ORRWri $wzr, 1
101+
$w12 = ORRWri $wzr, 1
102+
$w12 = ORRWri $wzr, 1
103+
$x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
104+
$x12 = LDRXui $x9, target-flags(aarch64-pageoff, aarch64-got) @x
105+
$lr = ORRXri $xzr, 1
106+
bb.1:
107+
liveins: $lr
108+
$w12 = ORRWri $wzr, 1
109+
$w12 = ORRWri $wzr, 1
110+
$w12 = ORRWri $wzr, 1
111+
$w12 = ORRWri $wzr, 1
112+
$w12 = ORRWri $wzr, 1
113+
$w12 = ORRWri $wzr, 1
114+
$x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
115+
$x12 = LDRXui $x9, target-flags(aarch64-pageoff, aarch64-got) @x
116+
$lr = ORRXri $xzr, 1
117+
bb.2:
118+
liveins: $lr
119+
$w12 = ORRWri $wzr, 1
120+
$w12 = ORRWri $wzr, 1
121+
$w12 = ORRWri $wzr, 1
122+
$w12 = ORRWri $wzr, 1
123+
$w12 = ORRWri $wzr, 1
124+
$w12 = ORRWri $wzr, 1
125+
$x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
126+
$x12 = LDRXui $x9, target-flags(aarch64-pageoff, aarch64-got) @x
127+
$lr = ORRXri $xzr, 1
128+
bb.3:
129+
liveins: $lr
130+
RET undef $lr

0 commit comments

Comments
 (0)