-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[SimplifyCFG][swifterror] Don't sink calls with swifterror params #139015
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-llvm-transforms Author: Ellis Hoag (ellishg) ChangesWe'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. Full diff: https://github.com/llvm/llvm-project/pull/139015.diff 2 Files Affected:
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
+}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be better to check this in canReplaceOperandWithVariable (and move the existing checks there as well).
In particular, legality here depends on whether sinking requires the introduction of a phi node or not. Could you add test variant where the swifterror argument is the same in both calls, and another argument differs?
Just to make sure I understand. In this case the sink would be safe, right? |
Let me know if the comment make sense in the context of |
I think it might make sense to try to leverage the similarity between swifterror values and the |
llvm/lib/Transforms/Utils/Local.cpp
Outdated
// argument; swifterror pointers are not allowed to be used in select or phi | ||
// instructions. | ||
if ((OpIdx == 1 && isa<StoreInst>(I)) || (OpIdx == 0 && isa<LoadInst>(I)) || | ||
(OpIdx < I->getNumOperands() && isa<CallBase>(I))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be better to omit these checks and just always check for isSwiftError().
I see that |
Friendly ping |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
3495fa6
to
3a4dc2f
Compare
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 and here we can see that swifterror values must also be used directly by call instructions.