| //===--- InstructionUtils.cpp - Utilities for SIL instructions ------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See http://swift.org/LICENSE.txt for license information |
| // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #define DEBUG_TYPE "sil-inst-utils" |
| #include "swift/SIL/InstructionUtils.h" |
| #include "swift/SIL/SILArgument.h" |
| #include "swift/SIL/SILBasicBlock.h" |
| #include "swift/SIL/Projection.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<SILInstruction>(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::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->getSinglePredecessor(); |
| 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<SILInstruction>(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<SILInstruction>(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<UpcastInst>(V)) |
| V = stripSinglePredecessorArgs(cast<UpcastInst>(V)->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<SILInstruction>(V)->getOperand(0); |
| } |
| } |
| |
| SILValue swift::stripUnaryAddressProjections(SILValue V) { |
| while (true) { |
| V = stripSinglePredecessorArgs(V); |
| if (!Projection::isAddressProjection(V)) |
| return V; |
| auto *Inst = cast<SILInstruction>(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<SILInstruction>(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]; |
| } |