Skip to content

[verify][swift] Allow passing swifterror to phi instructions #138598

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

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 49 additions & 12 deletions llvm/lib/IR/Verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<AllocaInst>(SwiftErrorArg->stripInBoundsOffsets())) {
Check(AI->isSwiftError(),
"swifterror argument for call has mismatched alloca", AI, Call);
continue;
const Value *Arg = Call.getArgOperand(i);
SetVector<const Value *> Values;
Values.insert(Arg);
SmallVector<const PHINode *> PHIWorkList;
if (auto *PhiI = dyn_cast<PHINode>(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<PHINode>(Op);
if (Values.insert(Op) && NextPhiI)
PHIWorkList.push_back(NextPhiI);
}
}
for (const Value *SwiftErrorArg : Values) {
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)) {
Expand Down Expand Up @@ -4356,9 +4376,26 @@ void Verifier::verifySwiftErrorCall(CallBase &Call,
}

void Verifier::verifySwiftErrorValue(const Value *SwiftErrorVal) {
SetVector<const User *> Users(SwiftErrorVal->users().begin(),
SwiftErrorVal->users().end());
SmallVector<const PHINode *> PHIWorkList;
for (const User *U : Users)
if (auto *PhiI = dyn_cast<PHINode>(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<PHINode>(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<PHINode>(U))
continue;
Check(isa<LoadInst>(U) || isa<StoreInst>(U) || isa<CallInst>(U) ||
isa<InvokeInst>(U),
"swifterror value can only be loaded and stored from, or "
Expand Down
34 changes: 33 additions & 1 deletion llvm/test/Verifier/swifterror.ll
Original file line number Diff line number Diff line change
@@ -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}

Expand All @@ -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)
Expand All @@ -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
Expand Down