Skip to content

Commit 2f54efd

Browse files
authored
[MachineOutliner] Don't outline ADRP pair to avoid incorrect ICF (llvm#160232)
On AArch64, ADRP and its user instructions (LDR, ADD, etc.), that are referencing a GOT symbol, when separated into different functions by machine outliner exposes a correctness issue in the linker ICF. In such cases, user instructions can end up pointing to a folded section (with its canonical folded symbol), while ADRP instruction point to a GOT entry corresponding to the original symbol. This leads to loading from incorrect memory address after ICF. llvm#129122 explains how this can happen in detail. This addresses llvm#131660 which should fix two things: 1. Hide the correctness issue described above in the LLVM linker. 2. Allows optimizations that could relax GOT addressing to PC-relative addressing.
1 parent 70a6475 commit 2f54efd

File tree

2 files changed

+154
-0
lines changed

2 files changed

+154
-0
lines changed

llvm/lib/Target/AArch64/AArch64InstrInfo.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9590,6 +9590,27 @@ AArch64InstrInfo::getOutliningCandidateInfo(
95909590

95919591
unsigned NumBytesToCreateFrame = 0;
95929592

9593+
// Avoid splitting ADRP ADD/LDR pair into outlined functions.
9594+
// These instructions are fused together by the scheduler.
9595+
// Any candidate where ADRP is the last instruction should be rejected
9596+
// as that will lead to splitting ADRP pair.
9597+
MachineInstr &LastMI = RepeatedSequenceLocs[0].back();
9598+
MachineInstr &FirstMI = RepeatedSequenceLocs[0].front();
9599+
if (LastMI.getOpcode() == AArch64::ADRP &&
9600+
(LastMI.getOperand(1).getTargetFlags() & AArch64II::MO_PAGE) != 0 &&
9601+
(LastMI.getOperand(1).getTargetFlags() & AArch64II::MO_GOT) != 0) {
9602+
return std::nullopt;
9603+
}
9604+
9605+
// Similarly any candidate where the first instruction is ADD/LDR with a
9606+
// page offset should be rejected to avoid ADRP splitting.
9607+
if ((FirstMI.getOpcode() == AArch64::ADDXri ||
9608+
FirstMI.getOpcode() == AArch64::LDRXui) &&
9609+
(FirstMI.getOperand(2).getTargetFlags() & AArch64II::MO_PAGEOFF) != 0 &&
9610+
(FirstMI.getOperand(2).getTargetFlags() & AArch64II::MO_GOT) != 0) {
9611+
return std::nullopt;
9612+
}
9613+
95939614
// We only allow outlining for functions having exactly matching return
95949615
// address signing attributes, i.e., all share the same value for the
95959616
// attribute "sign-return-address" and all share the same type of key they
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
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+
attributes #0 = { noinline noredzone }
15+
...
16+
---
17+
# Check that main function body doesn't split ADRP pair
18+
#
19+
# CHECK-LABEL: name: adrp_add
20+
# CHECK-DAG: bb.0:
21+
# CHECK: BL @OUTLINED_FUNCTION_[[F0:[0-9]+]]
22+
# CHECK-NEXT: BL @OUTLINED_FUNCTION_[[F2:[0-9]+]]
23+
# CHECK-NEXT: $lr = ORRXri $xzr, 1
24+
name: adrp_add
25+
tracksRegLiveness: true
26+
body: |
27+
bb.0:
28+
liveins: $lr
29+
$w12 = ORRWri $wzr, 1
30+
$w12 = ORRWri $wzr, 1
31+
$w12 = ORRWri $wzr, 1
32+
$w12 = ORRWri $wzr, 1
33+
$w12 = ORRWri $wzr, 1
34+
$w12 = ORRWri $wzr, 1
35+
$x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
36+
$x12 = ADDXri $x9, target-flags(aarch64-pageoff, aarch64-got) @x, 0
37+
$lr = ORRXri $xzr, 1
38+
bb.1:
39+
liveins: $lr
40+
$w12 = ORRWri $wzr, 1
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+
$x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
47+
$x12 = ADDXri $x9, target-flags(aarch64-pageoff, aarch64-got) @x, 0
48+
$lr = ORRXri $xzr, 1
49+
bb.2:
50+
liveins: $lr
51+
$w12 = ORRWri $wzr, 1
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+
$x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
58+
$x12 = ADDXri $x9, target-flags(aarch64-pageoff, aarch64-got) @x, 0
59+
$lr = ORRXri $xzr, 1
60+
bb.3:
61+
liveins: $lr
62+
RET undef $lr
63+
...
64+
---
65+
# Check that main function body doesn't split ADRP pair
66+
#
67+
# CHECK-LABEL: name: adrp_ldr
68+
# CHECK-DAG: bb.0:
69+
# CHECK: BL @OUTLINED_FUNCTION_[[F0]]
70+
# CHECK-NEXT: BL @OUTLINED_FUNCTION_[[F1:[0-9]+]]
71+
# CHECK-NEXT: $lr = ORRXri $xzr, 1
72+
name: adrp_ldr
73+
tracksRegLiveness: true
74+
body: |
75+
bb.0:
76+
liveins: $lr
77+
$w12 = ORRWri $wzr, 1
78+
$w12 = ORRWri $wzr, 1
79+
$w12 = ORRWri $wzr, 1
80+
$w12 = ORRWri $wzr, 1
81+
$w12 = ORRWri $wzr, 1
82+
$w12 = ORRWri $wzr, 1
83+
$x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
84+
$x12 = LDRXui $x9, target-flags(aarch64-pageoff, aarch64-got) @x
85+
$lr = ORRXri $xzr, 1
86+
bb.1:
87+
liveins: $lr
88+
$w12 = ORRWri $wzr, 1
89+
$w12 = ORRWri $wzr, 1
90+
$w12 = ORRWri $wzr, 1
91+
$w12 = ORRWri $wzr, 1
92+
$w12 = ORRWri $wzr, 1
93+
$w12 = ORRWri $wzr, 1
94+
$x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
95+
$x12 = LDRXui $x9, target-flags(aarch64-pageoff, aarch64-got) @x
96+
$lr = ORRXri $xzr, 1
97+
bb.2:
98+
liveins: $lr
99+
$w12 = ORRWri $wzr, 1
100+
$w12 = ORRWri $wzr, 1
101+
$w12 = ORRWri $wzr, 1
102+
$w12 = ORRWri $wzr, 1
103+
$w12 = ORRWri $wzr, 1
104+
$w12 = ORRWri $wzr, 1
105+
$x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
106+
$x12 = LDRXui $x9, target-flags(aarch64-pageoff, aarch64-got) @x
107+
$lr = ORRXri $xzr, 1
108+
bb.3:
109+
liveins: $lr
110+
RET undef $lr
111+
112+
# Check that no outlined function split the ADRP pair apart
113+
#
114+
# CHECK: OUTLINED_FUNCTION_[[F0]]
115+
# CHECK-DAG: bb.0
116+
# CHECK: $w12 = ORRWri $wzr, 1
117+
# CHECK-NEXT: $w12 = ORRWri $wzr, 1
118+
# CHECK-NEXT: $w12 = ORRWri $wzr, 1
119+
# CHECK-NEXT: $w12 = ORRWri $wzr, 1
120+
# CHECK-NEXT: $w12 = ORRWri $wzr, 1
121+
# CHECK-NEXT: RET $lr
122+
123+
# CHECK: OUTLINED_FUNCTION_[[F1]]
124+
# CHECK-DAG: bb.0
125+
# CHECK: $w12 = ORRWri $wzr, 1
126+
# CHECK-NEXT: $x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
127+
# CHECK-NEXT: $x12 = LDRXui $x9, target-flags(aarch64-pageoff, aarch64-got) @x
128+
129+
# CHECK: name: OUTLINED_FUNCTION_[[F2]]
130+
# CHECK-DAG: bb.0
131+
# CHECK: $w12 = ORRWri $wzr, 1
132+
# CHECK-NEXT: $x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
133+
# CHECK-NEXT: $x12 = ADDXri $x9, target-flags(aarch64-pageoff, aarch64-got) @x, 0

0 commit comments

Comments
 (0)