[MachineOutliner] Don't outline ADRP pair to avoid incorrect ICF (#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. #129122 explains how this can happen in detail. This addresses #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.
This commit is contained in:
parent
70a6475fdd
commit
2f54efd1bf
@ -9590,6 +9590,27 @@ AArch64InstrInfo::getOutliningCandidateInfo(
|
||||
|
||||
unsigned NumBytesToCreateFrame = 0;
|
||||
|
||||
// Avoid splitting ADRP ADD/LDR pair into outlined functions.
|
||||
// These instructions are fused together by the scheduler.
|
||||
// Any candidate where ADRP is the last instruction should be rejected
|
||||
// as that will lead to splitting ADRP pair.
|
||||
MachineInstr &LastMI = RepeatedSequenceLocs[0].back();
|
||||
MachineInstr &FirstMI = RepeatedSequenceLocs[0].front();
|
||||
if (LastMI.getOpcode() == AArch64::ADRP &&
|
||||
(LastMI.getOperand(1).getTargetFlags() & AArch64II::MO_PAGE) != 0 &&
|
||||
(LastMI.getOperand(1).getTargetFlags() & AArch64II::MO_GOT) != 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Similarly any candidate where the first instruction is ADD/LDR with a
|
||||
// page offset should be rejected to avoid ADRP splitting.
|
||||
if ((FirstMI.getOpcode() == AArch64::ADDXri ||
|
||||
FirstMI.getOpcode() == AArch64::LDRXui) &&
|
||||
(FirstMI.getOperand(2).getTargetFlags() & AArch64II::MO_PAGEOFF) != 0 &&
|
||||
(FirstMI.getOperand(2).getTargetFlags() & AArch64II::MO_GOT) != 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// We only allow outlining for functions having exactly matching return
|
||||
// address signing attributes, i.e., all share the same value for the
|
||||
// attribute "sign-return-address" and all share the same type of key they
|
||||
|
||||
133
llvm/test/CodeGen/AArch64/machine-outliner-adrp-got-split.mir
Normal file
133
llvm/test/CodeGen/AArch64/machine-outliner-adrp-got-split.mir
Normal file
@ -0,0 +1,133 @@
|
||||
# RUN: llc -mtriple=aarch64--- -run-pass=machine-outliner -verify-machineinstrs %s -o - | FileCheck %s
|
||||
--- |
|
||||
|
||||
@x = common global i32 0, align 4
|
||||
|
||||
define i32 @adrp_add() #0 {
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
define i32 @adrp_ldr() #0 {
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
attributes #0 = { noinline noredzone }
|
||||
...
|
||||
---
|
||||
# Check that main function body doesn't split ADRP pair
|
||||
#
|
||||
# CHECK-LABEL: name: adrp_add
|
||||
# CHECK-DAG: bb.0:
|
||||
# CHECK: BL @OUTLINED_FUNCTION_[[F0:[0-9]+]]
|
||||
# CHECK-NEXT: BL @OUTLINED_FUNCTION_[[F2:[0-9]+]]
|
||||
# CHECK-NEXT: $lr = ORRXri $xzr, 1
|
||||
name: adrp_add
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $lr
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
|
||||
$x12 = ADDXri $x9, target-flags(aarch64-pageoff, aarch64-got) @x, 0
|
||||
$lr = ORRXri $xzr, 1
|
||||
bb.1:
|
||||
liveins: $lr
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
|
||||
$x12 = ADDXri $x9, target-flags(aarch64-pageoff, aarch64-got) @x, 0
|
||||
$lr = ORRXri $xzr, 1
|
||||
bb.2:
|
||||
liveins: $lr
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
|
||||
$x12 = ADDXri $x9, target-flags(aarch64-pageoff, aarch64-got) @x, 0
|
||||
$lr = ORRXri $xzr, 1
|
||||
bb.3:
|
||||
liveins: $lr
|
||||
RET undef $lr
|
||||
...
|
||||
---
|
||||
# Check that main function body doesn't split ADRP pair
|
||||
#
|
||||
# CHECK-LABEL: name: adrp_ldr
|
||||
# CHECK-DAG: bb.0:
|
||||
# CHECK: BL @OUTLINED_FUNCTION_[[F0]]
|
||||
# CHECK-NEXT: BL @OUTLINED_FUNCTION_[[F1:[0-9]+]]
|
||||
# CHECK-NEXT: $lr = ORRXri $xzr, 1
|
||||
name: adrp_ldr
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $lr
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
|
||||
$x12 = LDRXui $x9, target-flags(aarch64-pageoff, aarch64-got) @x
|
||||
$lr = ORRXri $xzr, 1
|
||||
bb.1:
|
||||
liveins: $lr
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
|
||||
$x12 = LDRXui $x9, target-flags(aarch64-pageoff, aarch64-got) @x
|
||||
$lr = ORRXri $xzr, 1
|
||||
bb.2:
|
||||
liveins: $lr
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$w12 = ORRWri $wzr, 1
|
||||
$x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
|
||||
$x12 = LDRXui $x9, target-flags(aarch64-pageoff, aarch64-got) @x
|
||||
$lr = ORRXri $xzr, 1
|
||||
bb.3:
|
||||
liveins: $lr
|
||||
RET undef $lr
|
||||
|
||||
# Check that no outlined function split the ADRP pair apart
|
||||
#
|
||||
# CHECK: OUTLINED_FUNCTION_[[F0]]
|
||||
# CHECK-DAG: bb.0
|
||||
# CHECK: $w12 = ORRWri $wzr, 1
|
||||
# CHECK-NEXT: $w12 = ORRWri $wzr, 1
|
||||
# CHECK-NEXT: $w12 = ORRWri $wzr, 1
|
||||
# CHECK-NEXT: $w12 = ORRWri $wzr, 1
|
||||
# CHECK-NEXT: $w12 = ORRWri $wzr, 1
|
||||
# CHECK-NEXT: RET $lr
|
||||
|
||||
# CHECK: OUTLINED_FUNCTION_[[F1]]
|
||||
# CHECK-DAG: bb.0
|
||||
# CHECK: $w12 = ORRWri $wzr, 1
|
||||
# CHECK-NEXT: $x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
|
||||
# CHECK-NEXT: $x12 = LDRXui $x9, target-flags(aarch64-pageoff, aarch64-got) @x
|
||||
|
||||
# CHECK: name: OUTLINED_FUNCTION_[[F2]]
|
||||
# CHECK-DAG: bb.0
|
||||
# CHECK: $w12 = ORRWri $wzr, 1
|
||||
# CHECK-NEXT: $x9 = ADRP target-flags(aarch64-page, aarch64-got) @x
|
||||
# CHECK-NEXT: $x12 = ADDXri $x9, target-flags(aarch64-pageoff, aarch64-got) @x, 0
|
||||
Loading…
x
Reference in New Issue
Block a user