blob: 7548c4a051fd6fd53e8db108a31fed6e9498bd01 [file] [log] [blame]
//===--- Local.h - Local SIL transformations. -------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SILOPTIMIZER_UTILS_LOCAL_H
#define SWIFT_SILOPTIMIZER_UTILS_LOCAL_H
#include "swift/SILOptimizer/Analysis/ARCAnalysis.h"
#include "swift/SILOptimizer/Analysis/EpilogueARCAnalysis.h"
#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h"
#include "swift/SILOptimizer/Analysis/SimplifyInstruction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILCloner.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/Allocator.h"
#include <functional>
#include <utility>
namespace swift {
class DominanceInfo;
template <class T> class NullablePtr;
/// Transform a Use Range (Operand*) into a User Range (SILInstruction*)
using UserTransform = std::function<SILInstruction *(Operand *)>;
using ValueBaseUserRange =
TransformRange<IteratorRange<ValueBase::use_iterator>, UserTransform>;
inline ValueBaseUserRange makeUserRange(
iterator_range<ValueBase::use_iterator> R) {
auto toUser = [](Operand *O) { return O->getUser(); };
return makeTransformRange(makeIteratorRange(R.begin(), R.end()),
UserTransform(toUser));
}
using DeadInstructionSet = llvm::SmallSetVector<SILInstruction *, 8>;
/// Create a retain of \p Ptr before the \p InsertPt.
NullablePtr<SILInstruction> createIncrementBefore(SILValue Ptr,
SILInstruction *InsertPt);
/// Create a release of \p Ptr before the \p InsertPt.
NullablePtr<SILInstruction> createDecrementBefore(SILValue Ptr,
SILInstruction *InsertPt);
/// For each of the given instructions, if they are dead delete them
/// along with their dead operands.
///
/// \param I The ArrayRef of instructions to be deleted.
/// \param Force If Force is set, don't check if the top level instructions
/// are considered dead - delete them regardless.
/// \param C a callback called whenever an instruction is deleted.
void
recursivelyDeleteTriviallyDeadInstructions(
ArrayRef<SILInstruction*> I, bool Force = false,
llvm::function_ref<void(SILInstruction *)> C = [](SILInstruction *){});
/// For each of the given instructions, if they are dead delete them
/// along with their dead operands.
///
/// \param I The ArrayRef of instructions to be deleted.
/// \param InstIter is updated to the next valid instruction if it points to any
/// deleted instruction, including debug values.
/// \param Force If Force is set, don't check if the top level instructions
/// are considered dead - delete them regardless.
/// \param C a callback called whenever an instruction is deleted.
void recursivelyDeleteTriviallyDeadInstructions(
ArrayRef<SILInstruction *> I, SILBasicBlock::iterator &InstIter,
bool Force = false,
llvm::function_ref<void(SILInstruction *)> C = [](SILInstruction *) {});
/// 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.
/// \param C a callback called whenever an instruction is deleted.
///
/// Returns a valid instruction iterator to the next nondeleted instruction
/// after `I`.
SILBasicBlock::iterator recursivelyDeleteTriviallyDeadInstructions(
SILInstruction *I, bool Force = false,
llvm::function_ref<void(SILInstruction *)> C = [](SILInstruction *) {});
/// Perform a fast local check to see if the instruction is dead.
///
/// This routine only examines the state of the instruction at hand.
bool isInstructionTriviallyDead(SILInstruction *I);
/// Return true if this is a release instruction that's not going to
/// free the object.
bool isIntermediateRelease(SILInstruction *I, EpilogueARCFunctionInfo *ERFI);
/// Recursively collect all the uses and transitive uses of the
/// instruction.
void
collectUsesOfValue(SILValue V, llvm::SmallPtrSetImpl<SILInstruction *> &Insts);
/// Recursively erase all of the uses of the instruction (but not the
/// instruction itself)
void eraseUsesOfInstruction(
SILInstruction *Inst,
llvm::function_ref<void(SILInstruction *)> C = [](SILInstruction *){});
/// Recursively erase all of the uses of the value (but not the
/// value itself)
void eraseUsesOfValue(SILValue V);
FullApplySite findApplyFromDevirtualizedResult(SILValue value);
/// Cast a value into the expected, ABI compatible type if necessary.
/// This may happen e.g. when:
/// - a type of the return value is a subclass of the expected return type.
/// - actual return type and expected return type differ in optionality.
/// - both types are tuple-types and some of the elements need to be casted.
SILValue castValueToABICompatibleType(SILBuilder *B, SILLocation Loc,
SILValue Value,
SILType SrcTy,
SILType DestTy);
/// Peek through trivial Enum initialization, typically for pointless
/// Optionals.
///
/// The returned InitEnumDataAddr dominates the given
/// UncheckedTakeEnumDataAddrInst.
InitEnumDataAddrInst *
findInitAddressForTrivialEnum(UncheckedTakeEnumDataAddrInst *UTEDAI);
/// Returns a project_box if it is the next instruction after \p ABI and
/// and has \p ABI as operand. Otherwise it creates a new project_box right
/// after \p ABI and returns it.
ProjectBoxInst *getOrCreateProjectBox(AllocBoxInst *ABI, unsigned Index);
/// Return true if any call inside the given function may bind dynamic
/// 'Self' to a generic argument of the callee.
bool mayBindDynamicSelf(SILFunction *F);
/// Check whether the \p addr is an address of a tail-allocated array element.
bool isAddressOfArrayElement(SILValue addr);
/// Move an ApplyInst's FuncRef so that it dominates the call site.
void placeFuncRef(ApplyInst *AI, DominanceInfo *DT);
/// Add an argument, \p val, to the branch-edge that is pointing into
/// block \p Dest. Return a new instruction and do not erase the old
/// instruction.
TermInst *addArgumentToBranch(SILValue Val, SILBasicBlock *Dest,
TermInst *Branch);
/// Handle the mechanical aspects of removing an unreachable block.
void removeDeadBlock(SILBasicBlock *BB);
/// Remove all instructions in the body of \p BB in safe manner by using
/// undef.
void clearBlockBody(SILBasicBlock *BB);
/// Get the linkage to be used for specializations of a function with
/// the given linkage.
SILLinkage getSpecializedLinkage(SILFunction *F, SILLinkage L);
/// Tries to optimize a given apply instruction if it is a concatenation of
/// string literals. Returns a new instruction if optimization was possible.
SingleValueInstruction *tryToConcatenateStrings(ApplyInst *AI, SILBuilder &B);
/// Tries to perform jump-threading on all checked_cast_br instruction in
/// function \p Fn.
bool tryCheckedCastBrJumpThreading(SILFunction *Fn, DominanceInfo *DT,
SmallVectorImpl<SILBasicBlock *> &BlocksForWorklist);
/// A structure containing callbacks that are called when an instruction is
/// removed or added.
struct InstModCallbacks {
using CallbackTy = std::function<void (SILInstruction *)>;
CallbackTy DeleteInst = [](SILInstruction *I) {
I->eraseFromParent();
};
CallbackTy CreatedNewInst = [](SILInstruction *){};
InstModCallbacks(CallbackTy DeleteInst, CallbackTy CreatedNewInst)
: DeleteInst(DeleteInst), CreatedNewInst(CreatedNewInst) {}
InstModCallbacks() = default;
~InstModCallbacks() = default;
InstModCallbacks(const InstModCallbacks &) = default;
InstModCallbacks(InstModCallbacks &&) = default;
};
/// If Closure is a partial_apply or thin_to_thick_function with only local
/// ref count users and a set of post-dominating releases:
///
/// 1. Remove all ref count operations and the closure.
/// 2. Add each one of the last release locations insert releases for the
/// captured args if we have a partial_apply.
///
/// In the future this should be extended to be less conservative with users.
bool
tryDeleteDeadClosure(SingleValueInstruction *Closure,
InstModCallbacks Callbacks = InstModCallbacks());
/// Given a SILValue argument to a partial apply \p Arg and the associated
/// parameter info for that argument, perform the necessary cleanups to Arg when
/// one is attempting to delete the partial apply.
void releasePartialApplyCapturedArg(
SILBuilder &Builder, SILLocation Loc, SILValue Arg, SILParameterInfo PInfo,
InstModCallbacks Callbacks = InstModCallbacks());
/// This computes the lifetime of a single SILValue.
///
/// This does not compute a set of jointly postdominating use points. Instead it
/// assumes that the value's existing uses already jointly postdominate the
/// definition. This makes sense for values that are returned +1 from an
/// instruction, like partial_apply, and therefore must be released on all paths
/// via strong_release or apply.
class ValueLifetimeAnalysis {
public:
/// The lifetime frontier for the value. It is the list of instructions
/// following the last uses of the value. All the frontier instructions
/// end the value's lifetime.
typedef llvm::SmallVector<SILInstruction *, 4> Frontier;
/// Constructor for the value \p Def with a specific set of users of Def's
/// users.
ValueLifetimeAnalysis(SILInstruction *Def, ArrayRef<SILInstruction*> UserList) :
DefValue(Def), UserSet(UserList.begin(), UserList.end()) {
propagateLiveness();
}
/// Constructor for the value \p Def considering all the value's uses.
ValueLifetimeAnalysis(SILInstruction *Def) : DefValue(Def) {
for (auto result : Def->getResults()) {
for (Operand *op : result->getUses()) {
UserSet.insert(op->getUser());
}
}
propagateLiveness();
}
enum Mode {
/// Don't split critical edges if the frontier instructions are located on
/// a critical edges. Instead fail.
DontModifyCFG,
/// Split critical edges if the frontier instructions are located on
/// a critical edges.
AllowToModifyCFG,
/// Require that all users must commonly post-dominate the definition. In
/// other words: All paths from the definition to the function exit must
/// contain at least one use. Fail if this is not the case.
UsersMustPostDomDef
};
/// Computes and returns the lifetime frontier for the value in \p Fr.
///
/// Returns true if all instructions in the frontier could be found in
/// non-critical edges.
/// Returns false if some frontier instructions are located on critical edges.
/// In this case, if \p mode is AllowToModifyCFG, those critical edges are
/// split, otherwise nothing is done and the returned \p Fr is not valid.
///
/// If \p deadEndBlocks is provided, all dead-end blocks are ignored. This
/// prevents unreachable-blocks to be included in the frontier.
bool computeFrontier(Frontier &Fr, Mode mode,
DeadEndBlocks *DEBlocks = nullptr);
/// Returns true if the instruction \p Inst is located within the value's
/// lifetime.
/// It is assumed that \p Inst is located after the value's definition.
bool isWithinLifetime(SILInstruction *Inst);
/// Returns true if the value is alive at the begin of block \p BB.
bool isAliveAtBeginOfBlock(SILBasicBlock *BB) {
return LiveBlocks.count(BB) && BB != DefValue->getParent();
}
/// Checks if there is a dealloc_ref inside the value's live range.
bool containsDeallocRef(const Frontier &Frontier);
/// For debug dumping.
void dump() const;
private:
/// The value.
SILInstruction *DefValue;
/// The set of blocks where the value is live.
llvm::SmallSetVector<SILBasicBlock *, 16> LiveBlocks;
/// The set of instructions where the value is used, or the users-list
/// provided with the constructor.
llvm::SmallPtrSet<SILInstruction*, 16> UserSet;
/// Propagates the liveness information up the control flow graph.
void propagateLiveness();
/// Returns the last use of the value in the live block \p BB.
SILInstruction *findLastUserInBlock(SILBasicBlock *BB);
};
/// Clone a single basic block and any required successor edges within the same
/// function.
class BasicBlockCloner : public SILCloner<BasicBlockCloner> {
using SuperTy = SILCloner<BasicBlockCloner>;
friend class SILCloner<BasicBlockCloner>;
protected:
/// The original block to be cloned.
SILBasicBlock *origBB;
public:
/// An ordered list of old to new available value pairs.
///
/// updateSSAAfterCloning() expects this public field to hold values that may
/// be remapped in the cloned block and live out.
SmallVector<std::pair<SILValue, SILValue>, 16> AvailVals;
// Clone blocks starting at `origBB`, within the same function.
BasicBlockCloner(SILBasicBlock *origBB)
: SILCloner(*origBB->getParent()), origBB(origBB) {}
void cloneBlock(SILBasicBlock *insertAfterBB = nullptr) {
SmallVector<SILBasicBlock *, 4> successorBBs;
successorBBs.reserve(origBB->getSuccessors().size());
llvm::copy(origBB->getSuccessors(), std::back_inserter(successorBBs));
cloneReachableBlocks(origBB, successorBBs, insertAfterBB);
}
/// Clone the given branch instruction's destination block, splitting
/// its successors, and rewrite the branch instruction.
void cloneBranchTarget(BranchInst *BI) {
assert(origBB == BI->getDestBB());
cloneBlock(/*insertAfter*/BI->getParent());
SILBuilderWithScope(BI).createBranch(BI->getLoc(), getNewBB(),
BI->getArgs());
BI->eraseFromParent();
}
/// Get the newly cloned block corresponding to `origBB`.
SILBasicBlock *getNewBB() {
return remapBasicBlock(origBB);
}
/// Call this after processing all instructions to fix the control flow
/// graph. The branch cloner may have left critical edges.
bool splitCriticalEdges(DominanceInfo *DT, SILLoopInfo *LI);
protected:
// MARK: CRTP overrides.
/// Override getMappedValue to allow values defined outside the block to be
/// cloned to be reused in the newly cloned block.
SILValue getMappedValue(SILValue Value) {
if (auto SI = Value->getDefiningInstruction()) {
if (!isBlockCloned(SI->getParent()))
return Value;
} else if (auto BBArg = dyn_cast<SILArgument>(Value)) {
if (!isBlockCloned(BBArg->getParent()))
return Value;
} else {
assert(isa<SILUndef>(Value) && "Unexpected Value kind");
return Value;
}
// `value` is not defined outside the cloned block, so consult the cloner's
// map of cloned values.
return SuperTy::getMappedValue(Value);
}
void mapValue(SILValue origValue, SILValue mappedValue) {
SuperTy::mapValue(origValue, mappedValue);
AvailVals.emplace_back(origValue, mappedValue);
}
};
/// Helper function to perform SSA updates in case of jump threading.
void updateSSAAfterCloning(BasicBlockCloner &Cloner, SILBasicBlock *SrcBB,
SILBasicBlock *DestBB);
// Helper class that provides a callback that can be used in
// inliners/cloners for collecting new call sites.
class CloneCollector {
public:
typedef std::pair<SILInstruction *, SILInstruction *> value_type;
typedef std::function<void(SILInstruction *, SILInstruction *)> CallbackType;
typedef std::function<bool (SILInstruction *)> FilterType;
private:
FilterType Filter;
// Pairs of collected instructions; (new, old)
llvm::SmallVector<value_type, 4> InstructionPairs;
void collect(SILInstruction *Old, SILInstruction *New) {
if (Filter(New))
InstructionPairs.push_back(std::make_pair(New, Old));
}
public:
CloneCollector(FilterType Filter) : Filter(Filter) {}
CallbackType getCallback() {
return std::bind(&CloneCollector::collect, this, std::placeholders::_1,
std::placeholders::_2);
}
llvm::SmallVectorImpl<value_type> &getInstructionPairs() {
return InstructionPairs;
}
};
/// This iterator 'looks through' one level of builtin expect users exposing all
/// users of the looked through builtin expect instruction i.e it presents a
/// view that shows all users as if there were no builtin expect instructions
/// interposed.
class IgnoreExpectUseIterator
: public std::iterator<std::forward_iterator_tag, Operand *, ptrdiff_t> {
ValueBaseUseIterator OrigUseChain;
ValueBaseUseIterator CurrentIter;
static BuiltinInst *isExpect(Operand *Use) {
if (auto *BI = dyn_cast<BuiltinInst>(Use->getUser()))
if (BI->getIntrinsicInfo().ID == llvm::Intrinsic::expect)
return BI;
return nullptr;
}
// Advance through expect users to their users until we encounter a user that
// is not an expect.
void advanceThroughExpects() {
while (CurrentIter == OrigUseChain &&
CurrentIter != ValueBaseUseIterator(nullptr)) {
auto *Expect = isExpect(*CurrentIter);
if (!Expect) return;
CurrentIter = Expect->use_begin();
// Expect with no users advance to next item in original use chain.
if (CurrentIter == Expect->use_end())
CurrentIter = ++OrigUseChain;
}
}
public:
IgnoreExpectUseIterator(ValueBase *V)
: OrigUseChain(V->use_begin()), CurrentIter(V->use_begin()) {
advanceThroughExpects();
}
IgnoreExpectUseIterator() = default;
Operand *operator*() const { return *CurrentIter; }
Operand *operator->() const { return *CurrentIter; }
SILInstruction *getUser() const { return CurrentIter->getUser(); }
IgnoreExpectUseIterator &operator++() {
assert(**this && "increment past end()!");
if (OrigUseChain == CurrentIter) {
// Use chain of the original value.
++OrigUseChain;
++CurrentIter;
// Ignore expects.
advanceThroughExpects();
} else {
// Use chain of an expect.
++CurrentIter;
if (CurrentIter == ValueBaseUseIterator(nullptr)) {
// At the end of the use chain of an expect.
CurrentIter = ++OrigUseChain;
advanceThroughExpects();
}
}
return *this;
}
IgnoreExpectUseIterator operator++(int unused) {
IgnoreExpectUseIterator Copy = *this;
++*this;
return Copy;
}
friend bool operator==(IgnoreExpectUseIterator lhs,
IgnoreExpectUseIterator rhs) {
return lhs.CurrentIter == rhs.CurrentIter;
}
friend bool operator!=(IgnoreExpectUseIterator lhs,
IgnoreExpectUseIterator rhs) {
return !(lhs == rhs);
}
};
inline iterator_range<IgnoreExpectUseIterator>
ignore_expect_uses(ValueBase *V) {
return make_range(IgnoreExpectUseIterator(V),
IgnoreExpectUseIterator());
}
/// Run simplifyInstruction() on all of the instruction I's users if they only
/// have one result (since simplifyInstruction assumes that). Replace all uses
/// of the user with its simplification of we succeed. Returns true if we
/// succeed and false otherwise.
///
/// An example of how this is useful is in cases where one is splitting up an
/// aggregate and reforming it, the reformed aggregate may have extract
/// operations from it. These can be simplified and removed.
bool simplifyUsers(SingleValueInstruction *I);
/// True if a type can be expanded
/// without a significant increase to code size.
bool shouldExpand(SILModule &Module, SILType Ty);
/// Check if a given type is a simple type, i.e. a builtin
/// integer or floating point type or a struct/tuple whose members
/// are of simple types.
bool isSimpleType(SILType SILTy, SILModule& Module);
/// Check if the value of V is computed by means of a simple initialization.
/// Store the actual SILValue into \p Val and the reversed list of instructions
/// initializing it in \p Insns.
/// The check is performed by recursively walking the computation of the
/// SIL value being analyzed.
bool analyzeStaticInitializer(SILValue V,
SmallVectorImpl<SILInstruction *> &Insns);
/// Replace load sequence which may contain
/// a chain of struct_element_addr followed by a load.
/// The sequence is traversed inside out, i.e.
/// starting with the innermost struct_element_addr
void replaceLoadSequence(SILInstruction *I,
SILValue Value,
SILBuilder &B);
/// Do we have enough information to determine all callees that could
/// be reached by calling the function represented by Decl?
bool calleesAreStaticallyKnowable(SILModule &M, SILDeclRef Decl);
// Attempt to get the instance for S, whose static type is the same as
// its exact dynamic type, returning a null SILValue() if we cannot find it.
// The information that a static type is the same as the exact dynamic,
// can be derived e.g.:
// - from a constructor or
// - from a successful outcome of a checked_cast_br [exact] instruction.
SILValue getInstanceWithExactDynamicType(SILValue S, SILModule &M,
ClassHierarchyAnalysis *CHA);
/// Try to determine the exact dynamic type of an object.
/// returns the exact dynamic type of the object, or an empty type if the exact
/// type could not be determined.
SILType getExactDynamicType(SILValue S, SILModule &M,
ClassHierarchyAnalysis *CHA,
bool ForUnderlyingObject = false);
/// Try to statically determine the exact dynamic type of the underlying object.
/// returns the exact dynamic type of the underlying object, or an empty SILType
/// if the exact type could not be determined.
SILType getExactDynamicTypeOfUnderlyingObject(SILValue S, SILModule &M,
ClassHierarchyAnalysis *CHA);
/// Utility class for cloning init values into the static initializer of a
/// SILGlobalVariable.
class StaticInitCloner : public SILCloner<StaticInitCloner> {
friend class SILInstructionVisitor<StaticInitCloner>;
friend class SILCloner<StaticInitCloner>;
/// The number of not yet cloned operands for each instruction.
llvm::DenseMap<SILInstruction *, int> NumOpsToClone;
/// List of instructions for which all operands are already cloned (or which
/// don't have any operands).
llvm::SmallVector<SILInstruction *, 8> ReadyToClone;
public:
StaticInitCloner(SILGlobalVariable *GVar)
: SILCloner<StaticInitCloner>(GVar) { }
/// Add \p InitVal and all its operands (transitively) for cloning.
///
/// Note: all init values must are added, before calling clone().
void add(SILInstruction *InitVal);
/// Clone \p InitVal and all its operands into the initializer of the
/// SILGlobalVariable.
///
/// \return Returns the cloned instruction in the SILGlobalVariable.
SingleValueInstruction *clone(SingleValueInstruction *InitVal);
/// Convenience function to clone a single \p InitVal.
static void appendToInitializer(SILGlobalVariable *GVar,
SingleValueInstruction *InitVal) {
StaticInitCloner Cloner(GVar);
Cloner.add(InitVal);
Cloner.clone(InitVal);
}
protected:
SILLocation remapLocation(SILLocation Loc) {
return ArtificialUnreachableLocation();
}
};
/// Move only data structure that is the result of findLocalApplySite.
///
/// NOTE: Generally it is not suggested to have move only types that contain
/// small vectors. Since our small vectors contain one element or a std::vector
/// like data structure , this is ok since we will either just copy the single
/// element when we do the move or perform a move of the vector type.
struct LLVM_LIBRARY_VISIBILITY FindLocalApplySitesResult {
/// Contains the list of local non fully applied partial apply sites that we
/// found.
SmallVector<ApplySite, 1> partialApplySites;
/// Contains the list of full apply sites that we found.
SmallVector<FullApplySite, 1> fullApplySites;
/// Set to true if the function_ref escapes into a use that our analysis does
/// not understand. Set to false if we found a use that had an actual
/// escape. Set to None if we did not find any call sites, but also didn't
/// find any "escaping uses" as well.
///
/// The none case is so that we can distinguish in between saying that a value
/// did escape and saying that we did not find any conservative information.
bool escapes;
FindLocalApplySitesResult() = default;
FindLocalApplySitesResult(const FindLocalApplySitesResult &) = delete;
FindLocalApplySitesResult &
operator=(const FindLocalApplySitesResult &) = delete;
FindLocalApplySitesResult(FindLocalApplySitesResult &&) = default;
FindLocalApplySitesResult &operator=(FindLocalApplySitesResult &&) = default;
~FindLocalApplySitesResult() = default;
/// Treat this function ref as escaping only if we found an actual user we
/// didn't understand. Do not treat it as escaping if we did not find any
/// users at all.
bool isEscaping() const { return escapes; }
};
/// Returns .some(FindLocalApplySitesResult) if we found any interesting
/// information for the given function_ref. Otherwise, returns None.
///
/// We consider "interesting information" to mean inclusively that:
///
/// 1. We discovered that the function_ref never escapes.
/// 2. We were able to find either a partial apply or a full apply site.
Optional<FindLocalApplySitesResult>
findLocalApplySites(FunctionRefBaseInst *FRI);
} // end namespace swift
#endif