//===--- 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(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::UncheckedRefCastAddrInst: 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(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(PredTI)) { V = BI->getArg(A->getIndex()); continue; } if (auto *CBI = dyn_cast(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(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(V)->getOperand(0); continue; } return V; } } SILValue swift::stripUpCasts(SILValue V) { assert(V->getType().isClassOrClassMetatype() && "Expected class or class metatype!"); V = stripSinglePredecessorArgs(V); while (isa(V)) V = stripSinglePredecessorArgs(cast(V)->getOperand()); return V; } SILValue swift::stripClassCasts(SILValue V) { while (true) { if (auto *UI = dyn_cast(V)) { V = UI->getOperand(); continue; } if (auto *UCCI = dyn_cast(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(V)->getOperand(0); } } SILValue swift::stripUnaryAddressProjections(SILValue V) { while (true) { V = stripSinglePredecessorArgs(V); if (!Projection::isAddressProjection(V)) return V; auto *Inst = cast(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(V)->getOperand(0); } } SILValue swift::stripIndexingInsts(SILValue V) { while (true) { if (!isa(V)) return V; V = cast(V)->getBase(); } } SILValue swift::stripExpectIntrinsic(SILValue V) { auto *BI = dyn_cast(V); if (!BI) return V; if (BI->getIntrinsicInfo().ID != llvm::Intrinsic::expect) return V; return BI->getArguments()[0]; } namespace { enum class OwnershipQualifiedKind { NotApplicable, Qualified, Unqualified, }; struct OwnershipQualifiedKindVisitor : SILInstructionVisitor { OwnershipQualifiedKind visitValueBase(ValueBase *V) { 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."); }