Files
swift-mirror/lib/SILPasses/Utils/Local.cpp
Mark Lacey b6442dde4e Remove unused code in box-to-stack promotion.
r15322 reworked the logic for determining where the final releases are,
which means that we no longer need to collect the uses and releases as
we evaluate candidates for promotion.

Swift SVN r15333
2014-03-21 20:26:43 +00:00

282 lines
9.1 KiB
C++

//===--- Local.cpp - Functions that perform local SIL transformations. ---===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 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
//
//===---------------------------------------------------------------------===//
#include "swift/SILPasses/Utils/Local.h"
#include "swift/SILAnalysis/Analysis.h"
#include "swift/SIL/CallGraph.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILModule.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/IR/Intrinsics.h"
#include <deque>
using namespace swift;
bool
swift::isSideEffectFree(BuiltinFunctionRefInst *FR) {
// First, check if we are dealing with a swift builtin.
const BuiltinInfo &BInfo = FR->getBuiltinInfo();
if (BInfo.ID != BuiltinValueKind::None) {
return BInfo.isReadNone();
}
// Second, specialcase llvm intrinsic.
const IntrinsicInfo & IInfo = FR->getIntrinsicInfo();
if (IInfo.ID != llvm::Intrinsic::not_intrinsic) {
return ( (IInfo.hasAttribute(llvm::Attribute::ReadNone) ||
IInfo.hasAttribute(llvm::Attribute::ReadOnly)) &&
IInfo.hasAttribute(llvm::Attribute::NoUnwind) );
}
llvm_unreachable("All cases are covered.");
}
bool swift::isReadNone(BuiltinFunctionRefInst *FR) {
// First, check if we are dealing with a swift builtin.
const BuiltinInfo &BInfo = FR->getBuiltinInfo();
if (BInfo.ID != BuiltinValueKind::None)
return BInfo.isReadNone();
// Second, specialcase llvm intrinsic.
const IntrinsicInfo & IInfo = FR->getIntrinsicInfo();
if (IInfo.ID != llvm::Intrinsic::not_intrinsic)
return IInfo.hasAttribute(llvm::Attribute::ReadNone) &&
IInfo.hasAttribute(llvm::Attribute::NoUnwind);
llvm_unreachable("All cases are covered.");
}
/// \brief Perform a fast local check to see if the instruction is dead.
///
/// This routine only examines the state of the instruction at hand.
bool
swift::isInstructionTriviallyDead(SILInstruction *I) {
if (!I->use_empty() || isa<TermInst>(I))
return false;
// We know that some calls do not have side effects.
if (const ApplyInst *AI = dyn_cast<ApplyInst>(I)) {
if (BuiltinFunctionRefInst *FR =
dyn_cast<BuiltinFunctionRefInst>(AI->getCallee().getDef())) {
return isSideEffectFree(FR);
}
}
// condfail instructions that obviously can't fail are dead.
if (auto *CFI = dyn_cast<CondFailInst>(I))
if (auto *ILI = dyn_cast<IntegerLiteralInst>(CFI->getOperand()))
if (!ILI->getValue())
return true;
// mark_uninitialized is never dead.
if (isa<MarkUninitializedInst>(I))
return false;
if (!I->mayHaveSideEffects())
return true;
return false;
}
/// \brief For each of the given instructions, if they are dead delete them
/// along with their dead operands.
///
/// \param IA The instruction to be deleted.
/// \param Force If Force is set, don't check if the top level instructions
/// are considered dead - delete them regardless.
bool
swift::recursivelyDeleteTriviallyDeadInstructions(ArrayRef<SILInstruction*> IA,
bool Force) {
// Delete these instruction and others that become dead after it's deleted.
llvm::SmallPtrSet<SILInstruction*, 8> DeadInsts;
for (auto I : IA) {
// If the instruction is not dead or force is false, there is nothing to do.
if (Force || isInstructionTriviallyDead(I))
DeadInsts.insert(I);
}
llvm::SmallPtrSet<SILInstruction*, 8> NextInsts;
while (!DeadInsts.empty()) {
for (auto I : DeadInsts) {
// Check if any of the operands will become dead as well.
MutableArrayRef<Operand> Ops = I->getAllOperands();
for (Operand &Op : Ops) {
SILValue OpVal = Op.get();
if (!OpVal) continue;
// Remove the reference from the instruction being deleted to this
// operand.
Op.drop();
// If the operand is an instruction that is only used by the instruction
// being deleted, delete it.
if (SILInstruction *OpValInst = dyn_cast<SILInstruction>(OpVal))
if (!DeadInsts.count(OpValInst) &&
isInstructionTriviallyDead(OpValInst))
NextInsts.insert(OpValInst);
}
}
for (auto I : DeadInsts) {
// This will remove this instruction and all its uses.
I->eraseFromParent();
}
NextInsts.swap(DeadInsts);
NextInsts.clear();
}
return true;
}
/// \brief If the given instruction is dead, delete it along with its dead
/// operands.
///
/// \param I The instruction to be deleted.
/// \param Force If Force is set, don't check if the top level instruction is
/// considered dead - delete it regardless.
/// \return Returns true if any instructions were deleted.
bool
swift::recursivelyDeleteTriviallyDeadInstructions(SILInstruction *I,
bool Force) {
return recursivelyDeleteTriviallyDeadInstructions(
ArrayRef<SILInstruction*>(I), Force);
}
void swift::eraseUsesOfInstruction(SILInstruction *Inst) {
for (auto UI : Inst->getUses()) {
auto *User = UI->getUser();
// If the instruction itself has any uses, recursively zap them so that
// nothing uses this instruction.
eraseUsesOfInstruction(User);
// Walk through the operand list and delete any random instructions that
// will become trivially dead when this instruction is removed.
for (auto &Op : User->getAllOperands()) {
if (auto *OpI = dyn_cast<SILInstruction>(Op.get().getDef())) {
// Don't recursively delete the pointer we're getting in.
if (OpI != Inst) {
Op.drop();
recursivelyDeleteTriviallyDeadInstructions(OpI);
}
}
}
User->eraseFromParent();
}
}
void swift::bottomUpCallGraphOrder(SILModule *M,
std::vector<SILFunction*> &order) {
CallGraphSorter<SILFunction*> sorter;
for (auto &Caller : *M)
for (auto &BB : Caller)
for (auto &I : BB)
if (FunctionRefInst *FRI = dyn_cast<FunctionRefInst>(&I)) {
SILFunction *Callee = FRI->getReferencedFunction();
sorter.addEdge(&Caller, Callee);
}
sorter.sort(order);
}
void swift::replaceWithSpecializedFunction(ApplyInst *AI, SILFunction *NewF) {
SILLocation Loc = AI->getLoc();
ArrayRef<Substitution> Subst;
SmallVector<SILValue, 4> Arguments;
for (auto &Op : AI->getArgumentOperands()) {
Arguments.push_back(Op.get());
}
SILBuilder Builder(AI);
FunctionRefInst *FRI = Builder.createFunctionRef(Loc, NewF);
ApplyInst *NAI =
Builder.createApply(Loc, FRI, Arguments, AI->isTransparent());
SILValue(AI, 0).replaceAllUsesWith(SILValue(NAI, 0));
recursivelyDeleteTriviallyDeadInstructions(AI, true);
}
/// \brief Returns True if the operand or one of its users is captured.
static bool useCaptured(Operand *UI) {
auto *User = UI->getUser();
// These instructions do not cause the address to escape.
if (isa<CopyAddrInst>(User) ||
isa<LoadInst>(User) ||
isa<ProtocolMethodInst>(User))
return false;
if (auto *Store = dyn_cast<StoreInst>(User)) {
if (Store->getDest() == UI->get())
return false;
} else if (auto *Assign = dyn_cast<AssignInst>(User)) {
if (Assign->getDest() == UI->get())
return false;
}
return true;
}
bool
swift::canValueEscape(SILValue V) {
for (auto UI : V.getUses()) {
auto *User = UI->getUser();
// These instructions do not cause the address to escape.
if (!useCaptured(UI))
continue;
// These instructions only cause the value to escape if they are used in
// a way that escapes. Recursively check that the uses of the instruction
// don't escape and collect all of the uses of the value.
if (isa<StructElementAddrInst>(User) || isa<TupleElementAddrInst>(User) ||
isa<ProjectExistentialInst>(User) || isa<OpenExistentialInst>(User) ||
isa<MarkUninitializedInst>(User) || isa<AddressToPointerInst>(User) ||
isa<PointerToAddressInst>(User)) {
if (canValueEscape(User))
return true;
continue;
}
// apply instructions do not capture the pointer when it is passed
// indirectly
if (auto apply = dyn_cast<ApplyInst>(User)) {
if (apply->getSubstCalleeType()
->getInterfaceParameters()[UI->getOperandNumber()-1].isIndirect()) {
continue;
}
}
// partial_apply instructions do not allow the pointer to escape
// when it is passed indirectly, unless the partial_apply itself
// escapes
if (auto partialApply = dyn_cast<PartialApplyInst>(User)) {
auto args = partialApply->getArguments();
auto params = partialApply->getSubstCalleeType()
->getInterfaceParameters();
params = params.slice(params.size() - args.size(), args.size());
if (params[UI->getOperandNumber()-1].isIndirect()) {
if (canValueEscape(User))
return true;
continue;
}
}
return true;
}
return false;
}