[llvm] [SimplifyCFG][swifterror] Don't sink calls with swifterror params (PR #139015)
Ellis Hoag via llvm-commits
llvm-commits at lists.llvm.org
Wed May 7 21:05:16 PDT 2025
https://github.com/ellishg created https://github.com/llvm/llvm-project/pull/139015
We've encountered an LLVM verification failure when building Swift with the SimplifyCFG pass enabled. I found that https://reviews.llvm.org/D158083 fixed this pass by preventing sinking loads or stores of swifterror values, but it did not implement the same protection for call or invokes.
In `Verifier.cpp` [here](https://github.com/ellishg/llvm-project/blob/c68535581135a1513c9c4c1c7672307d4b5e616e/llvm/lib/IR/Verifier.cpp#L4360-L4364) and [here](https://github.com/ellishg/llvm-project/blob/c68535581135a1513c9c4c1c7672307d4b5e616e/llvm/lib/IR/Verifier.cpp#L3661-L3662) we can see that swifterror values must also be used directly by call instructions.
>From ce62ee0a19c8c5ea6cc69522d5d168298579f26a Mon Sep 17 00:00:00 2001
From: Ellis Hoag <ellishoag at meta.com>
Date: Wed, 7 May 2025 20:51:50 -0700
Subject: [PATCH] [SimplifyCFG][swifterror] Don't sink calls with swifterror
params
---
llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 11 ++--
.../hoist-sink-swifterror-store.ll | 53 +++++++++++++++++++
2 files changed, 61 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 33af582a9e0a9..98ecfeb101cd4 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -2190,13 +2190,18 @@ static bool canSinkInstructions(
if (!I->isSameOperationAs(I0, Instruction::CompareUsingIntersectedAttrs))
return false;
- // swifterror pointers can only be used by a load or store; sinking a load
- // or store would require introducing a select for the pointer operand,
- // which isn't allowed for swifterror pointers.
+ // swifterror pointers can only be used by a load, store, or as a swifterror
+ // argument; sinking a load, store, or call would require introducing a
+ // select for the pointer operand, which isn't allowed for swifterror
+ // pointers.
if (isa<StoreInst>(I) && I->getOperand(1)->isSwiftError())
return false;
if (isa<LoadInst>(I) && I->getOperand(0)->isSwiftError())
return false;
+ if (const auto *CB = dyn_cast<CallBase>(I))
+ for (const Use &Arg : CB->args())
+ if (Arg->isSwiftError())
+ return false;
// Treat MMRAs conservatively. This pass can be quite aggressive and
// could drop a lot of MMRAs otherwise.
diff --git a/llvm/test/Transforms/SimplifyCFG/hoist-sink-swifterror-store.ll b/llvm/test/Transforms/SimplifyCFG/hoist-sink-swifterror-store.ll
index 0c13f5703447a..75fb986b20a93 100644
--- a/llvm/test/Transforms/SimplifyCFG/hoist-sink-swifterror-store.ll
+++ b/llvm/test/Transforms/SimplifyCFG/hoist-sink-swifterror-store.ll
@@ -3,6 +3,7 @@
declare void @clobber1()
declare void @clobber2()
+declare swiftcc void @swift_willThrow(ptr swifterror)
; Do not try to sink the stores to the exit block, as this requires introducing
; a select for the pointer operand. This is not allowed for swifterror pointers.
@@ -76,6 +77,22 @@ exit:
; introduces 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:%.*]]) {
+; 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 [[ARG]], align 8
+; CHECK-NEXT: br label [[EXIT:%.*]]
+; CHECK: else:
+; CHECK-NEXT: call void @clobber2()
+; CHECK-NEXT: [[L2:%.*]] = load ptr, ptr [[ARG1]], 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
@@ -127,3 +144,39 @@ exit:
%p = phi ptr [ %l1, %then ], [ %l2, %else ]
ret ptr %p
}
+
+
+define swiftcc void @sink_call(i1 %c) {
+; CHECK-LABEL: define swiftcc void @sink_call
+; CHECK-SAME: (i1 [[C:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = alloca swifterror ptr, align 8
+; CHECK-NEXT: [[TMP2:%.*]] = alloca swifterror ptr, align 8
+; CHECK-NEXT: br i1 [[C]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK: then:
+; CHECK-NEXT: call void @clobber1()
+; CHECK-NEXT: call swiftcc void @swift_willThrow(ptr [[TMP2]])
+; CHECK-NEXT: br label [[EXIT:%.*]]
+; CHECK: else:
+; CHECK-NEXT: call void @clobber2()
+; CHECK-NEXT: call swiftcc void @swift_willThrow(ptr [[TMP1]])
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: exit:
+; CHECK-NEXT: ret void
+;
+ %2 = alloca swifterror ptr, align 8
+ %3 = alloca swifterror ptr, align 8
+ br i1 %c, label %then, label %else
+
+then:
+ call void @clobber1()
+ call swiftcc void @swift_willThrow(ptr %3)
+ br label %exit
+
+else:
+ call void @clobber2()
+ call swiftcc void @swift_willThrow(ptr %2)
+ br label %exit
+
+exit:
+ ret void
+}
More information about the llvm-commits
mailing list