[llvm] [xray] Do not emit tail exit hooks for conditional tail calls (PR #89364)
Ricky Zhou via llvm-commits
llvm-commits at lists.llvm.org
Fri Apr 19 17:14:56 PDT 2024
https://github.com/rickyz updated https://github.com/llvm/llvm-project/pull/89364
>From 64111efcdced53246013c5d3343cd3aadedc08db Mon Sep 17 00:00:00 2001
From: Ricky Zhou <ricky at rzhou.org>
Date: Fri, 19 Apr 2024 02:44:07 -0700
Subject: [PATCH] [xray] Handle conditional calls when lowering patchable tail
calls.
xray instruments tail call function exits by inserting a nop sled before
the tail call. When tracing is enabled, the nop sled is replaced with a
call to `__xray_FunctionTailExit()`. This currently does not work for
conditional tail calls, as the instrumentation assumes that the tail
call will be unconditional. This causes two issues:
- `__xray_FunctionTailExit()` is inappropately called even when the
tail call is not taken.
- `__xray_FunctionTailExit()`'s prologue/epilogue adjusts the stack
pointer with add/sub instructions. This clobbers condition flags,
which can flip the condition used for the tail call, leading to
incorrect program behavior.
Fix this by rewriting conditional tail calls, when lowering patchable
tail calls.
With this change, a conditional tail call like:
```
je target
```
Will be lowered to:
```
jne .fallthrough
.p2align 1, ..
.Lxray_sled_N:
SLED_CODE
jmp target
.fallthrough:
```
---
llvm/lib/Target/X86/X86MCInstLower.cpp | 41 ++++++++++++++++---
.../CodeGen/X86/xray-conditional-tail-call.ll | 35 ++++++++++++++++
2 files changed, 70 insertions(+), 6 deletions(-)
create mode 100644 llvm/test/CodeGen/X86/xray-conditional-tail-call.ll
diff --git a/llvm/lib/Target/X86/X86MCInstLower.cpp b/llvm/lib/Target/X86/X86MCInstLower.cpp
index e6510be6b9afd0..705c1b3ea45206 100644
--- a/llvm/lib/Target/X86/X86MCInstLower.cpp
+++ b/llvm/lib/Target/X86/X86MCInstLower.cpp
@@ -22,6 +22,7 @@
#include "X86RegisterInfo.h"
#include "X86ShuffleDecodeConstantPool.h"
#include "X86Subtarget.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/CodeGen/MachineConstantPool.h"
@@ -1361,6 +1362,31 @@ void X86AsmPrinter::LowerPATCHABLE_RET(const MachineInstr &MI,
void X86AsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI,
X86MCInstLower &MCIL) {
+ MCInst TC;
+ TC.setOpcode(convertTailJumpOpcode(MI.getOperand(0).getImm()));
+ bool IsConditional = TC.getOpcode() == X86::JCC_1;
+ MCSymbol *FallthroughLabel;
+ if (IsConditional) {
+ // Rewrite:
+ // je target
+ //
+ // To:
+ // jne .fallthrough
+ // .p2align 1, ...
+ // .Lxray_sled_N:
+ // SLED_CODE
+ // jmp target
+ // .fallthrough:
+ FallthroughLabel = OutContext.createTempSymbol();
+ EmitToStreamer(
+ *OutStreamer,
+ MCInstBuilder(X86::JCC_1)
+ .addExpr(MCSymbolRefExpr::create(FallthroughLabel, OutContext))
+ .addImm(X86::GetOppositeBranchCondition(
+ static_cast<X86::CondCode>(MI.getOperand(2).getImm()))));
+ TC.setOpcode(X86::JMP_1);
+ }
+
NoAutoPaddingScope NoPadScope(*OutStreamer);
// Like PATCHABLE_RET, we have the actual instruction in the operands to this
@@ -1382,18 +1408,21 @@ void X86AsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI,
OutStreamer->emitLabel(Target);
recordSled(CurSled, MI, SledKind::TAIL_CALL, 2);
- unsigned OpCode = MI.getOperand(0).getImm();
- OpCode = convertTailJumpOpcode(OpCode);
- MCInst TC;
- TC.setOpcode(OpCode);
-
// Before emitting the instruction, add a comment to indicate that this is
// indeed a tail call.
OutStreamer->AddComment("TAILCALL");
- for (auto &MO : drop_begin(MI.operands()))
+ auto TCOperands = drop_begin(MI.operands());
+ if (IsConditional) {
+ // Drop condition code.
+ TCOperands = drop_end(TCOperands);
+ }
+ for (auto &MO : TCOperands)
if (auto MaybeOperand = MCIL.LowerMachineOperand(&MI, MO))
TC.addOperand(*MaybeOperand);
OutStreamer->emitInstruction(TC, getSubtargetInfo());
+
+ if (IsConditional)
+ OutStreamer->emitLabel(FallthroughLabel);
}
// Returns instruction preceding MBBI in MachineFunction.
diff --git a/llvm/test/CodeGen/X86/xray-conditional-tail-call.ll b/llvm/test/CodeGen/X86/xray-conditional-tail-call.ll
new file mode 100644
index 00000000000000..9ceea75ca769e0
--- /dev/null
+++ b/llvm/test/CodeGen/X86/xray-conditional-tail-call.ll
@@ -0,0 +1,35 @@
+; RUN: llc -mtriple=x86_64 < %s | FileCheck %s
+
+declare void @tail_call_target()
+
+define void @conditional_tail_call(i32 %cond) "function-instrument"="xray-always" nounwind {
+ ; CHECK-LABEL: conditional_tail_call:
+ ; CHECK-NEXT: .Lfunc_begin0:
+ ; CHECK-NEXT: # %bb.0:
+ ; CHECK-NEXT: .p2align 1, 0x90
+ ; CHECK-NEXT: .Lxray_sled_0:
+ ; CHECK-NEXT: .ascii "\353\t"
+ ; CHECK-NEXT: nopw 512(%rax,%rax)
+ ; CHECK-NEXT: testl %edi, %edi
+ ; CHECK-NEXT: je .Ltmp0
+ ; CHECK-NEXT: .p2align 1, 0x90
+ ; CHECK-NEXT: .Lxray_sled_1:
+ ; CHECK-NEXT: .ascii "\353\t"
+ ; CHECK-NEXT: nopw 512(%rax,%rax)
+ ; CHECK-NEXT: .Ltmp1:
+ ; CHECK-NEXT: jmp tail_call_target at PLT # TAILCALL
+ ; CHECK-NEXT: .Ltmp0:
+ ; CHECK-NEXT: # %bb.1:
+ ; CHECK-NEXT: .p2align 1, 0x90
+ ; CHECK-NEXT: .Lxray_sled_2:
+ ; CHECK-NEXT: retq
+ ; CHECK-NEXT: nopw %cs:512(%rax,%rax)
+ ; CHECK-NEXT: .Lfunc_end0:
+ %cmp = icmp ne i32 %cond, 0
+ br i1 %cmp, label %docall, label %ret
+docall:
+ tail call void @tail_call_target()
+ ret void
+ret:
+ ret void
+}
More information about the llvm-commits
mailing list