Skip to content

Commit eac3e5c

Browse files
Joao Moreiranickdesaulniers
authored andcommitted
[X86] Do not emit JCC to __x86_indirect_thunk
Clang may optimize conditional tailcall blocks with the following layout: cmp <condition> je tailcall_target ret When retpoline is in place, indirect calls are converted into direct calls to a retpoline thunk. When these indirect calls are tail calls, they may be subject to the above described optimization (there is no indirect JCC, but since now the jump is direct it can be made conditional). The above layout is non-ideal for the Linux kernel scenario because the branches into thunks may be patched back into indirect branches during runtime depending on the underlying CPU features, what would not be feasible if the binary is emitted with the optimized layout above. Thus, prevent clang from emitting this it if CodeModel is Kernel. Feature request from the respective kernel mailing list: https://lore.kernel.org/llvm/Yv3uI%[email protected]/ Reviewed By: nickdesaulniers, pengfei Differential Revision: https://reviews.llvm.org/D134915
1 parent dc2b8fb commit eac3e5c

File tree

2 files changed

+46
-1
lines changed

2 files changed

+46
-1
lines changed

llvm/lib/Target/X86/X86InstrInfo.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2942,13 +2942,26 @@ bool X86InstrInfo::isUnconditionalTailCall(const MachineInstr &MI) const {
29422942
bool X86InstrInfo::canMakeTailCallConditional(
29432943
SmallVectorImpl<MachineOperand> &BranchCond,
29442944
const MachineInstr &TailCall) const {
2945+
2946+
const MachineFunction *MF = TailCall.getMF();
2947+
2948+
if (MF->getTarget().getCodeModel() == CodeModel::Kernel) {
2949+
// Kernel patches thunk calls in runtime, these should never be conditional.
2950+
const MachineOperand &Target = TailCall.getOperand(0);
2951+
if (Target.isSymbol()) {
2952+
StringRef Symbol(Target.getSymbolName());
2953+
// this is currently only relevant to r11/kernel indirect thunk.
2954+
if (Symbol.equals("__x86_indirect_thunk_r11"))
2955+
return false;
2956+
}
2957+
}
2958+
29452959
if (TailCall.getOpcode() != X86::TCRETURNdi &&
29462960
TailCall.getOpcode() != X86::TCRETURNdi64) {
29472961
// Only direct calls can be done with a conditional branch.
29482962
return false;
29492963
}
29502964

2951-
const MachineFunction *MF = TailCall.getParent()->getParent();
29522965
if (Subtarget.isTargetWin64() && MF->hasWinCFI()) {
29532966
// Conditional tail calls confuse the Win64 unwinder.
29542967
return false;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
; RUN: llc < %s -O2 --code-model=kernel | FileCheck %s
2+
; The intent of the test is that we do not generate conditional
3+
; tail calls to the thunk.
4+
5+
target triple = "x86_64-unknown-linux-gnu"
6+
7+
define dso_local void @foo(ptr %something) #0 {
8+
; CHECK-LABEL: foo:
9+
; CHECK: # %bb.0: # %entry
10+
; CHECK-NEXT: movq (%rdi), %r11
11+
; CHECK-NEXT: testq %r11, %r11
12+
; Make sure that a JNE was not generated instead of a JE + JMP sequence
13+
; CHECK-NOT: jne
14+
; CHECK-NEXT: je .LBB0_1
15+
; CHECK-NEXT: bb.2: # %if.then
16+
; CHECK-NEXT: jmp __x86_indirect_thunk_r11
17+
; CHECK-NEXT: LBB0_1:
18+
; CHECK-NEXT: retq
19+
entry:
20+
%0 = load ptr, ptr %something, align 8
21+
%tobool.not = icmp eq ptr %0, null
22+
br i1 %tobool.not, label %if.end, label %if.then
23+
24+
if.then:
25+
tail call void %0()
26+
br label %if.end
27+
28+
if.end:
29+
ret void
30+
}
31+
32+
attributes #0 = { optsize "target-features"="+retpoline-external-thunk" }

0 commit comments

Comments
 (0)