//===--- 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; } } 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(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(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::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]; }