[llvm] [verify][swift] Allow passing swifterror to phi instructions (PR #138598)

via llvm-commits llvm-commits at lists.llvm.org
Mon May 5 15:06:55 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-ir

Author: Ellis Hoag (ellishg)

<details>
<summary>Changes</summary>

We encountered some code that failed swift verification because some swifterror values were passed to phi instructions. I believe this should be valid, so this PR adjusts the verification code to allow this.

---
Full diff: https://github.com/llvm/llvm-project/pull/138598.diff


2 Files Affected:

- (modified) llvm/lib/IR/Verifier.cpp (+43-13) 
- (modified) llvm/test/Verifier/swifterror.ll (+33-1) 


``````````diff
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index a798808d79656..2e5ff4b5df8dd 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -3653,18 +3653,36 @@ void Verifier::visitCallBase(CallBase &Call) {
   // well.
   for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i) {
     if (Call.paramHasAttr(i, Attribute::SwiftError)) {
-      Value *SwiftErrorArg = Call.getArgOperand(i);
-      if (auto AI = dyn_cast<AllocaInst>(SwiftErrorArg->stripInBoundsOffsets())) {
-        Check(AI->isSwiftError(),
-              "swifterror argument for call has mismatched alloca", AI, Call);
-        continue;
+      SetVector<const Value *> Args;
+      Args.insert(Call.getArgOperand(i));
+      bool DidChange;
+      do {
+        DidChange = false;
+        // Inherit the incoming values of phi instructions to capture all
+        // values.
+        for (const Value *Arg : Args)
+          if (auto *PhiI = dyn_cast<PHINode>(Arg))
+            for (const auto &Op : PhiI->incoming_values())
+              DidChange |= Args.insert(Op.get());
+      } while (DidChange);
+
+      for (const Value *SwiftErrorArg : Args) {
+        if (isa<PHINode>(SwiftErrorArg))
+          continue;
+        if (auto AI =
+                dyn_cast<AllocaInst>(SwiftErrorArg->stripInBoundsOffsets())) {
+          Check(AI->isSwiftError(),
+                "swifterror argument for call has mismatched alloca", AI, Call);
+          continue;
+        }
+        auto ArgI = dyn_cast<Argument>(SwiftErrorArg);
+        Check(ArgI,
+              "swifterror argument should come from an alloca or parameter",
+              SwiftErrorArg, Call);
+        Check(ArgI->hasSwiftErrorAttr(),
+              "swifterror argument for call has mismatched parameter", ArgI,
+              Call);
       }
-      auto ArgI = dyn_cast<Argument>(SwiftErrorArg);
-      Check(ArgI, "swifterror argument should come from an alloca or parameter",
-            SwiftErrorArg, Call);
-      Check(ArgI->hasSwiftErrorAttr(),
-            "swifterror argument for call has mismatched parameter", ArgI,
-            Call);
     }
 
     if (Attrs.hasParamAttr(i, Attribute::ImmArg)) {
@@ -4356,11 +4374,23 @@ void Verifier::verifySwiftErrorCall(CallBase &Call,
 }
 
 void Verifier::verifySwiftErrorValue(const Value *SwiftErrorVal) {
+  SetVector<const User *> Users(SwiftErrorVal->users().begin(),
+                                SwiftErrorVal->users().end());
+  bool DidChange;
+  do {
+    DidChange = false;
+    // Inherit the users of phi instructions to capture all users.
+    for (const User *U : Users)
+      if (auto PhiI = dyn_cast<PHINode>(U))
+        for (const User *U : PhiI->users())
+          DidChange |= Users.insert(U);
+  } while (DidChange);
+
   // Check that swifterror value is only used by loads, stores, or as
   // a swifterror argument.
-  for (const User *U : SwiftErrorVal->users()) {
+  for (const User *U : Users) {
     Check(isa<LoadInst>(U) || isa<StoreInst>(U) || isa<CallInst>(U) ||
-              isa<InvokeInst>(U),
+              isa<InvokeInst>(U) || isa<PHINode>(U),
           "swifterror value can only be loaded and stored from, or "
           "as a swifterror argument!",
           SwiftErrorVal, U);
diff --git a/llvm/test/Verifier/swifterror.ll b/llvm/test/Verifier/swifterror.ll
index d27b43234cadc..ae340d24068fb 100644
--- a/llvm/test/Verifier/swifterror.ll
+++ b/llvm/test/Verifier/swifterror.ll
@@ -1,4 +1,4 @@
-; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
+; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s --implicit-check-not=swifterror
 
 %swift_error = type {i64, i8}
 
@@ -10,6 +10,36 @@ define float @foo(ptr swifterror %error_ptr_ref) {
   ret float 1.0
 }
 
+; CHECK: swifterror value can only be loaded and stored from, or as a swifterror argument!
+; CHECK: %ptr0 = alloca swifterror ptr, align 8
+; CHECK: %t = getelementptr inbounds ptr, ptr %err, i64 1
+; CHECK: swifterror value can only be loaded and stored from, or as a swifterror argument!
+; CHECK: %ptr1 = alloca swifterror ptr, align 8
+; CHECK: %t = getelementptr inbounds ptr, ptr %err, i64 1
+define float @phi(i1 %a) {
+entry:
+  %ptr0 = alloca swifterror ptr, align 8
+  %ptr1 = alloca swifterror ptr, align 8
+  %ptr2 = alloca ptr, align 8
+  br i1 %a, label %body, label %body2
+
+body:
+  %err = phi ptr [ %ptr0, %entry ], [ %ptr1, %body ]
+  %t = getelementptr inbounds ptr, ptr %err, i64 1
+  br label %body
+
+; CHECK: swifterror argument for call has mismatched alloca
+; CHECK: %ptr2 = alloca ptr, align 8
+; CHECK: %call = call float @foo(ptr swifterror %err_bad)
+body2:
+  %err_bad = phi ptr [ %ptr0, %entry ], [ %ptr2, %body2 ]
+  %call = call float @foo(ptr swifterror %err_bad)
+  br label %body2
+
+end:
+  ret float 1.0
+}
+
 ; CHECK: swifterror argument for call has mismatched alloca
 ; CHECK: %error_ptr_ref = alloca ptr
 ; CHECK: %call = call float @foo(ptr swifterror %error_ptr_ref)
@@ -22,12 +52,14 @@ entry:
 }
 
 ; CHECK: swifterror alloca must have pointer type
+; CHECK: %a = alloca swifterror i128, align 8
 define void @swifterror_alloca_invalid_type() {
   %a = alloca swifterror i128
   ret void
 }
 
 ; CHECK: swifterror alloca must not be array allocation
+; CHECK: %a = alloca swifterror ptr, i64 2, align 8
 define void @swifterror_alloca_array() {
   %a = alloca swifterror ptr, i64 2
   ret void

``````````

</details>


https://github.com/llvm/llvm-project/pull/138598


More information about the llvm-commits mailing list