Skip to content

Commit 5d6d743

Browse files
authored
[BOLT][BTI] Skip inlining BasicBlocks containing indirect tailcalls (#168403)
In the Inliner pass, tailcalls are converted to calls in the inlined BasicBlock. If the tailcall is indirect, the `BR` is converted to `BLR`. These instructions require different BTI landing pads at their targets. As the targets of indirect tailcalls are unknown, inlining such blocks is unsound for BTI: they should be skipped instead.
1 parent 25d027b commit 5d6d743

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-0
lines changed

bolt/lib/Passes/Inliner.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,32 @@ bool Inliner::inlineCallsInFunction(BinaryFunction &Function) {
491491
}
492492
}
493493

494+
// AArch64 BTI:
495+
// If the callee has an indirect tailcall (BR), we would transform it to
496+
// an indirect call (BLR) in InlineCall. Because of this, we would have to
497+
// update the BTI at the target of the tailcall. However, these targets
498+
// are not known. Instead, we skip inlining blocks with indirect
499+
// tailcalls.
500+
auto HasIndirectTailCall = [&](const BinaryFunction &BF) -> bool {
501+
for (const auto &BB : BF) {
502+
for (const auto &II : BB) {
503+
if (BC.MIB->isIndirectBranch(II) && BC.MIB->isTailCall(II)) {
504+
return true;
505+
}
506+
}
507+
}
508+
return false;
509+
};
510+
511+
if (BC.isAArch64() && BC.usesBTI() &&
512+
HasIndirectTailCall(*TargetFunction)) {
513+
++InstIt;
514+
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: Skipping inlining block with tailcall"
515+
<< " in " << Function << " : " << BB->getName()
516+
<< " to keep BTIs consistent.\n");
517+
continue;
518+
}
519+
494520
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: inlining call to " << *TargetFunction
495521
<< " in " << Function << " : " << BB->getName()
496522
<< ". Count: " << BB->getKnownExecutionCount()

bolt/test/AArch64/inline-bti.s

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
## This test checks that for AArch64 binaries with BTI, we do not inline blocks with indirect tailcalls.
2+
3+
# REQUIRES: system-linux
4+
5+
# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o
6+
# RUN: %clang %cflags -O0 %t.o -o %t.exe -Wl,-q -Wl,-z,force-bti
7+
# RUN: llvm-bolt --inline-all %t.exe -o %t.bolt --debug 2>&1 | FileCheck %s
8+
9+
# For BTI, we should not inline foo.
10+
# CHECK: BOLT-DEBUG: Skipping inlining block with tailcall in _Z3barP1A : .LBB01 to keep BTIs consistent.
11+
# CHECK-NOT: BOLT-INFO: inlined {{[0-9]+}} calls at {{[0-9]+}} call sites in {{[0-9]+}} iteration(s). Change in binary size: {{[0-9]+}} bytes.
12+
13+
.text
14+
.globl _Z3fooP1A
15+
.type _Z3fooP1A,@function
16+
_Z3fooP1A:
17+
ldr x8, [x0]
18+
ldr w0, [x8]
19+
br x30
20+
.size _Z3fooP1A, .-_Z3fooP1A
21+
22+
.globl _Z3barP1A
23+
.type _Z3barP1A,@function
24+
_Z3barP1A:
25+
stp x29, x30, [sp, #-16]!
26+
mov x29, sp
27+
bl _Z3fooP1A
28+
mul w0, w0, w0
29+
ldp x29, x30, [sp], #16
30+
ret
31+
.size _Z3barP1A, .-_Z3barP1A
32+
33+
.globl main
34+
.p2align 2
35+
.type main,@function
36+
main:
37+
mov w0, wzr
38+
ret
39+
.size main, .-main

0 commit comments

Comments
 (0)