diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index a798808d79656..cc73e40e355a6 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -3653,18 +3653,38 @@ 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(SwiftErrorArg->stripInBoundsOffsets())) { - Check(AI->isSwiftError(), - "swifterror argument for call has mismatched alloca", AI, Call); - continue; + const Value *Arg = Call.getArgOperand(i); + SetVector Values; + Values.insert(Arg); + SmallVector PHIWorkList; + if (auto *PhiI = dyn_cast(Arg)) + PHIWorkList.push_back(PhiI); + + while (!PHIWorkList.empty()) { + const auto *PhiI = PHIWorkList.pop_back_val(); + for (const Value *Op : PhiI->incoming_values()) { + const auto *NextPhiI = dyn_cast(Op); + if (Values.insert(Op) && NextPhiI) + PHIWorkList.push_back(NextPhiI); + } + } + for (const Value *SwiftErrorArg : Values) { + if (isa(SwiftErrorArg)) + continue; + if (auto AI = + dyn_cast(SwiftErrorArg->stripInBoundsOffsets())) { + Check(AI->isSwiftError(), + "swifterror argument for call has mismatched alloca", AI, Call); + continue; + } + auto ArgI = dyn_cast(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(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,9 +4376,26 @@ void Verifier::verifySwiftErrorCall(CallBase &Call, } void Verifier::verifySwiftErrorValue(const Value *SwiftErrorVal) { + SetVector Users(SwiftErrorVal->users().begin(), + SwiftErrorVal->users().end()); + SmallVector PHIWorkList; + for (const User *U : Users) + if (auto *PhiI = dyn_cast(U)) + PHIWorkList.push_back(PhiI); + + while (!PHIWorkList.empty()) { + const auto *PhiI = PHIWorkList.pop_back_val(); + for (const User *U : PhiI->users()) { + const auto *NextPhiI = dyn_cast(U); + if (Users.insert(U) && NextPhiI) + PHIWorkList.push_back(NextPhiI); + } + } // 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) { + if (isa(U)) + continue; Check(isa(U) || isa(U) || isa(U) || isa(U), "swifterror value can only be loaded and stored from, or " 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