[llvm] b89551b - [SimplifyCFG] Check every sinking candidate in canSinkInstructions (#217372)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 19 11:58:54 PDT 2026
Author: Florian Hahn
Date: 2026-08-19T19:58:50+01:00
New Revision: b89551b079ae57cfb00baae16881e22310ae342a
URL: https://github.com/llvm/llvm-project/commit/b89551b079ae57cfb00baae16881e22310ae342a
DIFF: https://github.com/llvm/llvm-project/commit/b89551b079ae57cfb00baae16881e22310ae342a.diff
LOG: [SimplifyCFG] Check every sinking candidate in canSinkInstructions (#217372)
canReplaceOperandWithVariable() can depend on the operand value (e.g. if
the operand of only some instructions is a swifterror value, or a
constant operand for an operand bundle). Check operands of all
instructions to sink.
Fixes verifier errors after sinking the swifterror examples.
PR: https://github.com/llvm/llvm-project/pull/217372
Added:
llvm/test/Transforms/SimplifyCFG/constant-bundle-operand.ll
Modified:
llvm/lib/Transforms/Utils/SimplifyCFG.cpp
llvm/test/Transforms/SimplifyCFG/hoist-sink-swifterror-store.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 089892dc573f3..2f9a4819f9984 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -2303,9 +2303,12 @@ static bool canSinkInstructions(
return I->getOperand(OI) == I0->getOperand(OI);
};
if (!all_of(Insts, SameAsI0)) {
+ auto CanReplaceOperand = [OI](const Instruction *I) {
+ return canReplaceOperandWithVariable(I, OI);
+ };
if ((isa<Constant>(Op) && !replacingOperandWithVariableIsCheap(I0, OI)) ||
- !canReplaceOperandWithVariable(I0, OI))
- // We can't create a PHI from this GEP.
+ !all_of(Insts, CanReplaceOperand))
+ // We can't create a PHI from this operand.
return false;
auto &Ops = PHIOperands[&I0->getOperandUse(OI)];
for (auto *I : Insts)
diff --git a/llvm/test/Transforms/SimplifyCFG/constant-bundle-operand.ll b/llvm/test/Transforms/SimplifyCFG/constant-bundle-operand.ll
new file mode 100644
index 0000000000000..ec068358099a9
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/constant-bundle-operand.ll
@@ -0,0 +1,110 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes='simplifycfg<sink-common-insts>,verify' -S %s | FileCheck %s
+
+declare void @clobber1()
+declare void @clobber2()
+declare void @f()
+
+; Both bundle operands are variable, so the calls can be sunk and the bundle
+; operand merged by a PHI.
+define void @sink_variable_bundle_operands(i1 %c, i32 %a, i32 %b) {
+; CHECK-LABEL: define void @sink_variable_bundle_operands(
+; CHECK-SAME: i1 [[C:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[BB:.*:]]
+; CHECK-NEXT: br i1 [[C]], label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK: [[THEN]]:
+; CHECK-NEXT: call void @clobber1()
+; CHECK-NEXT: br label %[[EXIT:.*]]
+; CHECK: [[ELSE]]:
+; CHECK-NEXT: call void @clobber2()
+; CHECK-NEXT: br label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: [[B_SINK:%.*]] = phi i32 [ [[B]], %[[ELSE]] ], [ [[A]], %[[THEN]] ]
+; CHECK-NEXT: call void @f() [ "deopt"(i32 [[B_SINK]]) ]
+; CHECK-NEXT: ret void
+;
+bb:
+ br i1 %c, label %then, label %else
+
+then:
+ call void @clobber1()
+ call void @f() [ "deopt"(i32 %a) ]
+ br label %exit
+
+else:
+ call void @clobber2()
+ call void @f() [ "deopt"(i32 %b) ]
+ br label %exit
+
+exit:
+ ret void
+}
+
+; The bundle operand of the call in %then is constant, so the calls must not be
+; sunk.
+define void @no_sink_constant_bundle_operand_in_then(i1 %c, i32 %b) {
+; CHECK-LABEL: define void @no_sink_constant_bundle_operand_in_then(
+; CHECK-SAME: i1 [[C:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[BB:.*:]]
+; CHECK-NEXT: br i1 [[C]], label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK: [[THEN]]:
+; CHECK-NEXT: call void @clobber1()
+; CHECK-NEXT: call void @f() [ "deopt"(i32 7) ]
+; CHECK-NEXT: br label %[[EXIT:.*]]
+; CHECK: [[ELSE]]:
+; CHECK-NEXT: call void @clobber2()
+; CHECK-NEXT: call void @f() [ "deopt"(i32 [[B]]) ]
+; CHECK-NEXT: br label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
+bb:
+ br i1 %c, label %then, label %else
+
+then:
+ call void @clobber1()
+ call void @f() [ "deopt"(i32 7) ]
+ br label %exit
+
+else:
+ call void @clobber2()
+ call void @f() [ "deopt"(i32 %b) ]
+ br label %exit
+
+exit:
+ ret void
+}
+
+; Same as above, with the constant bundle operand in the other predecessor.
+define void @no_sink_constant_bundle_operand_in_else(i1 %c, i32 %b) {
+; CHECK-LABEL: define void @no_sink_constant_bundle_operand_in_else(
+; CHECK-SAME: i1 [[C:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[BB:.*:]]
+; CHECK-NEXT: br i1 [[C]], label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK: [[THEN]]:
+; CHECK-NEXT: call void @clobber1()
+; CHECK-NEXT: call void @f() [ "deopt"(i32 [[B]]) ]
+; CHECK-NEXT: br label %[[EXIT:.*]]
+; CHECK: [[ELSE]]:
+; CHECK-NEXT: call void @clobber2()
+; CHECK-NEXT: call void @f() [ "deopt"(i32 7) ]
+; CHECK-NEXT: br label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
+bb:
+ br i1 %c, label %then, label %else
+
+then:
+ call void @clobber1()
+ call void @f() [ "deopt"(i32 %b) ]
+ br label %exit
+
+else:
+ call void @clobber2()
+ call void @f() [ "deopt"(i32 7) ]
+ br label %exit
+
+exit:
+ ret void
+}
diff --git a/llvm/test/Transforms/SimplifyCFG/hoist-sink-swifterror-store.ll b/llvm/test/Transforms/SimplifyCFG/hoist-sink-swifterror-store.ll
index 5dff39c1f9a52..382d881caf5c0 100644
--- a/llvm/test/Transforms/SimplifyCFG/hoist-sink-swifterror-store.ll
+++ b/llvm/test/Transforms/SimplifyCFG/hoist-sink-swifterror-store.ll
@@ -41,6 +41,42 @@ exit:
ret void
}
+; Same as @sink, but with the swifterror store in the other predecessor. Also
+; must not be sunk, as it requires introducing a select for the swifterror
+; pointer operand.
+define swiftcc void @sink_store_in_other_pred(ptr %arg, ptr swifterror %arg1, i1 %c) {
+; CHECK-LABEL: define swiftcc void @sink_store_in_other_pred
+; CHECK-SAME: (ptr [[ARG:%.*]], ptr swifterror [[ARG1:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT: bb:
+; CHECK-NEXT: br i1 [[C]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK: then:
+; CHECK-NEXT: call void @clobber1()
+; CHECK-NEXT: store ptr null, ptr [[ARG1]], align 8
+; CHECK-NEXT: br label [[EXIT:%.*]]
+; CHECK: else:
+; CHECK-NEXT: call void @clobber2()
+; CHECK-NEXT: store ptr null, ptr [[ARG]], align 8
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: exit:
+; CHECK-NEXT: ret void
+;
+bb:
+ br i1 %c, label %then, label %else
+
+then:
+ call void @clobber1()
+ store ptr null, ptr %arg1, align 8
+ br label %exit
+
+else:
+ call void @clobber2()
+ store ptr null, ptr %arg, align 8
+ br label %exit
+
+exit:
+ ret void
+}
+
define swiftcc void @hoist_store(ptr %arg, ptr swifterror %arg1, i1 %c) {
; CHECK-LABEL: define swiftcc void @hoist_store
; CHECK-SAME: (ptr [[ARG:%.*]], ptr swifterror [[ARG1:%.*]], i1 [[C:%.*]]) {
@@ -74,9 +110,8 @@ exit:
ret void
}
-; FIXME: currently simplifycfg tries to sink the load to the exit block and
-; introduces a select for the pointer operand. This is not allowed for
-; swifterror pointers.
+; Do not try to sink the loads to the exit block, as this requires introducing
+; a select for the pointer operand. This is not allowed for swifterror pointers.
define swiftcc ptr @sink_load(ptr %arg, ptr swifterror %arg1, i1 %c) {
; CHECK-LABEL: define swiftcc ptr @sink_load
; CHECK-SAME: (ptr [[ARG:%.*]], ptr swifterror [[ARG1:%.*]], i1 [[C:%.*]]) {
@@ -111,6 +146,43 @@ exit:
%p = phi ptr [ %l1, %then ], [ %l2, %else ]
ret ptr %p
}
+
+; Same as @sink_load, but with the swifterror load in the other predecessor.
+define swiftcc ptr @sink_load_in_other_pred(ptr %arg, ptr swifterror %arg1, i1 %c) {
+; CHECK-LABEL: define swiftcc ptr @sink_load_in_other_pred
+; CHECK-SAME: (ptr [[ARG:%.*]], ptr swifterror [[ARG1:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT: bb:
+; CHECK-NEXT: br i1 [[C]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK: then:
+; CHECK-NEXT: call void @clobber1()
+; CHECK-NEXT: [[L1:%.*]] = load ptr, ptr [[ARG1]], align 8
+; CHECK-NEXT: br label [[EXIT:%.*]]
+; CHECK: else:
+; CHECK-NEXT: call void @clobber2()
+; CHECK-NEXT: [[L2:%.*]] = load ptr, ptr [[ARG]], align 8
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: exit:
+; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[L1]], [[THEN]] ], [ [[L2]], [[ELSE]] ]
+; CHECK-NEXT: ret ptr [[P]]
+;
+bb:
+ br i1 %c, label %then, label %else
+
+then:
+ call void @clobber1()
+ %l1 = load ptr, ptr %arg1, align 8
+ br label %exit
+
+else:
+ call void @clobber2()
+ %l2 = load ptr, ptr %arg, align 8
+ br label %exit
+
+exit:
+ %p = phi ptr [ %l1, %then ], [ %l2, %else ]
+ ret ptr %p
+}
+
define swiftcc ptr @hoist_load(ptr %arg, ptr swifterror %arg1, i1 %c) {
; CHECK-LABEL: define swiftcc ptr @hoist_load
; CHECK-SAME: (ptr [[ARG:%.*]], ptr swifterror [[ARG1:%.*]], i1 [[C:%.*]]) {
More information about the llvm-commits
mailing list