[llvm] [CodeExtractor] Reject regions with terminating deoptimize (PR #204560)

Arda Serdar Pektezol via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 25 07:22:58 PDT 2026


https://github.com/pektezol updated https://github.com/llvm/llvm-project/pull/204560

>From 4bb6fe6ed5198a9216d435fda0243520fb496e59 Mon Sep 17 00:00:00 2001
From: Arda Serdar Pektezol <arda at pektezol.dev>
Date: Thu, 18 Jun 2026 14:17:51 +0300
Subject: [PATCH 1/3] [CodeExtractor] reject regions with terminating
 deoptimize

---
 llvm/lib/Transforms/Utils/CodeExtractor.cpp   |  2 +
 llvm/test/Transforms/HotColdSplit/pr192014.ll | 46 +++++++++++++++++++
 2 files changed, 48 insertions(+)
 create mode 100644 llvm/test/Transforms/HotColdSplit/pr192014.ll

diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
index 7ffa99878cf74..2741c3d86bb18 100644
--- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp
+++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
@@ -679,6 +679,8 @@ bool CodeExtractor::isEligible() const {
         return false;
       if (IsRestore && !definedInRegion(Blocks, II->getArgOperand(0)))
         return false;
+      if (BB->getTerminatingDeoptimizeCall())
+        return false;
     }
   }
   return true;
diff --git a/llvm/test/Transforms/HotColdSplit/pr192014.ll b/llvm/test/Transforms/HotColdSplit/pr192014.ll
new file mode 100644
index 0000000000000..aa3a56c7b4076
--- /dev/null
+++ b/llvm/test/Transforms/HotColdSplit/pr192014.ll
@@ -0,0 +1,46 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=hotcoldsplit -S < %s | FileCheck %s
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define i64 @combined_bridge() {
+; CHECK-LABEL: define i64 @combined_bridge() {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    br i1 false, label %[[LOOP_I:.*]], label %[[FAILED_I:.*]], !prof [[PROF0:![0-9]+]]
+; CHECK:       [[LOOP_I]]:
+; CHECK-NEXT:    br i1 false, label %[[GUARDED1_I:.*]], label %[[DEOPT2_I:.*]]
+; CHECK:       [[DEOPT2_I]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = call i64 (...) @llvm.experimental.deoptimize.i64() [ "deopt"() ]
+; CHECK-NEXT:    ret i64 [[TMP0]]
+; CHECK:       [[GUARDED1_I]]:
+; CHECK-NEXT:    [[IV_NEXT_I147:%.*]] = add i32 0, 0
+; CHECK-NEXT:    [[LOOP_COND_I148:%.*]] = icmp ult i32 0, 0
+; CHECK-NEXT:    ret i64 0
+; CHECK:       [[FAILED_I]]:
+; CHECK-NEXT:    ret i64 0
+;
+entry:
+  br i1 false, label %loop.i, label %failed.i, !prof !0
+
+loop.i:                                           ; preds = %entry
+  br i1 false, label %guarded1.i, label %deopt2.i
+
+deopt2.i:                                         ; preds = %loop.i
+  %0 = call i64 (...) @llvm.experimental.deoptimize.i64() [ "deopt"() ]
+  ret i64 %0
+
+guarded1.i:                                       ; preds = %loop.i
+  %iv.next.i147 = add i32 0, 0
+  %loop.cond.i148 = icmp ult i32 0, 0
+  ret i64 0
+
+failed.i:                                         ; preds = %entry
+  ret i64 0
+}
+
+declare i64 @llvm.experimental.deoptimize.i64(...)
+
+!0 = !{!"branch_weights", i32 1, i32 1000}
+;.
+; CHECK: [[PROF0]] = !{!"branch_weights", i32 1, i32 1000}
+;.

>From 0ede09c88f152eb3bdca06df10205de9394cc004 Mon Sep 17 00:00:00 2001
From: Arda Serdar Pektezol <arda at pektezol.dev>
Date: Fri, 19 Jun 2026 13:29:44 +0300
Subject: [PATCH 2/3] move check to isBlockValidForExtraction

---
 llvm/lib/Transforms/Utils/CodeExtractor.cpp | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
index 2741c3d86bb18..abe0338bc7bea 100644
--- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp
+++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
@@ -164,6 +164,12 @@ static bool isBlockValidForExtraction(const BasicBlock &BB,
       continue;
     }
 
+    // llvm.experimental.deoptimize must return the enclosing function's return
+    // type. Extraction changes the outlined function signature, which can make
+    // the deoptimize call invalid.
+    if (BB.getTerminatingDeoptimizeCall())
+      return false;
+
     if (const CallInst *CI = dyn_cast<CallInst>(I)) {
       // musttail calls have several restrictions, generally enforcing matching
       // calling conventions between the caller parent and musttail callee.
@@ -679,8 +685,6 @@ bool CodeExtractor::isEligible() const {
         return false;
       if (IsRestore && !definedInRegion(Blocks, II->getArgOperand(0)))
         return false;
-      if (BB->getTerminatingDeoptimizeCall())
-        return false;
     }
   }
   return true;

>From 7bb082d096ec36e02c7c1d064c17e625bec6db2c Mon Sep 17 00:00:00 2001
From: Arda Serdar Pektezol <arda at pektezol.dev>
Date: Tue, 25 Aug 2026 17:22:39 +0300
Subject: [PATCH 3/3] simplify test case

---
 llvm/test/Transforms/HotColdSplit/pr192014.ll | 34 +++++++++----------
 1 file changed, 16 insertions(+), 18 deletions(-)

diff --git a/llvm/test/Transforms/HotColdSplit/pr192014.ll b/llvm/test/Transforms/HotColdSplit/pr192014.ll
index aa3a56c7b4076..050899f84a2f2 100644
--- a/llvm/test/Transforms/HotColdSplit/pr192014.ll
+++ b/llvm/test/Transforms/HotColdSplit/pr192014.ll
@@ -1,40 +1,38 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
 ; RUN: opt -passes=hotcoldsplit -S < %s | FileCheck %s
-target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-linux-gnu"
 
 define i64 @combined_bridge() {
 ; CHECK-LABEL: define i64 @combined_bridge() {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    br i1 false, label %[[LOOP_I:.*]], label %[[FAILED_I:.*]], !prof [[PROF0:![0-9]+]]
-; CHECK:       [[LOOP_I]]:
-; CHECK-NEXT:    br i1 false, label %[[GUARDED1_I:.*]], label %[[DEOPT2_I:.*]]
-; CHECK:       [[DEOPT2_I]]:
+; CHECK-NEXT:    br i1 false, label %[[LOOP:.*]], label %[[FAILED:.*]], !prof [[PROF0:![0-9]+]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    br i1 false, label %[[GUARDED:.*]], label %[[DEOPT:.*]]
+; CHECK:       [[DEOPT]]:
 ; CHECK-NEXT:    [[TMP0:%.*]] = call i64 (...) @llvm.experimental.deoptimize.i64() [ "deopt"() ]
 ; CHECK-NEXT:    ret i64 [[TMP0]]
-; CHECK:       [[GUARDED1_I]]:
-; CHECK-NEXT:    [[IV_NEXT_I147:%.*]] = add i32 0, 0
-; CHECK-NEXT:    [[LOOP_COND_I148:%.*]] = icmp ult i32 0, 0
+; CHECK:       [[GUARDED]]:
+; CHECK-NEXT:    [[I:%.*]] = add i32 0, 0
+; CHECK-NEXT:    [[J:%.*]] = icmp ult i32 0, 0
 ; CHECK-NEXT:    ret i64 0
-; CHECK:       [[FAILED_I]]:
+; CHECK:       [[FAILED]]:
 ; CHECK-NEXT:    ret i64 0
 ;
 entry:
-  br i1 false, label %loop.i, label %failed.i, !prof !0
+  br i1 false, label %loop, label %failed, !prof !0
 
-loop.i:                                           ; preds = %entry
-  br i1 false, label %guarded1.i, label %deopt2.i
+loop:                                           ; preds = %entry
+  br i1 false, label %guarded, label %deopt
 
-deopt2.i:                                         ; preds = %loop.i
+deopt:                                         ; preds = %loop
   %0 = call i64 (...) @llvm.experimental.deoptimize.i64() [ "deopt"() ]
   ret i64 %0
 
-guarded1.i:                                       ; preds = %loop.i
-  %iv.next.i147 = add i32 0, 0
-  %loop.cond.i148 = icmp ult i32 0, 0
+guarded:                                       ; preds = %loop
+  %i = add i32 0, 0
+  %j = icmp ult i32 0, 0
   ret i64 0
 
-failed.i:                                         ; preds = %entry
+failed:                                         ; preds = %entry
   ret i64 0
 }
 



More information about the llvm-commits mailing list