[llvm] [CodeGen] Do not emit TRAP for `unreachable` after `@llvm.trap` (PR #94570)
Igor Kudrin via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 5 22:13:43 PDT 2024
https://github.com/igorkudrin created https://github.com/llvm/llvm-project/pull/94570
With `--trap-unreachable`, `clang` can emit double `TRAP` instructions for code that contains a call to `__builtin_trap()`:
```
> cat test.c
void test() { __builtin_trap(); }
> clang test.c --target=x86_64 -mllvm --trap-unreachable -O1 -S -o -
...
test:
...
ud2
ud2
...
```
`SimplifyCFGPass` inserts `unreachable` after a call to a `noreturn` function, and later this instruction causes `TRAP/G_TRAP` to be emitted in `SelectionDAGBuilder::visitUnreachable()` or
`IRTranslator::translateUnreachable()` if `TargetOptions.TrapUnreachable` is set.
The patch checks the instruction before `unreachable` and avoids inserting an additional trap.
>From 8e02e3fd613fbbe39d68899a8d953daaa4fc0882 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Wed, 5 Jun 2024 15:18:31 -0700
Subject: [PATCH] [CodeGen] Do not emit TRAP for `unreachable` after
`@llvm.trap`
With `--trap-unreachable`, `clang` can emit double `TRAP` instructions
for code that contains a call to `__builtin_trap()`:
```
> cat test.c
void test() { __builtin_trap(); }
> clang test.c --target=x86_64 -mllvm --trap-unreachable -O1 -S -o -
...
test:
...
ud2
ud2
...
```
`SimplifyCFGPass` inserts `unreachable` after a call to a `noreturn`
function, and later this instruction causes `TRAP/G_TRAP` to be emitted
in `SelectionDAGBuilder::visitUnreachable()` or
`IRTranslator::translateUnreachable()` if `TargetOptions.TrapUnreachable`
is set.
The patch checks the instruction before `unreachable` and avoids
inserting an additional trap.
---
llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp | 20 ++++++-------
.../SelectionDAG/SelectionDAGBuilder.cpp | 14 +++++----
llvm/test/CodeGen/X86/trap.ll | 30 ++++++-------------
llvm/test/CodeGen/X86/unreachable-trap.ll | 16 ++++++++--
llvm/test/LTO/X86/unified-cfi.ll | 1 -
5 files changed, 42 insertions(+), 39 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index 25b14c860284d..a9b43f03ee95c 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -3076,17 +3076,17 @@ bool IRTranslator::translateUnreachable(const User &U, MachineIRBuilder &MIRBuil
return true;
auto &UI = cast<UnreachableInst>(U);
+
// We may be able to ignore unreachable behind a noreturn call.
- if (MF->getTarget().Options.NoTrapAfterNoreturn) {
- const BasicBlock &BB = *UI.getParent();
- if (&UI != &BB.front()) {
- BasicBlock::const_iterator PredI =
- std::prev(BasicBlock::const_iterator(UI));
- if (const CallInst *Call = dyn_cast<CallInst>(&*PredI)) {
- if (Call->doesNotReturn())
- return true;
- }
- }
+ if (const CallInst *Call = dyn_cast_or_null<CallInst>(UI.getPrevNode());
+ Call && Call->doesNotReturn()) {
+ if (MF->getTarget().Options.NoTrapAfterNoreturn)
+ return true;
+ // Do not emit an additional trap instruction.
+ if (Function *F = Call->getCalledFunction();
+ F && F->getIntrinsicID() == Intrinsic::trap &&
+ !Call->hasFnAttr("trap-func-name"))
+ return true;
}
MIRBuilder.buildTrap();
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 64d6fd458c62f..f63eade302af3 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -3526,11 +3526,15 @@ void SelectionDAGBuilder::visitUnreachable(const UnreachableInst &I) {
return;
// We may be able to ignore unreachable behind a noreturn call.
- if (DAG.getTarget().Options.NoTrapAfterNoreturn) {
- if (const CallInst *Call = dyn_cast_or_null<CallInst>(I.getPrevNode())) {
- if (Call->doesNotReturn())
- return;
- }
+ if (const CallInst *Call = dyn_cast_or_null<CallInst>(I.getPrevNode());
+ Call && Call->doesNotReturn()) {
+ if (DAG.getTarget().Options.NoTrapAfterNoreturn)
+ return;
+ // Do not emit an additional trap instruction.
+ if (Function *F = Call->getCalledFunction();
+ F && F->getIntrinsicID() == Intrinsic::trap &&
+ !Call->hasFnAttr("trap-func-name"))
+ return;
}
DAG.setRoot(DAG.getNode(ISD::TRAP, getCurSDLoc(), MVT::Other, DAG.getRoot()));
diff --git a/llvm/test/CodeGen/X86/trap.ll b/llvm/test/CodeGen/X86/trap.ll
index 1b1837a7c5a7a..3d9a858beda85 100644
--- a/llvm/test/CodeGen/X86/trap.ll
+++ b/llvm/test/CodeGen/X86/trap.ll
@@ -1,33 +1,22 @@
-; RUN: llc < %s -mtriple=i686-apple-darwin8 -mcpu=yonah | FileCheck %s -check-prefix=DARWIN
-; RUN: llc < %s -mtriple=i686-unknown-linux -mcpu=yonah | FileCheck %s -check-prefix=LINUX
-; RUN: llc < %s -mtriple=x86_64-scei-ps4 | FileCheck %s -check-prefix=PS4
-; RUN: llc < %s -mtriple=x86_64-sie-ps5 | FileCheck %s -check-prefix=PS4
-; RUN: llc < %s -mtriple=x86_64-windows-msvc | FileCheck %s -check-prefix=WIN64
+; RUN: llc < %s -mtriple=i686-apple-darwin8 -mcpu=yonah | FileCheck %s -check-prefixes=CHECK,DARWIN
+; RUN: llc < %s -mtriple=i686-unknown-linux -mcpu=yonah | FileCheck %s -check-prefixes=CHECK,LINUX
+; RUN: llc < %s -mtriple=x86_64-scei-ps4 | FileCheck %s -check-prefixes=CHECK,PS4
+; RUN: llc < %s -mtriple=x86_64-sie-ps5 | FileCheck %s -check-prefixes=CHECK,PS4
+; RUN: llc < %s -mtriple=x86_64-windows-msvc | FileCheck %s -check-prefixes=CHECK,WIN64
-; DARWIN-LABEL: test0:
-; DARWIN: ud2
-; LINUX-LABEL: test0:
-; LINUX: ud2
-; FIXME: PS4 probably doesn't want two ud2s.
-; PS4-LABEL: test0:
-; PS4: ud2
-; PS4: ud2
-; WIN64-LABEL: test0:
-; WIN64: ud2
-; WIN64-NOT: ud2
+; CHECK-LABEL: test0:
+; CHECK: ud2
+; CHECK-NOT: ud2
define i32 @test0() noreturn nounwind {
entry:
tail call void @llvm.trap( )
unreachable
}
-; DARWIN-LABEL: test1:
+; CHECK-LABEL: test1:
; DARWIN: int3
-; LINUX-LABEL: test1:
; LINUX: int3
-; PS4-LABEL: test1:
; PS4: int $65
-; WIN64-LABEL: test1:
; WIN64: int3
; WIN64-NOT: ud2
define i32 @test1() noreturn nounwind {
@@ -38,4 +27,3 @@ entry:
declare void @llvm.trap() nounwind
declare void @llvm.debugtrap() nounwind
-
diff --git a/llvm/test/CodeGen/X86/unreachable-trap.ll b/llvm/test/CodeGen/X86/unreachable-trap.ll
index ee1a11c767784..d1eeab594b5b7 100644
--- a/llvm/test/CodeGen/X86/unreachable-trap.ll
+++ b/llvm/test/CodeGen/X86/unreachable-trap.ll
@@ -2,6 +2,8 @@
; RUN: llc -o - %s -mtriple=x86_64-windows-msvc | FileCheck %s --check-prefixes=CHECK,NORMAL
; RUN: llc -o - %s -mtriple=x86_64-scei-ps4 | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
; RUN: llc -o - %s -mtriple=x86_64-apple-darwin | FileCheck %s --check-prefixes=CHECK,NO_TRAP_AFTER_NORETURN
+; RUN: llc --trap-unreachable -o - %s -mtriple=x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
+; RUN: llc --trap-unreachable -global-isel -o - %s -mtriple=x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
; CHECK-LABEL: call_exit:
; CHECK: callq {{_?}}exit
@@ -15,11 +17,19 @@ define i32 @call_exit() noreturn nounwind {
; CHECK-LABEL: trap:
; CHECK: ud2
+; CHECK-NOT: ud2
+define i32 @trap() noreturn nounwind {
+ tail call void @llvm.trap()
+ unreachable
+}
+
+; CHECK-LABEL: trap_fn_attr:
+; CHECK: callq {{_?}}trap_func
; TRAP_AFTER_NORETURN: ud2
; NO_TRAP_AFTER_NORETURN-NOT: ud2
; NORMAL-NOT: ud2
-define i32 @trap() noreturn nounwind {
- tail call void @llvm.trap()
+define i32 @trap_fn_attr() noreturn nounwind {
+ tail call void @llvm.trap() #0
unreachable
}
@@ -34,3 +44,5 @@ define i32 @unreachable() noreturn nounwind {
declare void @llvm.trap() nounwind noreturn
declare void @exit(i32 %rc) nounwind noreturn
+
+attributes #0 = { "trap-func-name"="trap_func" }
diff --git a/llvm/test/LTO/X86/unified-cfi.ll b/llvm/test/LTO/X86/unified-cfi.ll
index f404136ca35f1..47dbe2b9f292a 100644
--- a/llvm/test/LTO/X86/unified-cfi.ll
+++ b/llvm/test/LTO/X86/unified-cfi.ll
@@ -6,7 +6,6 @@
; CHECK: jbe
; CHECK-NEXT: ud2
-; CHECK-NEXT: ud2
; ModuleID = 'llvm/test/LTO/X86/unified-cfi.ll'
source_filename = "cfi.cpp"
More information about the llvm-commits
mailing list