[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