| //===--- InstructionUtils.cpp - Utilities for SIL instructions ------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #define DEBUG_TYPE "sil-inst-utils" |
| #include "swift/SIL/InstructionUtils.h" |
| #include "swift/AST/SubstitutionMap.h" |
| #include "swift/Basic/NullablePtr.h" |
| #include "swift/SIL/Projection.h" |
| #include "swift/SIL/SILArgument.h" |
| #include "swift/SIL/SILBasicBlock.h" |
| #include "swift/SIL/SILVisitor.h" |
| |
| using namespace swift; |
| |
| /// Strip off casts/indexing insts/address projections from V until there is |
| /// nothing left to strip. |
| /// FIXME: Why don't we strip projections after stripping indexes? |
| SILValue swift::getUnderlyingObject(SILValue V) { |
| while (true) { |
| SILValue V2 = stripIndexingInsts(stripAddressProjections(stripCasts(V))); |
| if (V2 == V) |
| return V2; |
| V = V2; |
| } |
| } |
| |
| SILValue swift::getUnderlyingAddressRoot(SILValue V) { |
| while (true) { |
| SILValue V2 = stripIndexingInsts(stripCasts(V)); |
| switch (V2->getKind()) { |
| case ValueKind::StructElementAddrInst: |
| case ValueKind::TupleElementAddrInst: |
| case ValueKind::UncheckedTakeEnumDataAddrInst: |
| V2 = cast<SingleValueInstruction>(V2)->getOperand(0); |
| break; |
| default: |
| break; |
| } |
| if (V2 == V) |
| return V2; |
| V = V2; |
| } |
| } |
| |
| |
| SILValue swift::getUnderlyingObjectStopAtMarkDependence(SILValue V) { |
| while (true) { |
| SILValue V2 = stripIndexingInsts(stripAddressProjections(stripCastsWithoutMarkDependence(V))); |
| if (V2 == V) |
| return V2; |
| V = V2; |
| } |
| } |
| |
| static bool isRCIdentityPreservingCast(ValueKind Kind) { |
| switch (Kind) { |
| case ValueKind::UpcastInst: |
| case ValueKind::UncheckedRefCastInst: |
| case ValueKind::UnconditionalCheckedCastInst: |
| case ValueKind::UnconditionalCheckedCastValueInst: |
| case ValueKind::RefToBridgeObjectInst: |
| case ValueKind::BridgeObjectToRefInst: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| /// Return the underlying SILValue after stripping off identity SILArguments if |
| /// we belong to a BB with one predecessor. |
| SILValue swift::stripSinglePredecessorArgs(SILValue V) { |
| while (true) { |
| auto *A = dyn_cast<SILArgument>(V); |
| if (!A) |
| return V; |
| |
| SILBasicBlock *BB = A->getParent(); |
| |
| // First try and grab the single predecessor of our parent BB. If we don't |
| // have one, bail. |
| SILBasicBlock *Pred = BB->getSinglePredecessorBlock(); |
| if (!Pred) |
| return V; |
| |
| // Then grab the terminator of Pred... |
| TermInst *PredTI = Pred->getTerminator(); |
| |
| // And attempt to find our matching argument. |
| // |
| // *NOTE* We can only strip things here if we know that there is no semantic |
| // change in terms of upcasts/downcasts/enum extraction since this is used |
| // by other routines here. This means that we can only look through |
| // cond_br/br. |
| // |
| // For instance, routines that use stripUpcasts() do not want to strip off a |
| // downcast that results from checked_cast_br. |
| if (auto *BI = dyn_cast<BranchInst>(PredTI)) { |
| V = BI->getArg(A->getIndex()); |
| continue; |
| } |
| |
| if (auto *CBI = dyn_cast<CondBranchInst>(PredTI)) { |
| if (SILValue Arg = CBI->getArgForDestBB(BB, A)) { |
| V = Arg; |
| continue; |
| } |
| } |
| |
| return V; |
| } |
| } |
| |
| SILValue swift::stripCastsWithoutMarkDependence(SILValue V) { |
| while (true) { |
| V = stripSinglePredecessorArgs(V); |
| |
| auto K = V->getKind(); |
| if (isRCIdentityPreservingCast(K) || |
| K == ValueKind::UncheckedTrivialBitCastInst) { |
| V = cast<SingleValueInstruction>(V)->getOperand(0); |
| continue; |
| } |
| |
| return V; |
| } |
| } |
| |
| SILValue swift::stripCasts(SILValue V) { |
| while (true) { |
| V = stripSinglePredecessorArgs(V); |
| |
| auto K = V->getKind(); |
| if (isRCIdentityPreservingCast(K) |
| || K == ValueKind::UncheckedTrivialBitCastInst |
| || K == ValueKind::MarkDependenceInst) { |
| V = cast<SingleValueInstruction>(V)->getOperand(0); |
| continue; |
| } |
| |
| return V; |
| } |
| } |
| |
| SILValue swift::stripUpCasts(SILValue V) { |
| assert(V->getType().isClassOrClassMetatype() && |
| "Expected class or class metatype!"); |
| |
| V = stripSinglePredecessorArgs(V); |
| |
| while (auto upcast = dyn_cast<UpcastInst>(V)) |
| V = stripSinglePredecessorArgs(upcast->getOperand()); |
| |
| return V; |
| } |
| |
| SILValue swift::stripClassCasts(SILValue V) { |
| while (true) { |
| if (auto *UI = dyn_cast<UpcastInst>(V)) { |
| V = UI->getOperand(); |
| continue; |
| } |
| |
| if (auto *UCCI = dyn_cast<UnconditionalCheckedCastInst>(V)) { |
| V = UCCI->getOperand(); |
| continue; |
| } |
| |
| return V; |
| } |
| } |
| |
| SILValue swift::stripAddressProjections(SILValue V) { |
| while (true) { |
| V = stripSinglePredecessorArgs(V); |
| if (!Projection::isAddressProjection(V)) |
| return V; |
| V = cast<SingleValueInstruction>(V)->getOperand(0); |
| } |
| } |
| |
| SILValue swift::stripUnaryAddressProjections(SILValue V) { |
| while (true) { |
| V = stripSinglePredecessorArgs(V); |
| if (!Projection::isAddressProjection(V)) |
| return V; |
| auto *Inst = cast<SingleValueInstruction>(V); |
| if (Inst->getNumOperands() > 1) |
| return V; |
| V = Inst->getOperand(0); |
| } |
| } |
| |
| SILValue swift::stripValueProjections(SILValue V) { |
| while (true) { |
| V = stripSinglePredecessorArgs(V); |
| if (!Projection::isObjectProjection(V)) |
| return V; |
| V = cast<SingleValueInstruction>(V)->getOperand(0); |
| } |
| } |
| |
| SILValue swift::stripIndexingInsts(SILValue V) { |
| while (true) { |
| if (!isa<IndexingInst>(V)) |
| return V; |
| V = cast<IndexingInst>(V)->getBase(); |
| } |
| } |
| |
| SILValue swift::stripExpectIntrinsic(SILValue V) { |
| auto *BI = dyn_cast<BuiltinInst>(V); |
| if (!BI) |
| return V; |
| if (BI->getIntrinsicInfo().ID != llvm::Intrinsic::expect) |
| return V; |
| return BI->getArguments()[0]; |
| } |
| |
| SILValue swift::stripBorrow(SILValue V) { |
| if (auto *BBI = dyn_cast<BeginBorrowInst>(V)) |
| return BBI->getOperand(); |
| return V; |
| } |
| |
| namespace { |
| |
| enum class OwnershipQualifiedKind { |
| NotApplicable, |
| Qualified, |
| Unqualified, |
| }; |
| |
| struct OwnershipQualifiedKindVisitor : SILInstructionVisitor<OwnershipQualifiedKindVisitor, OwnershipQualifiedKind> { |
| |
| OwnershipQualifiedKind visitSILInstruction(SILInstruction *I) { |
| return OwnershipQualifiedKind::NotApplicable; |
| } |
| |
| #define QUALIFIED_INST(CLASS) \ |
| OwnershipQualifiedKind visit ## CLASS(CLASS *I) { \ |
| return OwnershipQualifiedKind::Qualified; \ |
| } |
| QUALIFIED_INST(EndBorrowInst) |
| QUALIFIED_INST(LoadBorrowInst) |
| QUALIFIED_INST(CopyValueInst) |
| QUALIFIED_INST(CopyUnownedValueInst) |
| QUALIFIED_INST(DestroyValueInst) |
| #undef QUALIFIED_INST |
| |
| OwnershipQualifiedKind visitLoadInst(LoadInst *LI) { |
| if (LI->getOwnershipQualifier() == LoadOwnershipQualifier::Unqualified) |
| return OwnershipQualifiedKind::Unqualified; |
| return OwnershipQualifiedKind::Qualified; |
| } |
| |
| OwnershipQualifiedKind visitStoreInst(StoreInst *SI) { |
| if (SI->getOwnershipQualifier() == StoreOwnershipQualifier::Unqualified) |
| return OwnershipQualifiedKind::Unqualified; |
| return OwnershipQualifiedKind::Qualified; |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| bool FunctionOwnershipEvaluator::evaluate(SILInstruction *I) { |
| assert(I->getFunction() == F.get() && "Can not evaluate function ownership " |
| "implications of an instruction that " |
| "does not belong to the instruction " |
| "that we are evaluating"); |
| |
| switch (OwnershipQualifiedKindVisitor().visit(I)) { |
| case OwnershipQualifiedKind::Unqualified: { |
| // If we already know that the function has unqualified ownership, just |
| // return early. |
| if (!F.get()->hasQualifiedOwnership()) |
| return true; |
| |
| // Ok, so we know at this point that we have qualified ownership. If we have |
| // seen any instructions with qualified ownership, we have an error since |
| // the function mixes qualified and unqualified instructions. |
| if (HasOwnershipQualifiedInstruction) |
| return false; |
| |
| // Otherwise, set the function to have unqualified ownership. This will |
| // ensure that no more Qualified instructions can be added to the given |
| // function. |
| F.get()->setUnqualifiedOwnership(); |
| return true; |
| } |
| case OwnershipQualifiedKind::Qualified: { |
| // First check if our function has unqualified ownership. If we already do |
| // have unqualified ownership, then we know that we have already seen an |
| // unqualified ownership instruction. This means the function has both |
| // qualified and unqualified instructions. =><=. |
| if (!F.get()->hasQualifiedOwnership()) |
| return false; |
| |
| // Ok, at this point we know that we are still qualified. Since functions |
| // start as qualified, we need to set the HasOwnershipQualifiedInstructions |
| // so we do not need to look back through the function if we see an |
| // unqualified instruction later on. |
| HasOwnershipQualifiedInstruction = true; |
| return true; |
| } |
| case OwnershipQualifiedKind::NotApplicable: { |
| // Not Applicable instr |
| return true; |
| } |
| } |
| |
| llvm_unreachable("Unhandled OwnershipQualifiedKind in switch."); |
| } |