Files
swift-mirror/lib/SIL/InstructionUtils.cpp
Erik Eckstein a16beaea3c Remove the now usused ConformanceCollector utility.
It was used for dead witness table elimination. But this is done now by lazy emission in IRGen.
Also update DeadFunctionElimination.
NFC.
2017-03-15 10:18:18 -07:00

317 lines
9.1 KiB
C++

//===--- 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<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::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<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];
}
namespace {
enum class OwnershipQualifiedKind {
NotApplicable,
Qualified,
Unqualified,
};
struct OwnershipQualifiedKindVisitor : SILInstructionVisitor<OwnershipQualifiedKindVisitor, OwnershipQualifiedKind> {
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.");
}