[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