diff --git a/include/swift/SIL/OptimizationRemark.h b/include/swift/SIL/OptimizationRemark.h index f5c74888dcc..5accdbc2e76 100644 --- a/include/swift/SIL/OptimizationRemark.h +++ b/include/swift/SIL/OptimizationRemark.h @@ -157,9 +157,9 @@ public: using RemarkT = decltype(RemarkBuilder()); // Avoid building the remark unless remarks are enabled. if (isEnabled() || Module.getOptRecordStream()) { - auto R = RemarkBuilder(); - R.setPassName(PassName); - emit(R); + auto rb = RemarkBuilder(); + rb.setPassName(PassName); + emit(rb); } } diff --git a/include/swift/SIL/SILGlobalVariable.h b/include/swift/SIL/SILGlobalVariable.h index 0684c4832f2..eedc850458e 100644 --- a/include/swift/SIL/SILGlobalVariable.h +++ b/include/swift/SIL/SILGlobalVariable.h @@ -17,7 +17,6 @@ #ifndef SWIFT_SIL_SILGLOBALVARIABLE_H #define SWIFT_SIL_SILGLOBALVARIABLE_H -#include #include "swift/SIL/SILLinkage.h" #include "swift/SIL/SILLocation.h" #include "swift/SIL/SILBasicBlock.h" diff --git a/include/swift/SIL/SILInstructionWorklist.h b/include/swift/SIL/SILInstructionWorklist.h index af43d47bf4a..36af8225211 100644 --- a/include/swift/SIL/SILInstructionWorklist.h +++ b/include/swift/SIL/SILInstructionWorklist.h @@ -33,7 +33,7 @@ #include "swift/Basic/BlotSetVector.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILValue.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" diff --git a/include/swift/SIL/TypeSubstCloner.h b/include/swift/SIL/TypeSubstCloner.h index 5bca456a3f4..3bbb363945a 100644 --- a/include/swift/SIL/TypeSubstCloner.h +++ b/include/swift/SIL/TypeSubstCloner.h @@ -21,10 +21,10 @@ #include "swift/AST/GenericEnvironment.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/Type.h" -#include "swift/SIL/SILCloner.h" #include "swift/SIL/DynamicCasts.h" +#include "swift/SIL/SILCloner.h" #include "swift/SIL/SILFunctionBuilder.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SpecializationMangler.h" #include "llvm/Support/Debug.h" diff --git a/include/swift/SILOptimizer/Analysis/CFG.h b/include/swift/SILOptimizer/Analysis/CFG.h deleted file mode 100644 index 2f8b195b1e0..00000000000 --- a/include/swift/SILOptimizer/Analysis/CFG.h +++ /dev/null @@ -1,50 +0,0 @@ -//===--- CFG.h - Routines which analyze the CFG of a function ---*- 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_ANALYSIS_CFG_H -#define SWIFT_SILOPTIMIZER_ANALYSIS_CFG_H - -namespace llvm { - -template class TinyPtrVector; - -} // end namespace llvm - -namespace swift { - -class SILFunction; -class SILBasicBlock; - -/// Return true if we conservatively find all BB's that are non-failure exit -/// basic blocks and place them in \p BBs. If we find something we don't -/// understand, bail. -/// -/// A non-failure exit BB is defined as a BB that: -/// -/// 1. Has a return terminator. -/// 2. unreachable + noreturn terminator sequence. -/// 3. has a throw terminator. -/// -/// If we just have an unreachable without a noreturn call before it, we must -/// have a failure BB. -/// -/// We use a TinyPtrVector since in most cases this will only return one -/// SILBasicBlock since non-failure noreturn functions should not occur often -/// implying in most cases this will be one element. -/// -/// TODO: -bool findAllNonFailureExitBBs(SILFunction *F, - llvm::TinyPtrVector &BBs); - -} // end namespace swift - -#endif diff --git a/include/swift/SILOptimizer/Analysis/CallerAnalysis.h b/include/swift/SILOptimizer/Analysis/CallerAnalysis.h index b23570c2e49..b2a722f3ed6 100644 --- a/include/swift/SILOptimizer/Analysis/CallerAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/CallerAnalysis.h @@ -17,7 +17,7 @@ #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILModule.h" #include "swift/SILOptimizer/Analysis/Analysis.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallSet.h" diff --git a/include/swift/SILOptimizer/Utils/BasicBlockOptUtils.h b/include/swift/SILOptimizer/Utils/BasicBlockOptUtils.h new file mode 100644 index 00000000000..2d0bb0e4578 --- /dev/null +++ b/include/swift/SILOptimizer/Utils/BasicBlockOptUtils.h @@ -0,0 +1,260 @@ +//===--- BasicBlockOptUtils.h - SIL basic block utilities -------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 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 +// +//===----------------------------------------------------------------------===// +/// +/// Utilities used by the SILOptimizer for analyzing and operating on whole +/// basic blocks, including as removal, cloning, and SSA update. +/// +/// CFGOptUtils.h provides lower-level CFG branch and edge utilities. +/// +/// SIL/BasicBlockUtils.h provides essential SILBasicBlock utilities. +/// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SILOPTIMIZER_UTILS_BASICBLOCKOPTUTILS_H +#define SWIFT_SILOPTIMIZER_UTILS_BASICBLOCKOPTUTILS_H + +#include "swift/SIL/SILInstruction.h" +#include "swift/SIL/SILBasicBlock.h" +#include "swift/SIL/SILCloner.h" + +namespace swift { + +class BasicBlockCloner; +class SILLoop; +class SILLoopInfo; + +/// Remove all instructions in the body of \p bb in safe manner by using +/// undef. +void clearBlockBody(SILBasicBlock *bb); + +/// Handle the mechanical aspects of removing an unreachable block. +void removeDeadBlock(SILBasicBlock *bb); + +/// Remove all unreachable blocks in a function. +bool removeUnreachableBlocks(SILFunction &f); + +/// Return true if there are any users of v outside the specified block. +inline bool isUsedOutsideOfBlock(SILValue v) { + auto *bb = v->getParentBlock(); + for (auto *use : v->getUses()) + if (use->getUser()->getParent() != bb) + return true; + return false; +} + +/// Rotate a loop's header as long as it is exiting and not equal to the +/// passed basic block. +/// If \p RotateSingleBlockLoops is true a single basic block loop will be +/// rotated once. ShouldVerify specifies whether to perform verification after +/// the transformation. +/// Returns true if the loop could be rotated. +bool rotateLoop(SILLoop *loop, DominanceInfo *domInfo, SILLoopInfo *loopInfo, + bool rotateSingleBlockLoops, SILBasicBlock *upToBB, + bool shouldVerify); + +/// Helper function to perform SSA updates in case of jump threading. +void updateSSAAfterCloning(BasicBlockCloner &cloner, SILBasicBlock *srcBB, + SILBasicBlock *destBB); + +/// Clone a single basic block and any required successor edges within the same +/// function. +class BasicBlockCloner : public SILCloner { + using SuperTy = SILCloner; + friend class SILCloner; + +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, 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 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 *domInfo, SILLoopInfo *loopInfo); + +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(value)) { + if (!isBlockCloned(bbArg->getParent())) + return value; + } else { + assert(isa(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 class that provides a callback that can be used in +// inliners/cloners for collecting new call sites. +class CloneCollector { +public: + typedef std::pair value_type; + typedef std::function CallbackType; + typedef std::function FilterType; + +private: + FilterType filter; + + // Pairs of collected instructions; (new, old) + llvm::SmallVector instructionpairs; + + void collect(SILInstruction *oldI, SILInstruction *newI) { + if (filter(newI)) + instructionpairs.push_back(std::make_pair(newI, oldI)); + } + +public: + CloneCollector(FilterType filter) : filter(filter) {} + + CallbackType getCallback() { + return std::bind(&CloneCollector::collect, this, std::placeholders::_1, + std::placeholders::_2); + } + + llvm::SmallVectorImpl &getInstructionPairs() { + return instructionpairs; + } +}; + +/// Sink address projections to their out-of-block uses. This is +/// required after cloning a block and before calling +/// updateSSAAfterCloning to avoid address-type phis. +/// +/// This clones address projections at their use points, but does not +/// mutate the block containing the projections. +class SinkAddressProjections { + // Projections ordered from last to first in the chain. + SmallVector projections; + SmallSetVector inBlockDefs; + +public: + /// Check for an address projection chain ending at \p inst. Return true if + /// the given instruction is successfully analyzed. + /// + /// If \p inst does not produce an address, then return + /// true. getInBlockDefs() will contain \p inst if any of its + /// (non-address) values are used outside its block. + /// + /// If \p inst does produce an address, return true only of the + /// chain of address projections within this block is clonable at + /// their use sites. getInBlockDefs will return all non-address + /// operands in the chain that are also defined in this block. These + /// may require phis after cloning the projections. + bool analyzeAddressProjections(SILInstruction *inst); + + /// After analyzing projections, returns the list of (non-address) values + /// defined in the same block as the projections which will have uses outside + /// the block after cloning. + ArrayRef getInBlockDefs() const { + return inBlockDefs.getArrayRef(); + } + /// Clone the chain of projections at their use sites. + /// + /// Return true if anything was done. + /// + /// getInBlockProjectionOperandValues() can be called before or after cloning. + bool cloneProjections(); +}; + +/// Utility class for cloning init values into the static initializer of a +/// SILGlobalVariable. +class StaticInitCloner : public SILCloner { + friend class SILInstructionVisitor; + friend class SILCloner; + + /// The number of not yet cloned operands for each instruction. + llvm::DenseMap numOpsToClone; + + /// List of instructions for which all operands are already cloned (or which + /// don't have any operands). + llvm::SmallVector readyToClone; + +public: + StaticInitCloner(SILGlobalVariable *gVar) + : SILCloner(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(); + } +}; + +} // namespace swift + +#endif diff --git a/include/swift/SILOptimizer/Utils/CFG.h b/include/swift/SILOptimizer/Utils/CFGOptUtils.h similarity index 56% rename from include/swift/SILOptimizer/Utils/CFG.h rename to include/swift/SILOptimizer/Utils/CFGOptUtils.h index ceaea27b91f..9c3f8189ff7 100644 --- a/include/swift/SILOptimizer/Utils/CFG.h +++ b/include/swift/SILOptimizer/Utils/CFGOptUtils.h @@ -1,20 +1,34 @@ -//===--- CFG.h - Utilities for SIL CFG transformations ----------*- C++ -*-===// +//===--- CFGOptUtils.h - SIL CFG edge utilities -----------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2019 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 // //===----------------------------------------------------------------------===// +/// +/// APIs used by the SILOptimizer for low-level branch and CFG edge analysis +/// and operations. These may merge blocks, split blocks, or create empty +/// blocks, but don't duplicate whole blocks. +/// +/// Essential CFG utilities are in SIL/CFG.h. +/// +/// Whole block-level transformations are in BasicBlockOptUtils.h. +/// +//===----------------------------------------------------------------------===// -#ifndef SWIFT_SILOPTIMIZER_UTILS_CFG_H -#define SWIFT_SILOPTIMIZER_UTILS_CFG_H +#ifndef SWIFT_SILOPTIMIZER_UTILS_CFGOPTUTILS_H +#define SWIFT_SILOPTIMIZER_UTILS_CFGOPTUTILS_H -#include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILBuilder.h" +#include "swift/SIL/SILInstruction.h" + +namespace llvm { +template class TinyPtrVector; +} namespace swift { @@ -25,25 +39,25 @@ class SILLoopInfo; /// Adds a new argument to an edge between a branch and a destination /// block. /// -/// \param Branch The terminator to add the argument to. -/// \param Dest The destination block of the edge. -/// \param Val The value to the arguments of the branch. +/// \param branch The terminator to add the argument to. +/// \param dest The destination block of the edge. +/// \param val The value to the arguments of the branch. /// \return The created branch. The old branch is deleted. /// The argument is appended at the end of the argument tuple. -TermInst *addNewEdgeValueToBranch(TermInst *Branch, SILBasicBlock *Dest, - SILValue Val); +TermInst *addNewEdgeValueToBranch(TermInst *branch, SILBasicBlock *dest, + SILValue val); /// Changes the edge value between a branch and destination basic block /// at the specified index. Changes all edges from \p Branch to \p Dest to carry /// the value. /// -/// \param Branch The branch to modify. -/// \param Dest The destination of the edge. -/// \param Idx The index of the argument to modify. -/// \param Val The new value to use. +/// \param branch The branch to modify. +/// \param dest The destination of the edge. +/// \param idx The index of the argument to modify. +/// \param val The new value to use. /// \return The new branch. Deletes the old one. -TermInst *changeEdgeValue(TermInst *Branch, SILBasicBlock *Dest, size_t Idx, - SILValue Val); +TermInst *changeEdgeValue(TermInst *branch, SILBasicBlock *dest, size_t idx, + SILValue val); /// Deletes the edge value between a branch and a destination basic block at the /// specified index. Asserts internally that the argument along the edge does @@ -59,24 +73,24 @@ void erasePhiArgument(SILBasicBlock *block, unsigned argIndex); /// Replace a branch target. /// -/// \param T The terminating instruction to modify. -/// \param OldDest The successor block that will be replaced. -/// \param NewDest The new target block. -/// \param PreserveArgs If set, preserve arguments on the replaced edge. -void replaceBranchTarget(TermInst *T, SILBasicBlock *OldDest, - SILBasicBlock *NewDest, bool PreserveArgs); +/// \param t The terminating instruction to modify. +/// \param oldDest The successor block that will be replaced. +/// \param newDest The new target block. +/// \param preserveArgs If set, preserve arguments on the replaced edge. +void replaceBranchTarget(TermInst *t, SILBasicBlock *oldDest, + SILBasicBlock *newDest, bool preserveArgs); /// Check if the edge from the terminator is critical. -bool isCriticalEdge(TermInst *T, unsigned EdgeIdx); +bool isCriticalEdge(TermInst *t, unsigned edgeIdx); /// Splits the edge from terminator if it is critical. /// /// Updates dominance information and loop information if not null. /// Returns the newly created basic block on success or nullptr otherwise (if /// the edge was not critical). -SILBasicBlock *splitCriticalEdge(TermInst *T, unsigned EdgeIdx, - DominanceInfo *DT = nullptr, - SILLoopInfo *LI = nullptr); +SILBasicBlock *splitCriticalEdge(TermInst *, unsigned edgeIdx, + DominanceInfo *domInfo = nullptr, + SILLoopInfo *loopInfo = nullptr); /// Splits the critical edges between from and to. This code assumes there is /// exactly one edge between the two basic blocks. It will return the wrong @@ -84,45 +98,39 @@ SILBasicBlock *splitCriticalEdge(TermInst *T, unsigned EdgeIdx, /// between the two blocks. /// /// Updates dominance information and loop information if not null. -SILBasicBlock *splitIfCriticalEdge(SILBasicBlock *From, SILBasicBlock *To, - DominanceInfo *DT = nullptr, - SILLoopInfo *LI = nullptr); +SILBasicBlock *splitIfCriticalEdge(SILBasicBlock *from, SILBasicBlock *to, + DominanceInfo *domInfo = nullptr, + SILLoopInfo *loopInfo = nullptr); /// Splits all critical edges originating from `fromBB`. -bool splitCriticalEdgesFrom(SILBasicBlock *fromBB, DominanceInfo *DT = nullptr, - SILLoopInfo *LI = nullptr); +bool splitCriticalEdgesFrom(SILBasicBlock *fromBB, + DominanceInfo *domInfo = nullptr, + SILLoopInfo *loopInfo = nullptr); /// Splits the edges between two basic blocks. /// /// Updates dominance information and loop information if not null. -void splitEdgesFromTo(SILBasicBlock *From, SILBasicBlock *To, - DominanceInfo *DT = nullptr, SILLoopInfo *LI = nullptr); - -/// Rotate a loop's header as long as it is exiting and not equal to the -/// passed basic block. -/// If \p RotateSingleBlockLoops is true a single basic block loop will be -/// rotated once. ShouldVerify specifies whether to perform verification after -/// the transformation. -/// Returns true if the loop could be rotated. -bool rotateLoop(SILLoop *L, DominanceInfo *DT, SILLoopInfo *LI, - bool RotateSingleBlockLoops, SILBasicBlock *UpTo, - bool ShouldVerify); +void splitEdgesFromTo(SILBasicBlock *from, SILBasicBlock *to, + DominanceInfo *domInfo = nullptr, + SILLoopInfo *loopInfo = nullptr); /// Splits the basic block before the instruction with an unconditional branch /// and updates the dominator tree and loop info. Returns the new, branched to /// block that contains the end of \p SplitBeforeInst's block. -SILBasicBlock *splitBasicBlockAndBranch(SILBuilder &B, - SILInstruction *SplitBeforeInst, - DominanceInfo *DT, SILLoopInfo *LI); +SILBasicBlock *splitBasicBlockAndBranch(SILBuilder &builder, + SILInstruction *splitBeforeInst, + DominanceInfo *domInfo, + SILLoopInfo *loopInfo); /// Return true if the function has a critical edge, false otherwise. -bool hasCriticalEdges(SILFunction &F, bool OnlyNonCondBr); +bool hasCriticalEdges(SILFunction &f, bool onlyNonCondBr); /// Split all critical edges in the given function, updating the /// dominator tree and loop information if they are provided. /// /// FIXME: This should never be called! Fix passes that create critical edges. -bool splitAllCriticalEdges(SILFunction &F, DominanceInfo *DT, SILLoopInfo *LI); +bool splitAllCriticalEdges(SILFunction &F, DominanceInfo *domInfo, + SILLoopInfo *loopInfo); /// Split all cond_br critical edges with non-trivial arguments in the /// function updating the dominator tree and loop information (if they are not @@ -130,15 +138,15 @@ bool splitAllCriticalEdges(SILFunction &F, DominanceInfo *DT, SILLoopInfo *LI); /// /// A current invariant of Ownership SIL is that cond_br can only have critical /// edges with non-trivial arguments. This simplifies computation. -bool splitAllCondBrCriticalEdgesWithNonTrivialArgs(SILFunction &Fn, - DominanceInfo *DT, - SILLoopInfo *LI); +bool splitAllCondBrCriticalEdgesWithNonTrivialArgs(SILFunction &fn, + DominanceInfo *domInfo, + SILLoopInfo *loopInfo); /// Merge a basic block ending in a branch with its successor /// if possible. If dominance information or loop info is non null update it. /// Return true if block was merged. -bool mergeBasicBlockWithSuccessor(SILBasicBlock *BB, DominanceInfo *DT, - SILLoopInfo *LI); +bool mergeBasicBlockWithSuccessor(SILBasicBlock *bb, DominanceInfo *domInfo, + SILLoopInfo *loopInfo); /// Merge basic blocks in the given function by eliminating all unconditional /// branches to single-predecessor branch targets. @@ -148,7 +156,7 @@ bool mergeBasicBlockWithSuccessor(SILBasicBlock *BB, DominanceInfo *DT, /// is not done on-the-fly after splitting blocks because merging is linear in /// the number of instructions, so interleaved merging and splitting is /// quadratic. -bool mergeBasicBlocks(SILFunction *F); +bool mergeBasicBlocks(SILFunction *f); /// Given a list of \p UserBlocks and a list of \p DefBlocks, find a set of /// blocks that together with \p UserBlocks joint-postdominate \p @@ -177,11 +185,29 @@ bool mergeBasicBlocks(SILFunction *F); /// /// *NOTE* This completion may not be unique. void completeJointPostDominanceSet( - ArrayRef UserBlocks, ArrayRef DefBlocks, - llvm::SmallVectorImpl &Completion); + ArrayRef userBlocks, ArrayRef defBlocks, + llvm::SmallVectorImpl &completion); -/// Remove all unreachable blocks in a function. -bool removeUnreachableBlocks(SILFunction &Fn); +/// Return true if we conservatively find all bb's that are non-failure exit +/// basic blocks and place them in \p bbs. If we find something we don't +/// understand, bail. +/// +/// A non-failure exit BB is defined as a BB that: +/// +/// 1. Has a return terminator. +/// 2. unreachable + noreturn terminator sequence. +/// 3. has a throw terminator. +/// +/// If we just have an unreachable without a noreturn call before it, we must +/// have a failure BB. +/// +/// We use a TinyPtrVector since in most cases this will only return one +/// SILBasicBlock since non-failure noreturn functions should not occur often +/// implying in most cases this will be one element. +/// +/// TODO: +bool findAllNonFailureExitBBs(SILFunction *f, + llvm::TinyPtrVector &bbs); } // end namespace swift diff --git a/include/swift/SILOptimizer/Utils/Devirtualize.h b/include/swift/SILOptimizer/Utils/Devirtualize.h index d99810f951c..6301c64725e 100644 --- a/include/swift/SILOptimizer/Utils/Devirtualize.h +++ b/include/swift/SILOptimizer/Utils/Devirtualize.h @@ -27,7 +27,7 @@ #include "swift/SIL/SILType.h" #include "swift/SIL/SILValue.h" #include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/ArrayRef.h" namespace swift { diff --git a/include/swift/SILOptimizer/Utils/GenericCloner.h b/include/swift/SILOptimizer/Utils/GenericCloner.h index 1c54bdecf16..ea0d3aa617d 100644 --- a/include/swift/SILOptimizer/Utils/GenericCloner.h +++ b/include/swift/SILOptimizer/Utils/GenericCloner.h @@ -22,7 +22,7 @@ #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/TypeSubstCloner.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" #include "swift/SILOptimizer/Utils/Generics.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" diff --git a/include/swift/SILOptimizer/Utils/Generics.h b/include/swift/SILOptimizer/Utils/Generics.h index 3c78e3c6a1a..50c80b51578 100644 --- a/include/swift/SILOptimizer/Utils/Generics.h +++ b/include/swift/SILOptimizer/Utils/Generics.h @@ -20,7 +20,7 @@ #include "swift/AST/SubstitutionMap.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" diff --git a/include/swift/SILOptimizer/Utils/InstOptUtils.h b/include/swift/SILOptimizer/Utils/InstOptUtils.h new file mode 100644 index 00000000000..15c5f82089d --- /dev/null +++ b/include/swift/SILOptimizer/Utils/InstOptUtils.h @@ -0,0 +1,390 @@ +//===--- InstOptUtils.h - SILOptimizer instruction utilities ----*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 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 +// +//===----------------------------------------------------------------------===// +/// +/// Utilities used by the SILOptimizer for analyzing and transforming +/// SILInstructions. +/// +/// SIL/InstUtils.h provides essential SILInstruction utilities. +/// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SILOPTIMIZER_UTILS_INSTOPTUTILS_H +#define SWIFT_SILOPTIMIZER_UTILS_INSTOPTUTILS_H + +#include "swift/SIL/SILBuilder.h" +#include "swift/SIL/SILInstruction.h" +#include "swift/SILOptimizer/Analysis/ARCAnalysis.h" +#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h" +#include "swift/SILOptimizer/Analysis/EpilogueARCAnalysis.h" +#include "swift/SILOptimizer/Analysis/SimplifyInstruction.h" +#include "llvm/ADT/SmallPtrSet.h" +#include +#include + +namespace swift { + +class DominanceInfo; +template class NullablePtr; + +/// Transform a Use Range (Operand*) into a User Range (SILInstruction*) +using UserTransform = std::function; +using ValueBaseUserRange = + TransformRange, UserTransform>; + +inline ValueBaseUserRange +makeUserRange(iterator_range range) { + auto toUser = [](Operand *operand) { return operand->getUser(); }; + return makeTransformRange(makeIteratorRange(range.begin(), range.end()), + UserTransform(toUser)); +} + +using DeadInstructionSet = llvm::SmallSetVector; + +/// Create a retain of \p Ptr before the \p InsertPt. +NullablePtr createIncrementBefore(SILValue ptr, + SILInstruction *insertpt); + +/// Create a release of \p Ptr before the \p InsertPt. +NullablePtr createDecrementBefore(SILValue ptr, + SILInstruction *insertpt); + +/// For each of the given instructions, if they are dead delete them +/// along with their dead operands. +/// +/// \param inst 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 callback a callback called whenever an instruction is deleted. +void recursivelyDeleteTriviallyDeadInstructions( + ArrayRef inst, bool force = false, + llvm::function_ref callback = [](SILInstruction *) { + }); + +/// If the given instruction is dead, delete it along with its dead +/// operands. +/// +/// \param inst 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 callback a callback called whenever an instruction is deleted. +void recursivelyDeleteTriviallyDeadInstructions( + SILInstruction *inst, bool force = false, + llvm::function_ref callback = [](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 *inst); + +/// Return true if this is a release instruction that's not going to +/// free the object. +bool isIntermediateRelease(SILInstruction *inst, EpilogueARCFunctionInfo *erfi); + +/// Recursively collect all the uses and transitive uses of the +/// instruction. +void collectUsesOfValue(SILValue V, + llvm::SmallPtrSetImpl &Insts); + +/// Recursively erase all of the uses of the instruction (but not the +/// instruction itself) +void eraseUsesOfInstruction( + SILInstruction *inst, llvm::function_ref callback = + [](SILInstruction *) {}); + +/// Recursively erase all of the uses of the value (but not the +/// value itself) +void eraseUsesOfValue(SILValue value); + +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 *builder, 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); + +/// Get the linkage to be used for specializations of a function with +/// the given linkage. +SILLinkage getSpecializedLinkage(SILFunction *f, SILLinkage linkage); + +/// 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 &builder); + +/// Tries to perform jump-threading on all checked_cast_br instruction in +/// function \p Fn. +bool tryCheckedCastBrJumpThreading( + SILFunction *fn, DominanceInfo *dt, + SmallVectorImpl &blocksForWorklist); + +/// A structure containing callbacks that are called when an instruction is +/// removed or added. +struct InstModCallbacks { + using CallbackTy = std::function; + CallbackTy deleteInst = [](SILInstruction *inst) { inst->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 paramInfo, + InstModCallbacks callbacks = InstModCallbacks()); + +/// Insert destroys of captured arguments of partial_apply [stack]. +void insertDestroyOfCapturedArguments( + PartialApplyInst *pai, SILBuilder &builder, + llvm::function_ref shouldInsertDestroy = + [](SILValue arg) -> bool { return true; }); + +/// 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 { + ValueBaseUseIterator origUseChain; + ValueBaseUseIterator currentIter; + + static BuiltinInst *isExpect(Operand *use) { + if (auto *bi = dyn_cast(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 *value) + : origUseChain(value->use_begin()), currentIter(value->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 +ignore_expect_uses(ValueBase *value) { + return make_range(IgnoreExpectUseIterator(value), 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 *inst); + +/// True if a type can be expanded +/// without a significant increase to code size. +bool shouldExpand(SILModule &module, SILType ty); + +/// Check if the value of value 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 value, + SmallVectorImpl &insns); + +/// Returns true if the below operation will succeed. +bool canReplaceLoadSequence(SILInstruction *inst); + +/// 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 *inst, SILValue value); + +/// Do we have enough information to determine all callees that could +/// be reached by calling the function represented by Decl? +bool calleesAreStaticallyKnowable(SILModule &module, SILDeclRef decl); + +// Attempt to get the instance for , 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 instance, + 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 instance, 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 instance, + ClassHierarchyAnalysis *cha); + +// 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 partialApplySites; + + /// Contains the list of full apply sites that we found. + SmallVector 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 +findLocalApplySites(FunctionRefBaseInst *fri); + +} // end namespace swift + +#endif diff --git a/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h b/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h index 5613af10681..f11fbcd3042 100644 --- a/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h +++ b/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h @@ -33,7 +33,7 @@ #include "swift/SILOptimizer/Analysis/EscapeAnalysis.h" #include "swift/SILOptimizer/Analysis/TypeExpansionAnalysis.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Hashing.h" diff --git a/include/swift/SILOptimizer/Utils/Local.h b/include/swift/SILOptimizer/Utils/Local.h deleted file mode 100644 index c7a33d8afa0..00000000000 --- a/include/swift/SILOptimizer/Utils/Local.h +++ /dev/null @@ -1,684 +0,0 @@ -//===--- 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 -#include - -namespace swift { - -class DominanceInfo; -template class NullablePtr; - -/// Transform a Use Range (Operand*) into a User Range (SILInstruction*) -using UserTransform = std::function; -using ValueBaseUserRange = - TransformRange, UserTransform>; - -inline ValueBaseUserRange makeUserRange( - iterator_range R) { - auto toUser = [](Operand *O) { return O->getUser(); }; - return makeTransformRange(makeIteratorRange(R.begin(), R.end()), - UserTransform(toUser)); -} - -using DeadInstructionSet = llvm::SmallSetVector; - -/// Create a retain of \p Ptr before the \p InsertPt. -NullablePtr createIncrementBefore(SILValue Ptr, - SILInstruction *InsertPt); - -/// Create a release of \p Ptr before the \p InsertPt. -NullablePtr 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 I, bool Force = false, - llvm::function_ref 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. -void recursivelyDeleteTriviallyDeadInstructions( - SILInstruction *I, bool Force = false, - llvm::function_ref 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 &Insts); - -/// Recursively erase all of the uses of the instruction (but not the -/// instruction itself) -void eraseUsesOfInstruction( - SILInstruction *Inst, - llvm::function_ref 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 &BlocksForWorklist); - -/// A structure containing callbacks that are called when an instruction is -/// removed or added. -struct InstModCallbacks { - using CallbackTy = std::function; - 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()); - -/// Insert destroys of captured arguments of partial_apply [stack]. -void insertDestroyOfCapturedArguments( - PartialApplyInst *PAI, SILBuilder &B, - llvm::function_ref shouldInsertDestroy = - [](SILValue arg) -> bool { return true; }); - -/// 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 Frontier; - - /// Constructor for the value \p Def with a specific set of users of Def's - /// users. - ValueLifetimeAnalysis(SILInstruction *Def, ArrayRef 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 LiveBlocks; - - /// The set of instructions where the value is used, or the users-list - /// provided with the constructor. - llvm::SmallPtrSet 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 { - using SuperTy = SILCloner; - friend class SILCloner; - -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, 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 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(Value)) { - if (!isBlockCloned(BBArg->getParent())) - return Value; - } else { - assert(isa(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); - } -}; - -/// Sink address projections to their out-of-block uses. This is -/// required after cloning a block and before calling -/// updateSSAAfterCloning to avoid address-type phis. -/// -/// This clones address projections at their use points, but does not -/// mutate the block containing the projections. -class SinkAddressProjections { - // Projections ordered from last to first in the chain. - SmallVector projections; - SmallSetVector inBlockDefs; - -public: - /// Check for an address projection chain ending at \p inst. Return true if - /// the given instruction is successfully analyzed. - /// - /// If \p inst does not produce an address, then return - /// true. getInBlockDefs() will contain \p inst if any of its - /// (non-address) values are used outside its block. - /// - /// If \p inst does produce an address, return true only of the - /// chain of address projections within this block is clonable at - /// their use sites. getInBlockDefs will return all non-address - /// operands in the chain that are also defined in this block. These - /// may require phis after cloning the projections. - bool analyzeAddressProjections(SILInstruction *inst); - - /// After analyzing projections, returns the list of (non-address) values - /// defined in the same block as the projections which will have uses outside - /// the block after cloning. - ArrayRef getInBlockDefs() const { - return inBlockDefs.getArrayRef(); - } - /// Clone the chain of projections at their use sites. - /// - /// Return true if anything was done. - /// - /// getInBlockProjectionOperandValues() can be called before or after cloning. - bool cloneProjections(); -}; - -/// 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 value_type; - typedef std::function CallbackType; - typedef std::function FilterType; - -private: - FilterType Filter; - - // Pairs of collected instructions; (new, old) - llvm::SmallVector 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 &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 { - ValueBaseUseIterator OrigUseChain; - ValueBaseUseIterator CurrentIter; - - static BuiltinInst *isExpect(Operand *Use) { - if (auto *BI = dyn_cast(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 -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 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 &Insns); - -/// Returns true if the below operation will succeed. -bool canReplaceLoadSequence(SILInstruction *I); - -/// 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); - - -/// 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, - 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, - 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, - ClassHierarchyAnalysis *CHA); - -/// Utility class for cloning init values into the static initializer of a -/// SILGlobalVariable. -class StaticInitCloner : public SILCloner { - friend class SILInstructionVisitor; - friend class SILCloner; - - /// The number of not yet cloned operands for each instruction. - llvm::DenseMap NumOpsToClone; - - /// List of instructions for which all operands are already cloned (or which - /// don't have any operands). - llvm::SmallVector ReadyToClone; - -public: - StaticInitCloner(SILGlobalVariable *GVar) - : SILCloner(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 partialApplySites; - - /// Contains the list of full apply sites that we found. - SmallVector 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 -findLocalApplySites(FunctionRefBaseInst *FRI); - -} // end namespace swift - -#endif diff --git a/include/swift/SILOptimizer/Utils/ValueLifetime.h b/include/swift/SILOptimizer/Utils/ValueLifetime.h new file mode 100644 index 00000000000..85be58077e6 --- /dev/null +++ b/include/swift/SILOptimizer/Utils/ValueLifetime.h @@ -0,0 +1,125 @@ +//===--- ValueLifetime.h - ValueLifetimeAnalysis ----------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 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 +// +//===----------------------------------------------------------------------===// +/// +/// Utilities used by the SILOptimizer for SSA analysis and update. +/// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SILOPTIMIZER_UTILS_CFG_H +#define SWIFT_SILOPTIMIZER_UTILS_CFG_H + +#include "swift/SIL/SILInstruction.h" +#include "swift/SIL/SILBuilder.h" + +namespace swift { + +/// 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 Frontier; + + /// Constructor for the value \p Def with a specific set of users of Def's + /// users. + ValueLifetimeAnalysis(SILInstruction *def, + ArrayRef 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 frontier. + /// + /// 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 frontier is not + /// valid. + /// + /// If \p deBlocks is provided, all dead-end blocks are ignored. This + /// prevents unreachable-blocks to be included in the frontier. + bool computeFrontier(Frontier &frontier, 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 liveBlocks; + + /// The set of instructions where the value is used, or the users-list + /// provided with the constructor. + llvm::SmallPtrSet 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); +}; + + +} // end namespace swift + +#endif diff --git a/lib/IRGen/LoadableByAddress.cpp b/lib/IRGen/LoadableByAddress.cpp index 2e01eaa55e7..4a3b79b25f3 100644 --- a/lib/IRGen/LoadableByAddress.cpp +++ b/lib/IRGen/LoadableByAddress.cpp @@ -27,7 +27,7 @@ #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBuilder.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SetVector.h" #include "llvm/Support/CommandLine.h" diff --git a/lib/SILOptimizer/ARC/ARCMatchingSet.cpp b/lib/SILOptimizer/ARC/ARCMatchingSet.cpp index dff2579427d..442a4c9011b 100644 --- a/lib/SILOptimizer/ARC/ARCMatchingSet.cpp +++ b/lib/SILOptimizer/ARC/ARCMatchingSet.cpp @@ -12,24 +12,24 @@ #define DEBUG_TYPE "arc-sequence-opts" -#include "RefCountState.h" #include "ARCMatchingSet.h" +#include "RefCountState.h" #include "swift/Basic/BlotMapVector.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILVisitor.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/MapVector.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Statistic.h" -#include "llvm/Support/Debug.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp b/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp index f4e0cdc07c4..00d284761f6 100644 --- a/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp +++ b/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp @@ -12,28 +12,28 @@ #define DEBUG_TYPE "arc-sequence-opts" -#include "swift/SILOptimizer/PassManager/Passes.h" #include "ARCSequenceOpts.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILVisitor.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SILOptimizer/Utils/LoopUtils.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/EpilogueARCAnalysis.h" -#include "swift/SILOptimizer/Analysis/ProgramTerminationAnalysis.h" -#include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" -#include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" -#include "swift/SILOptimizer/Analysis/LoopRegionAnalysis.h" #include "swift/SILOptimizer/Analysis/LoopAnalysis.h" +#include "swift/SILOptimizer/Analysis/LoopRegionAnalysis.h" +#include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" +#include "swift/SILOptimizer/Analysis/ProgramTerminationAnalysis.h" +#include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/LoopUtils.h" +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/MapVector.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Statistic.h" -#include "llvm/Support/Debug.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/Analysis/ARCAnalysis.cpp b/lib/SILOptimizer/Analysis/ARCAnalysis.cpp index 74d1ceb5ffd..f600f0d0523 100644 --- a/lib/SILOptimizer/Analysis/ARCAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/ARCAnalysis.cpp @@ -15,16 +15,16 @@ #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SIL/DebugUtils.h" #include "swift/SIL/InstructionUtils.h" +#include "swift/SIL/Projection.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" -#include "swift/SIL/Projection.h" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "llvm/ADT/StringSwitch.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/Analysis/AliasAnalysis.cpp b/lib/SILOptimizer/Analysis/AliasAnalysis.cpp index acbd467d374..b70518c0b81 100644 --- a/lib/SILOptimizer/Analysis/AliasAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/AliasAnalysis.cpp @@ -12,18 +12,18 @@ #define DEBUG_TYPE "sil-aa" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" -#include "swift/SILOptimizer/Analysis/ValueTracking.h" -#include "swift/SILOptimizer/Analysis/SideEffectAnalysis.h" -#include "swift/SILOptimizer/Analysis/EscapeAnalysis.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SILOptimizer/PassManager/PassManager.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SIL/Projection.h" -#include "swift/SIL/SILValue.h" -#include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILFunction.h" +#include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILModule.h" -#include "swift/SIL/InstructionUtils.h" +#include "swift/SIL/SILValue.h" +#include "swift/SILOptimizer/Analysis/EscapeAnalysis.h" +#include "swift/SILOptimizer/Analysis/SideEffectAnalysis.h" +#include "swift/SILOptimizer/Analysis/ValueTracking.h" +#include "swift/SILOptimizer/PassManager/PassManager.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" diff --git a/lib/SILOptimizer/Analysis/Analysis.cpp b/lib/SILOptimizer/Analysis/Analysis.cpp index 2fc7354f9ec..ac1b76de4bb 100644 --- a/lib/SILOptimizer/Analysis/Analysis.cpp +++ b/lib/SILOptimizer/Analysis/Analysis.cpp @@ -12,19 +12,19 @@ #define DEBUG_TYPE "sil-analysis" #include "swift/SILOptimizer/Analysis/Analysis.h" +#include "swift/AST/Module.h" +#include "swift/AST/SILOptions.h" +#include "swift/SIL/SILFunction.h" +#include "swift/SIL/SILModule.h" #include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h" +#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/Analysis/IVAnalysis.h" #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" -#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h" #include "swift/SILOptimizer/Analysis/ProtocolConformanceAnalysis.h" -#include "swift/AST/Module.h" -#include "swift/AST/SILOptions.h" -#include "swift/SIL/SILModule.h" -#include "swift/SIL/SILFunction.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" -#include "swift/SILOptimizer/Utils/Local.h" using namespace swift; diff --git a/lib/SILOptimizer/Analysis/ArraySemantic.cpp b/lib/SILOptimizer/Analysis/ArraySemantic.cpp index e01864c3089..52282d2a7cf 100644 --- a/lib/SILOptimizer/Analysis/ArraySemantic.cpp +++ b/lib/SILOptimizer/Analysis/ArraySemantic.cpp @@ -10,14 +10,14 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/StringSwitch.h" #include "swift/SILOptimizer/Analysis/ArraySemantic.h" -#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" -#include "swift/SILOptimizer/Utils/Local.h" #include "swift/SIL/DebugUtils.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILFunction.h" +#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "llvm/ADT/StringSwitch.h" using namespace swift; diff --git a/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp b/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp index 5aae7d49271..904518a21b8 100644 --- a/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp @@ -13,9 +13,10 @@ #include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h" #include "swift/AST/Decl.h" +#include "swift/AST/ProtocolConformance.h" #include "swift/Basic/Statistic.h" #include "swift/SIL/SILModule.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/Support/Compiler.h" #include diff --git a/lib/SILOptimizer/Analysis/CFG.cpp b/lib/SILOptimizer/Analysis/CFG.cpp deleted file mode 100644 index a079be8ce56..00000000000 --- a/lib/SILOptimizer/Analysis/CFG.cpp +++ /dev/null @@ -1,107 +0,0 @@ -//===--- CFG.cpp ----------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -#include "swift/SILOptimizer/Analysis/CFG.h" -#include "swift/SIL/SILFunction.h" -#include "swift/SIL/SILInstruction.h" -#include "swift/SIL/SILValue.h" -#include "swift/Demangling/ManglingMacros.h" -#include "llvm/ADT/TinyPtrVector.h" - -using namespace swift; - -static bool isSafeNonExitTerminator(TermInst *TI) { - switch (TI->getTermKind()) { - case TermKind::BranchInst: - case TermKind::CondBranchInst: - case TermKind::SwitchValueInst: - case TermKind::SwitchEnumInst: - case TermKind::SwitchEnumAddrInst: - case TermKind::DynamicMethodBranchInst: - case TermKind::CheckedCastBranchInst: - case TermKind::CheckedCastValueBranchInst: - case TermKind::CheckedCastAddrBranchInst: - return true; - case TermKind::UnreachableInst: - case TermKind::ReturnInst: - case TermKind::ThrowInst: - case TermKind::UnwindInst: - return false; - // yield is special because it can do arbitrary, - // potentially-process-terminating things. - case TermKind::YieldInst: - return false; - case TermKind::TryApplyInst: - return true; - } - - llvm_unreachable("Unhandled TermKind in switch."); -} - -static bool isTrapNoReturnFunction(ApplyInst *AI) { - const char *fatalName = - MANGLE_AS_STRING(MANGLE_SYM(s18_fatalErrorMessageyys12StaticStringV_AcCSutF)); - auto *Fn = AI->getReferencedFunctionOrNull(); - - // We use endswith here since if we specialize fatal error we will always - // prepend the specialization records to fatalName. - if (!Fn || !Fn->getName().endswith(fatalName)) - return false; - - return true; -} - -bool -swift:: -findAllNonFailureExitBBs(SILFunction *F, - llvm::TinyPtrVector &BBs) { - for (SILBasicBlock &BB : *F) { - TermInst *TI = BB.getTerminator(); - - // If we know that this terminator is not an exit terminator, continue. - if (isSafeNonExitTerminator(TI)) - continue; - - // A return inst is always a non-failure exit bb. - if (TI->isFunctionExiting()) { - BBs.push_back(&BB); - continue; - } - - // If we don't have an unreachable inst at this point, this is a terminator - // we don't understand. Be conservative and return false. - if (!isa(TI)) - return false; - - // Ok, at this point we know we have a terminator. If it is the only - // instruction in our BB, it is a failure BB. continue... - if (TI == &*BB.begin()) - continue; - - // If the unreachable is preceded by a no-return apply inst, then it is a - // non-failure exit BB. Add it to our list and continue. - auto PrevIter = std::prev(SILBasicBlock::iterator(TI)); - if (auto *AI = dyn_cast(&*PrevIter)) { - if (AI->isCalleeNoReturn() && - !isTrapNoReturnFunction(AI)) { - BBs.push_back(&BB); - continue; - } - } - - // Otherwise, it must be a failure BB where we leak, continue. - continue; - } - - // We understood all terminators, return true. - return true; -} diff --git a/lib/SILOptimizer/Analysis/CMakeLists.txt b/lib/SILOptimizer/Analysis/CMakeLists.txt index 009fea5b7e3..58be25ffa01 100644 --- a/lib/SILOptimizer/Analysis/CMakeLists.txt +++ b/lib/SILOptimizer/Analysis/CMakeLists.txt @@ -7,7 +7,6 @@ silopt_register_sources( ArraySemantic.cpp BasicCalleeAnalysis.cpp CallerAnalysis.cpp - CFG.cpp ClassHierarchyAnalysis.cpp ClosureScope.cpp ColdBlockInfo.cpp diff --git a/lib/SILOptimizer/Analysis/CallerAnalysis.cpp b/lib/SILOptimizer/Analysis/CallerAnalysis.cpp index c2894f10725..f27316bd95e 100644 --- a/lib/SILOptimizer/Analysis/CallerAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/CallerAnalysis.cpp @@ -14,7 +14,8 @@ #include "swift/SILOptimizer/Analysis/CallerAnalysis.h" #include "swift/SIL/InstructionUtils.h" #include "swift/SIL/SILModule.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SIL/SILVisitor.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/YAMLTraits.h" diff --git a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp index 8924baa8f90..0b6316d9b80 100644 --- a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp @@ -12,13 +12,13 @@ #define DEBUG_TYPE "sil-escape" #include "swift/SILOptimizer/Analysis/EscapeAnalysis.h" -#include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h" +#include "swift/SIL/DebugUtils.h" +#include "swift/SIL/SILArgument.h" #include "swift/SILOptimizer/Analysis/ArraySemantic.h" +#include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" #include "swift/SILOptimizer/PassManager/PassManager.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SIL/SILArgument.h" -#include "swift/SIL/DebugUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/Support/GraphWriter.h" #include "llvm/Support/raw_ostream.h" diff --git a/lib/SILOptimizer/Analysis/SimplifyInstruction.cpp b/lib/SILOptimizer/Analysis/SimplifyInstruction.cpp index 914650a6bda..1ffe2bb525b 100644 --- a/lib/SILOptimizer/Analysis/SimplifyInstruction.cpp +++ b/lib/SILOptimizer/Analysis/SimplifyInstruction.cpp @@ -25,7 +25,7 @@ #include "swift/SIL/PatternMatch.h" #include "swift/SIL/SILVisitor.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" using namespace swift; using namespace swift::PatternMatch; diff --git a/lib/SILOptimizer/Analysis/TypeExpansionAnalysis.cpp b/lib/SILOptimizer/Analysis/TypeExpansionAnalysis.cpp index 9758746fb8a..203e7cca659 100644 --- a/lib/SILOptimizer/Analysis/TypeExpansionAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/TypeExpansionAnalysis.cpp @@ -14,7 +14,7 @@ #include "swift/SILOptimizer/Analysis/TypeExpansionAnalysis.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILModule.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/Analysis/ValueTracking.cpp b/lib/SILOptimizer/Analysis/ValueTracking.cpp index 58d0e3aac98..43a067b3224 100644 --- a/lib/SILOptimizer/Analysis/ValueTracking.cpp +++ b/lib/SILOptimizer/Analysis/ValueTracking.cpp @@ -12,13 +12,13 @@ #define DEBUG_TYPE "sil-value-tracking" #include "swift/SILOptimizer/Analysis/ValueTracking.h" -#include "swift/SILOptimizer/Analysis/SimplifyInstruction.h" +#include "swift/SIL/InstructionUtils.h" +#include "swift/SIL/PatternMatch.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILValue.h" -#include "swift/SIL/InstructionUtils.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SIL/PatternMatch.h" +#include "swift/SILOptimizer/Analysis/SimplifyInstruction.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/Support/Debug.h" using namespace swift; using namespace swift::PatternMatch; diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialSpecializer.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialSpecializer.cpp index 0d93ef676ec..6a10833dc58 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialSpecializer.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialSpecializer.cpp @@ -22,7 +22,7 @@ #include "swift/SILOptimizer/Analysis/ProtocolConformanceAnalysis.h" #include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Utils/Existential.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp index 85006473260..37f1fbaf2c6 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp @@ -23,10 +23,9 @@ #include "swift/SIL/SILInstruction.h" #include "swift/SIL/TypeSubstCloner.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" #include "swift/SILOptimizer/Utils/Existential.h" #include "swift/SILOptimizer/Utils/Generics.h" -#include "swift/SILOptimizer/Utils/Local.h" #include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/Utils/SpecializationMangler.h" #include "llvm/ADT/SmallVector.h" diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.h b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.h index 424595c8d4e..79ad59ec7eb 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.h +++ b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.h @@ -20,7 +20,7 @@ #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" #include "swift/SILOptimizer/Utils/Existential.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/Utils/SpecializationMangler.h" #include "llvm/ADT/SmallBitVector.h" diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp index b683e260647..106503643ae 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp @@ -34,7 +34,6 @@ #include "swift/SIL/DebugUtils.h" #include "swift/SIL/SILCloner.h" #include "swift/SIL/SILFunction.h" -#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SIL/SILValue.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/CallerAnalysis.h" @@ -42,8 +41,9 @@ #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILInliner.h" +#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/Utils/SpecializationMangler.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/CommandLine.h" diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.h b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.h index 84c1f62847a..764510db9bd 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.h +++ b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.h @@ -26,7 +26,7 @@ #include "swift/SILOptimizer/Analysis/CallerAnalysis.h" #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" #include "swift/SILOptimizer/PassManager/PassManager.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/Utils/SpecializationMangler.h" #include "llvm/ADT/DenseMap.h" diff --git a/lib/SILOptimizer/IPO/CapturePropagation.cpp b/lib/SILOptimizer/IPO/CapturePropagation.cpp index 43aec92f08d..614f8781b8b 100644 --- a/lib/SILOptimizer/IPO/CapturePropagation.cpp +++ b/lib/SILOptimizer/IPO/CapturePropagation.cpp @@ -14,7 +14,6 @@ #include "swift/AST/GenericEnvironment.h" #include "swift/Demangling/Demangle.h" #include "swift/SIL/SILCloner.h" -#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/TypeSubstCloner.h" #include "swift/SILOptimizer/Analysis/ColdBlockInfo.h" @@ -22,7 +21,8 @@ #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Utils/Generics.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/Utils/SpecializationMangler.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/Statistic.h" diff --git a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp index 38184d982ae..335961d249e 100644 --- a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp +++ b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp @@ -63,18 +63,19 @@ #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILModule.h" #include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h" -#include "swift/SILOptimizer/Analysis/CFG.h" #include "swift/SILOptimizer/Analysis/FunctionOrder.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILInliner.h" #include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/Utils/SpecializationMangler.h" #include "swift/SILOptimizer/Utils/StackNesting.h" -#include "llvm/ADT/SmallString.h" +#include "swift/SILOptimizer/Utils/ValueLifetime.h" #include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" diff --git a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp index a533cc5f764..48bba4ae285 100644 --- a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp +++ b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp @@ -12,13 +12,13 @@ #define DEBUG_TYPE "sil-dead-function-elimination" #include "swift/AST/ProtocolConformance.h" -#include "swift/SILOptimizer/PassManager/Passes.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SIL/PatternMatch.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILVisitor.h" -#include "swift/SIL/InstructionUtils.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" diff --git a/lib/SILOptimizer/IPO/GlobalOpt.cpp b/lib/SILOptimizer/IPO/GlobalOpt.cpp index f2e18428c6b..0fcd0d7f390 100644 --- a/lib/SILOptimizer/IPO/GlobalOpt.cpp +++ b/lib/SILOptimizer/IPO/GlobalOpt.cpp @@ -17,14 +17,16 @@ #include "swift/Demangling/ManglingMacros.h" #include "swift/SIL/CFG.h" #include "swift/SIL/DebugUtils.h" -#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" +#include "swift/SIL/SILCloner.h" #include "swift/SIL/SILGlobalVariable.h" #include "swift/SIL/SILInstruction.h" #include "swift/SILOptimizer/Analysis/ColdBlockInfo.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SCCIterator.h" #include "llvm/Support/CommandLine.h" diff --git a/lib/SILOptimizer/IPO/GlobalPropertyOpt.cpp b/lib/SILOptimizer/IPO/GlobalPropertyOpt.cpp index 86500322f54..b0b6dc0ecd1 100644 --- a/lib/SILOptimizer/IPO/GlobalPropertyOpt.cpp +++ b/lib/SILOptimizer/IPO/GlobalPropertyOpt.cpp @@ -11,20 +11,20 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "globalpropertyopt" -#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" -#include "swift/SIL/SILArgument.h" #include "swift/SIL/SILModule.h" -#include "swift/SIL/SILBuilder.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" #include "swift/SILOptimizer/Analysis/ArraySemantic.h" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/Statistic.h" -#include "llvm/Support/Debug.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp b/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp index ed90ade92b1..6fc43adc5fe 100644 --- a/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp +++ b/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp @@ -26,7 +26,8 @@ #include "swift/SIL/SILLinkage.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/MapVector.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" diff --git a/lib/SILOptimizer/IPO/UsePrespecialized.cpp b/lib/SILOptimizer/IPO/UsePrespecialized.cpp index 42f39f5c203..2b1e8f58aa4 100644 --- a/lib/SILOptimizer/IPO/UsePrespecialized.cpp +++ b/lib/SILOptimizer/IPO/UsePrespecialized.cpp @@ -11,16 +11,16 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "use-prespecialized" +#include "swift/SIL/SILBuilder.h" +#include "swift/SIL/SILFunction.h" +#include "swift/SIL/SILInstruction.h" +#include "swift/SIL/SILModule.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SILOptimizer/Utils/SpecializationMangler.h" -#include "swift/SIL/SILBuilder.h" -#include "swift/SIL/SILInstruction.h" -#include "swift/SIL/SILFunction.h" -#include "swift/SIL/SILModule.h" -#include "llvm/Support/Debug.h" #include "swift/SILOptimizer/Utils/Generics.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/SpecializationMangler.h" +#include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/LoopTransforms/ArrayBoundsCheckOpts.cpp b/lib/SILOptimizer/LoopTransforms/ArrayBoundsCheckOpts.cpp index c9c07299331..3af89ed40f5 100644 --- a/lib/SILOptimizer/LoopTransforms/ArrayBoundsCheckOpts.cpp +++ b/lib/SILOptimizer/LoopTransforms/ArrayBoundsCheckOpts.cpp @@ -12,8 +12,15 @@ #define DEBUG_TYPE "sil-abcopts" -#include "swift/Basic/STLExtras.h" #include "swift/AST/Builtins.h" +#include "swift/Basic/STLExtras.h" +#include "swift/SIL/Dominance.h" +#include "swift/SIL/InstructionUtils.h" +#include "swift/SIL/PatternMatch.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILBuilder.h" +#include "swift/SIL/SILFunction.h" +#include "swift/SIL/SILInstruction.h" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SILOptimizer/Analysis/ArraySemantic.h" @@ -24,16 +31,9 @@ #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILSSAUpdater.h" -#include "swift/SIL/Dominance.h" -#include "swift/SIL/PatternMatch.h" -#include "swift/SIL/SILArgument.h" -#include "swift/SIL/SILBuilder.h" -#include "swift/SIL/SILFunction.h" -#include "swift/SIL/SILInstruction.h" -#include "swift/SIL/InstructionUtils.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/PointerIntPair.h" diff --git a/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp b/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp index e1840cae2ba..48fdf943ef4 100644 --- a/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp +++ b/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp @@ -11,26 +11,26 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "cowarray-opts" -#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SIL/CFG.h" +#include "swift/SIL/DebugUtils.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SIL/Projection.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILCloner.h" #include "swift/SIL/SILInstruction.h" -#include "swift/SIL/DebugUtils.h" -#include "swift/SIL/InstructionUtils.h" -#include "swift/SILOptimizer/Analysis/ArraySemantic.h" -#include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" +#include "swift/SILOptimizer/Analysis/AliasAnalysis.h" +#include "swift/SILOptimizer/Analysis/ArraySemantic.h" #include "swift/SILOptimizer/Analysis/ColdBlockInfo.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/Analysis/LoopAnalysis.h" #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" +#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILSSAUpdater.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringExtras.h" diff --git a/lib/SILOptimizer/LoopTransforms/LICM.cpp b/lib/SILOptimizer/LoopTransforms/LICM.cpp index c105d165ec4..97f8ca76bb8 100644 --- a/lib/SILOptimizer/LoopTransforms/LICM.cpp +++ b/lib/SILOptimizer/LoopTransforms/LICM.cpp @@ -27,8 +27,8 @@ #include "swift/SILOptimizer/Analysis/SideEffectAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILSSAUpdater.h" #include "llvm/ADT/DepthFirstIterator.h" diff --git a/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp b/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp index 52c622c4821..31500702043 100644 --- a/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp +++ b/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp @@ -13,17 +13,18 @@ #define DEBUG_TYPE "sil-looprotate" #include "swift/SIL/Dominance.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILBuilder.h" +#include "swift/SIL/SILInstruction.h" #include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/Analysis/LoopAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/SILSSAUpdater.h" +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "swift/SILOptimizer/Utils/LoopUtils.h" -#include "swift/SIL/SILArgument.h" -#include "swift/SIL/SILBuilder.h" -#include "swift/SIL/SILInstruction.h" +#include "swift/SILOptimizer/Utils/SILSSAUpdater.h" #include "llvm/Support/Debug.h" #include "llvm/Support/CommandLine.h" @@ -34,18 +35,18 @@ static llvm::cl::opt ShouldRotate("sil-looprotate", llvm::cl::init(true)); /// Check whether all operands are loop invariant. -static bool hasLoopInvariantOperands(SILInstruction *I, SILLoop *L, - llvm::DenseSet &Inv) { - auto Opds = I->getAllOperands(); +static bool +hasLoopInvariantOperands(SILInstruction *inst, SILLoop *loop, + llvm::DenseSet &invariant) { + auto operands = inst->getAllOperands(); - return std::all_of(Opds.begin(), Opds.end(), [=](Operand &Op) { - - ValueBase *Def = Op.get(); + return llvm::all_of(operands, [=](Operand &operand) { + ValueBase *def = operand.get(); // Operand is outside the loop or marked invariant. - if (auto *Inst = Def->getDefiningInstruction()) - return !L->contains(Inst->getParent()) || Inv.count(Inst); - if (auto *Arg = dyn_cast(Def)) - return !L->contains(Arg->getParent()); + if (auto *inst = def->getDefiningInstruction()) + return !loop->contains(inst->getParent()) || invariant.count(inst); + if (auto *arg = dyn_cast(def)) + return !loop->contains(arg->getParent()); return false; }); @@ -54,76 +55,72 @@ static bool hasLoopInvariantOperands(SILInstruction *I, SILLoop *L, /// We cannot duplicate blocks with AllocStack instructions (they need to be /// FIFO). Other instructions can be moved to the preheader. static bool -canDuplicateOrMoveToPreheader(SILLoop *L, SILBasicBlock *Preheader, - SILBasicBlock *Blk, - SmallVectorImpl &Move) { - llvm::DenseSet Invariant; - for (auto &I : *Blk) { - auto *Inst = &I; - if (auto *MI = dyn_cast(Inst)) { +canDuplicateOrMoveToPreheader(SILLoop *loop, SILBasicBlock *preheader, + SILBasicBlock *bb, + SmallVectorImpl &moves) { + llvm::DenseSet invariants; + for (auto &instRef : *bb) { + auto *inst = &instRef; + if (auto *MI = dyn_cast(inst)) { if (MI->getMember().isForeign) return false; - if (!hasLoopInvariantOperands(Inst, L, Invariant)) + if (!hasLoopInvariantOperands(inst, loop, invariants)) continue; - Move.push_back(Inst); - Invariant.insert(Inst); - } else if (!I.isTriviallyDuplicatable()) + moves.push_back(inst); + invariants.insert(inst); + } else if (!inst->isTriviallyDuplicatable()) return false; - else if (isa(Inst)) { - Move.push_back(Inst); - Invariant.insert(Inst); - } else if (isa(Inst)) { - Move.push_back(Inst); - Invariant.insert(Inst); - } - else if (isa(Inst)) { - Move.push_back(Inst); - Invariant.insert(Inst); - } else if (isa(Inst)) { - Move.push_back(Inst); - Invariant.insert(Inst); - } else if (!Inst->mayHaveSideEffects() && - !Inst->mayReadFromMemory() && - !isa(Inst) && - !isa(Inst) && /* not marked mayhavesideffects */ - hasLoopInvariantOperands(Inst, L, Invariant)) { - Move.push_back(Inst); - Invariant.insert(Inst); + else if (isa(inst)) { + moves.push_back(inst); + invariants.insert(inst); + } else if (isa(inst)) { + moves.push_back(inst); + invariants.insert(inst); + } else if (isa(inst)) { + moves.push_back(inst); + invariants.insert(inst); + } else if (isa(inst)) { + moves.push_back(inst); + invariants.insert(inst); + } else if (!inst->mayHaveSideEffects() && !inst->mayReadFromMemory() + && !isa(inst) && !isa(inst) + && /* not marked mayhavesideffects */ + hasLoopInvariantOperands(inst, loop, invariants)) { + moves.push_back(inst); + invariants.insert(inst); } } return true; } -static void mapOperands(SILInstruction *I, - const llvm::DenseMap &ValueMap) { - for (auto &Opd : I->getAllOperands()) { - SILValue OrigVal = Opd.get(); - ValueBase *OrigDef = OrigVal; - auto Found = ValueMap.find(OrigDef); - if (Found != ValueMap.end()) { - SILValue MappedVal = Found->second; - Opd.set(MappedVal); +static void mapOperands(SILInstruction *inst, + const llvm::DenseMap &valueMap) { + for (auto &operand : inst->getAllOperands()) { + SILValue origVal = operand.get(); + ValueBase *origDef = origVal; + auto found = valueMap.find(origDef); + if (found != valueMap.end()) { + SILValue mappedVal = found->second; + operand.set(mappedVal); } } } static void updateSSAForUseOfValue( - SILSSAUpdater &Updater, SmallVectorImpl &InsertedPHIs, - const llvm::DenseMap &ValueMap, - SILBasicBlock *Header, SILBasicBlock *EntryCheckBlock, - SILValue Res) { + SILSSAUpdater &updater, SmallVectorImpl &insertedPhis, + const llvm::DenseMap &valueMap, + SILBasicBlock *Header, SILBasicBlock *EntryCheckBlock, SILValue Res) { // Find the mapped instruction. - assert(ValueMap.count(Res) && "Expected to find value in map!"); - SILValue MappedValue = ValueMap.find(Res)->second; + assert(valueMap.count(Res) && "Expected to find value in map!"); + SILValue MappedValue = valueMap.find(Res)->second; assert(MappedValue); assert(Res->getType() == MappedValue->getType() && "The types must match"); - InsertedPHIs.clear(); - Updater.Initialize(Res->getType()); - Updater.AddAvailableValue(Header, Res); - Updater.AddAvailableValue(EntryCheckBlock, MappedValue); - + insertedPhis.clear(); + updater.Initialize(Res->getType()); + updater.AddAvailableValue(Header, Res); + updater.AddAvailableValue(EntryCheckBlock, MappedValue); // Because of the way that phi nodes are represented we have to collect all // uses before we update SSA. Modifying one phi node can invalidate another @@ -131,26 +128,26 @@ static void updateSSAForUseOfValue( // has to be modified). This would invalidate a plain ValueUseIterator. // Instead we collect uses wrapping uses in branches specially so that we // can reconstruct the use even after the branch has been modified. - SmallVector StoredUses; - for (auto *U : Res->getUses()) - StoredUses.push_back(UseWrapper(U)); - for (auto U : StoredUses) { - Operand *Use = U; - SILInstruction *User = Use->getUser(); - assert(User && "Missing user"); + SmallVector storedUses; + for (auto *use : Res->getUses()) + storedUses.push_back(UseWrapper(use)); + for (auto useWrapper : storedUses) { + Operand *use = useWrapper; + SILInstruction *user = use->getUser(); + assert(user && "Missing user"); // Ignore uses in the same basic block. - if (User->getParent() == Header) + if (user->getParent() == Header) continue; - assert(User->getParent() != EntryCheckBlock && - "The entry check block should dominate the header"); - Updater.RewriteUse(*Use); + assert(user->getParent() != EntryCheckBlock + && "The entry check block should dominate the header"); + updater.RewriteUse(*use); } // Canonicalize inserted phis to avoid extra BB Args. - for (SILPhiArgument *Arg : InsertedPHIs) { - if (SILValue Inst = replaceBBArgWithCast(Arg)) { - Arg->replaceAllUsesWith(Inst); + for (SILPhiArgument *arg : insertedPhis) { + if (SILValue inst = replaceBBArgWithCast(arg)) { + arg->replaceAllUsesWith(inst); // DCE+SimplifyCFG runs as a post-pass cleanup. // DCE replaces dead arg values with undef. // SimplifyCFG deletes the dead BB arg. @@ -158,72 +155,76 @@ static void updateSSAForUseOfValue( } } -static void updateSSAForUseOfInst( - SILSSAUpdater &Updater, SmallVectorImpl &InsertedPHIs, - const llvm::DenseMap &ValueMap, - SILBasicBlock *Header, SILBasicBlock *EntryCheckBlock, - SILInstruction *Inst) { - for (auto result : Inst->getResults()) - updateSSAForUseOfValue(Updater, InsertedPHIs, ValueMap, Header, - EntryCheckBlock, result); +static void +updateSSAForUseOfInst(SILSSAUpdater &updater, + SmallVectorImpl &insertedPhis, + const llvm::DenseMap &valueMap, + SILBasicBlock *header, SILBasicBlock *entryCheckBlock, + SILInstruction *inst) { + for (auto result : inst->getResults()) + updateSSAForUseOfValue(updater, insertedPhis, valueMap, header, + entryCheckBlock, result); } /// Rewrite the code we just created in the preheader and update SSA form. -static void -rewriteNewLoopEntryCheckBlock(SILBasicBlock *Header, - SILBasicBlock *EntryCheckBlock, - const llvm::DenseMap &ValueMap) { - SmallVector InsertedPHIs; - SILSSAUpdater Updater(&InsertedPHIs); +static void rewriteNewLoopEntryCheckBlock( + SILBasicBlock *header, SILBasicBlock *entryCheckBlock, + const llvm::DenseMap &valueMap) { + SmallVector insertedPhis; + SILSSAUpdater updater(&insertedPhis); // Fix PHIs (incoming arguments). - for (auto *Arg : Header->getArguments()) - updateSSAForUseOfValue(Updater, InsertedPHIs, ValueMap, Header, - EntryCheckBlock, Arg); + for (auto *arg : header->getArguments()) + updateSSAForUseOfValue(updater, insertedPhis, valueMap, header, + entryCheckBlock, arg); - auto InstIter = Header->begin(); + auto instIter = header->begin(); // The terminator might change from under us. - while (InstIter != Header->end()) { - auto &Inst = *InstIter; - updateSSAForUseOfInst(Updater, InsertedPHIs, ValueMap, Header, - EntryCheckBlock, &Inst); - InstIter++; + while (instIter != header->end()) { + auto &inst = *instIter; + updateSSAForUseOfInst(updater, insertedPhis, valueMap, header, + entryCheckBlock, &inst); + instIter++; } } /// Update the dominator tree after rotating the loop. /// The former preheader now dominates all of the former headers children. The /// former latch now dominates the former header. -static void updateDomTree(DominanceInfo *DT, SILBasicBlock *Preheader, - SILBasicBlock *Latch, SILBasicBlock *Header) { - auto *HeaderN = DT->getNode(Header); - SmallVector Children(HeaderN->begin(), - HeaderN->end()); - auto *PreheaderN = DT->getNode(Preheader); +static void updateDomTree(DominanceInfo *domInfo, SILBasicBlock *preheader, + SILBasicBlock *latch, SILBasicBlock *header) { + auto *headerN = domInfo->getNode(header); + SmallVector Children(headerN->begin(), + headerN->end()); + auto *preheaderN = domInfo->getNode(preheader); for (auto *Child : Children) - DT->changeImmediateDominator(Child, PreheaderN); + domInfo->changeImmediateDominator(Child, preheaderN); - if (Header != Latch) - DT->changeImmediateDominator(HeaderN, DT->getNode(Latch)); + if (header != latch) + domInfo->changeImmediateDominator(headerN, domInfo->getNode(latch)); } -static bool rotateLoopAtMostUpToLatch(SILLoop *L, DominanceInfo *DT, - SILLoopInfo *LI, bool ShouldVerify) { - auto *Latch = L->getLoopLatch(); - if (!Latch) { - LLVM_DEBUG(llvm::dbgs() << *L << " does not have a single latch block\n"); +static bool rotateLoopAtMostUpToLatch(SILLoop *loop, DominanceInfo *domInfo, + SILLoopInfo *loopInfo, + bool ShouldVerify) { + auto *latch = loop->getLoopLatch(); + if (!latch) { + LLVM_DEBUG(llvm::dbgs() + << *loop << " does not have a single latch block\n"); return false; } - bool DidRotate = rotateLoop(L, DT, LI, false /* RotateSingleBlockLoops */, - Latch, ShouldVerify); + bool didRotate = + rotateLoop(loop, domInfo, loopInfo, false /* rotateSingleBlockLoops */, + latch, ShouldVerify); // Keep rotating at most until we hit the original latch. - if (DidRotate) - while (rotateLoop(L, DT, LI, false, Latch, ShouldVerify)) {} + if (didRotate) + while (rotateLoop(loop, domInfo, loopInfo, false, latch, ShouldVerify)) { + } - return DidRotate; + return didRotate; } /// Check whether this a single basic block loop - ignoring split back edges. @@ -236,16 +237,16 @@ static bool isSingleBlockLoop(SILLoop *L) { if (NumBlocks == 1) return true; - auto *Header = L->getHeader(); + auto *header = L->getHeader(); auto *BackEdge = Blocks[1]; - if (BackEdge == Header) + if (BackEdge == header) BackEdge = Blocks[0]; if (!BackEdge->getSingleSuccessorBlock()) return false; - assert(BackEdge->getSingleSuccessorBlock() == Header && - "Loop not well formed"); + assert(BackEdge->getSingleSuccessorBlock() == header + && "Loop not well formed"); // Check whether the back-edge block is just a split-edge. return ++BackEdge->begin() == BackEdge->end(); @@ -259,153 +260,155 @@ static bool isSingleBlockLoop(SILLoop *L) { /// /// We will rotate at most up to the basic block passed as an argument. /// We will not rotate a loop where the header is equal to the latch except is -/// RotateSingleBlockLoops is true. +/// rotateSingleBlockLoops is true. /// /// Note: The code relies on the 'UpTo' basic block to stay within the rotate /// loop for termination. -bool swift::rotateLoop(SILLoop *L, DominanceInfo *DT, SILLoopInfo *LI, - bool RotateSingleBlockLoops, SILBasicBlock *UpTo, - bool ShouldVerify) { - assert(L != nullptr && DT != nullptr && LI != nullptr && - "Missing loop information"); +bool swift::rotateLoop(SILLoop *loop, DominanceInfo *domInfo, + SILLoopInfo *loopInfo, bool rotateSingleBlockLoops, + SILBasicBlock *upToBB, bool shouldVerify) { + assert(loop != nullptr && domInfo != nullptr && loopInfo != nullptr + && "Missing loop information"); - auto *Header = L->getHeader(); - if (!Header) + auto *header = loop->getHeader(); + if (!header) return false; // We need a preheader - this is also a canonicalization for follow-up // passes. - auto *Preheader = L->getLoopPreheader(); - if (!Preheader) { - LLVM_DEBUG(llvm::dbgs() << *L << " no preheader\n"); - LLVM_DEBUG(L->getHeader()->getParent()->dump()); + auto *preheader = loop->getLoopPreheader(); + if (!preheader) { + LLVM_DEBUG(llvm::dbgs() << *loop << " no preheader\n"); + LLVM_DEBUG(loop->getHeader()->getParent()->dump()); return false; } - if (!RotateSingleBlockLoops && (Header == UpTo || isSingleBlockLoop(L))) + if (!rotateSingleBlockLoops && (header == upToBB || isSingleBlockLoop(loop))) return false; - assert(RotateSingleBlockLoops || L->getBlocks().size() != 1); + assert(rotateSingleBlockLoops || loop->getBlocks().size() != 1); // Need a conditional branch that guards the entry into the loop. - auto *LoopEntryBranch = dyn_cast(Header->getTerminator()); - if (!LoopEntryBranch) + auto *loopEntryBranch = dyn_cast(header->getTerminator()); + if (!loopEntryBranch) return false; // The header needs to exit the loop. - if (!L->isLoopExiting(Header)) { - LLVM_DEBUG(llvm::dbgs() << *L << " not an exiting header\n"); - LLVM_DEBUG(L->getHeader()->getParent()->dump()); + if (!loop->isLoopExiting(header)) { + LLVM_DEBUG(llvm::dbgs() << *loop << " not an exiting header\n"); + LLVM_DEBUG(loop->getHeader()->getParent()->dump()); return false; } // We need a single backedge and the latch must not exit the loop if it is // also the header. - auto *Latch = L->getLoopLatch(); - if (!Latch) { - LLVM_DEBUG(llvm::dbgs() << *L << " no single latch\n"); + auto *latch = loop->getLoopLatch(); + if (!latch) { + LLVM_DEBUG(llvm::dbgs() << *loop << " no single latch\n"); return false; } // Make sure we can duplicate the header. - SmallVector MoveToPreheader; - if (!canDuplicateOrMoveToPreheader(L, Preheader, Header, MoveToPreheader)) { - LLVM_DEBUG(llvm::dbgs() << *L - << " instructions in header preventing rotating\n"); + SmallVector moveToPreheader; + if (!canDuplicateOrMoveToPreheader(loop, preheader, header, + moveToPreheader)) { + LLVM_DEBUG(llvm::dbgs() + << *loop << " instructions in header preventing rotating\n"); return false; } - auto *NewHeader = LoopEntryBranch->getTrueBB(); - auto *Exit = LoopEntryBranch->getFalseBB(); - if (L->contains(Exit)) - std::swap(NewHeader, Exit); - assert(L->contains(NewHeader) && !L->contains(Exit) && - "Could not find loop header and exit block"); + auto *newHeader = loopEntryBranch->getTrueBB(); + auto *exit = loopEntryBranch->getFalseBB(); + if (loop->contains(exit)) + std::swap(newHeader, exit); + assert(loop->contains(newHeader) && !loop->contains(exit) + && "Could not find loop header and exit block"); // We don't want to rotate such that we merge two headers of separate loops // into one. This can be turned into an assert again once we have guaranteed // preheader insertions. - if (!NewHeader->getSinglePredecessorBlock() && Header != Latch) + if (!newHeader->getSinglePredecessorBlock() && header != latch) return false; // Now that we know we can perform the rotation - move the instructions that // need moving. - for (auto *Inst : MoveToPreheader) - Inst->moveBefore(Preheader->getTerminator()); + for (auto *inst : moveToPreheader) + inst->moveBefore(preheader->getTerminator()); - LLVM_DEBUG(llvm::dbgs() << " Rotating " << *L); + LLVM_DEBUG(llvm::dbgs() << " Rotating " << *loop); // Map the values for the duplicated header block. We are duplicating the // header instructions into the end of the preheader. - llvm::DenseMap ValueMap; + llvm::DenseMap valueMap; // The original 'phi' argument values are just the values coming from the // preheader edge. - ArrayRef PHIs = Header->getArguments(); - OperandValueArrayRef PreheaderArgs = - cast(Preheader->getTerminator())->getArgs(); - assert(PHIs.size() == PreheaderArgs.size() && - "Basic block arguments and incoming edge mismatch"); + ArrayRef phis = header->getArguments(); + OperandValueArrayRef preheaderArgs = + cast(preheader->getTerminator())->getArgs(); + assert(phis.size() == preheaderArgs.size() + && "Basic block arguments and incoming edge mismatch"); // Here we also store the value index to use into the value map (versus // non-argument values where the operand use decides which value index to // use). - for (unsigned Idx = 0, E = PHIs.size(); Idx != E; ++Idx) - ValueMap[PHIs[Idx]] = PreheaderArgs[Idx]; + for (unsigned Idx = 0, E = phis.size(); Idx != E; ++Idx) + valueMap[phis[Idx]] = preheaderArgs[Idx]; // The other instructions are just cloned to the preheader. - TermInst *PreheaderBranch = Preheader->getTerminator(); - for (auto &Inst : *Header) { - if (SILInstruction *cloned = Inst.clone(PreheaderBranch)) { - mapOperands(cloned, ValueMap); + TermInst *preheaderBranch = preheader->getTerminator(); + for (auto &inst : *header) { + if (SILInstruction *cloned = inst.clone(preheaderBranch)) { + mapOperands(cloned, valueMap); // The actual operand will sort out which result idx to use. - auto instResults = Inst.getResults(); + auto instResults = inst.getResults(); auto clonedResults = cloned->getResults(); assert(instResults.size() == clonedResults.size()); for (auto i : indices(instResults)) - ValueMap[instResults[i]] = clonedResults[i]; + valueMap[instResults[i]] = clonedResults[i]; } } - PreheaderBranch->dropAllReferences(); - PreheaderBranch->eraseFromParent(); + preheaderBranch->dropAllReferences(); + preheaderBranch->eraseFromParent(); // If there were any uses of instructions in the duplicated loop entry check // block rewrite them using the ssa updater. - rewriteNewLoopEntryCheckBlock(Header, Preheader, ValueMap); + rewriteNewLoopEntryCheckBlock(header, preheader, valueMap); - L->moveToHeader(NewHeader); + loop->moveToHeader(newHeader); // Now the original preheader dominates all of headers children and the // original latch dominates the header. - updateDomTree(DT, Preheader, Latch, Header); + updateDomTree(domInfo, preheader, latch, header); - assert(DT->getNode(NewHeader)->getIDom() == DT->getNode(Preheader)); - assert(!DT->dominates(Header, Exit) || - DT->getNode(Exit)->getIDom() == DT->getNode(Preheader)); - assert(DT->getNode(Header)->getIDom() == DT->getNode(Latch) || - ((Header == Latch) && - DT->getNode(Header)->getIDom() == DT->getNode(Preheader))); + assert(domInfo->getNode(newHeader)->getIDom() == domInfo->getNode(preheader)); + assert(!domInfo->dominates(header, exit) + || domInfo->getNode(exit)->getIDom() == domInfo->getNode(preheader)); + assert(domInfo->getNode(header)->getIDom() == domInfo->getNode(latch) + || ((header == latch) + && domInfo->getNode(header)->getIDom() + == domInfo->getNode(preheader))); // Beautify the IR. Move the old header to after the old latch as it is now // the latch. - Header->moveAfter(Latch); + header->moveAfter(latch); // Merge the old latch with the old header if possible. - mergeBasicBlockWithSuccessor(Latch, DT, LI); + mergeBasicBlockWithSuccessor(latch, domInfo, loopInfo); // Create a new preheader. - splitIfCriticalEdge(Preheader, NewHeader, DT, LI); + splitIfCriticalEdge(preheader, newHeader, domInfo, loopInfo); - if (ShouldVerify) { - DT->verify(); - LI->verify(); - Latch->getParent()->verify(); + if (shouldVerify) { + domInfo->verify(); + loopInfo->verify(); + latch->getParent()->verify(); } - LLVM_DEBUG(llvm::dbgs() << " to " << *L); - LLVM_DEBUG(L->getHeader()->getParent()->dump()); + LLVM_DEBUG(llvm::dbgs() << " to " << *loop); + LLVM_DEBUG(loop->getHeader()->getParent()->dump()); return true; } @@ -414,58 +417,59 @@ namespace { class LoopRotation : public SILFunctionTransform { void run() override { - SILLoopAnalysis *LA = PM->getAnalysis(); - assert(LA); - DominanceAnalysis *DA = PM->getAnalysis(); - assert(DA); + SILLoopAnalysis *loopAnalysis = PM->getAnalysis(); + assert(loopAnalysis); + DominanceAnalysis *domAnalysis = PM->getAnalysis(); + assert(domAnalysis); - SILFunction *F = getFunction(); - assert(F); + SILFunction *f = getFunction(); + assert(f); // FIXME: Add ownership support. - if (F->hasOwnership()) + if (f->hasOwnership()) return; - SILLoopInfo *LI = LA->get(F); - assert(LI); - DominanceInfo *DT = DA->get(F); + SILLoopInfo *loopInfo = loopAnalysis->get(f); + assert(loopInfo); + DominanceInfo *domInfo = domAnalysis->get(f); - if (LI->empty()) { - LLVM_DEBUG(llvm::dbgs() << "No loops in " << F->getName() << "\n"); + if (loopInfo->empty()) { + LLVM_DEBUG(llvm::dbgs() << "No loops in " << f->getName() << "\n"); return; } if (!ShouldRotate) { - LLVM_DEBUG(llvm::dbgs() << "Skipping loop rotation in " << F->getName() - << "\n"); + LLVM_DEBUG(llvm::dbgs() + << "Skipping loop rotation in " << f->getName() << "\n"); return; } - LLVM_DEBUG(llvm::dbgs() << "Rotating loops in " << F->getName() << "\n"); - bool ShouldVerify = getOptions().VerifyAll; + LLVM_DEBUG(llvm::dbgs() << "Rotating loops in " << f->getName() << "\n"); + bool shouldVerify = getOptions().VerifyAll; - bool Changed = false; - for (auto *LoopIt : *LI) { + bool changed = false; + for (auto *LoopIt : *loopInfo) { // Rotate loops recursively bottom-up in the loop tree. - SmallVector Worklist; - Worklist.push_back(LoopIt); - for (unsigned i = 0; i < Worklist.size(); ++i) { - auto *L = Worklist[i]; + SmallVector worklist; + worklist.push_back(LoopIt); + for (unsigned i = 0; i < worklist.size(); ++i) { + auto *L = worklist[i]; for (auto *SubLoop : *L) - Worklist.push_back(SubLoop); + worklist.push_back(SubLoop); } - while (!Worklist.empty()) { - SILLoop *Loop = Worklist.pop_back_val(); - Changed |= canonicalizeLoop(Loop, DT, LI); - Changed |= rotateLoopAtMostUpToLatch(Loop, DT, LI, ShouldVerify); + while (!worklist.empty()) { + SILLoop *loop = worklist.pop_back_val(); + changed |= canonicalizeLoop(loop, domInfo, loopInfo); + changed |= + rotateLoopAtMostUpToLatch(loop, domInfo, loopInfo, shouldVerify); } } - if (Changed) { + if (changed) { // We preserve loop info and the dominator tree. - DA->lockInvalidation(); - LA->lockInvalidation(); - PM->invalidateAnalysis(F, SILAnalysis::InvalidationKind::FunctionBody); - DA->unlockInvalidation(); - LA->unlockInvalidation(); + domAnalysis->lockInvalidation(); + loopAnalysis->lockInvalidation(); + PM->invalidateAnalysis(f, SILAnalysis::InvalidationKind::FunctionBody); + domAnalysis->unlockInvalidation(); + loopAnalysis->unlockInvalidation(); } } }; diff --git a/lib/SILOptimizer/Mandatory/AddressLowering.cpp b/lib/SILOptimizer/Mandatory/AddressLowering.cpp index 864f1464ab0..061bdab9cb2 100644 --- a/lib/SILOptimizer/Mandatory/AddressLowering.cpp +++ b/lib/SILOptimizer/Mandatory/AddressLowering.cpp @@ -96,7 +96,7 @@ #include "swift/SIL/SILVisitor.h" #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SetVector.h" #include "llvm/Support/CommandLine.h" diff --git a/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp b/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp index 2a54afb4835..d0c9c67e5c4 100644 --- a/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp +++ b/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp @@ -19,8 +19,8 @@ #include "swift/SIL/SILInstruction.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILSSAUpdater.h" #include "swift/SILOptimizer/Utils/StackNesting.h" diff --git a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp index dbab75c357f..531d68083f6 100644 --- a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp +++ b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp @@ -22,8 +22,8 @@ #include "swift/SIL/SILBuilder.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/Statistic.h" diff --git a/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp b/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp index d7af3f17fc2..3a60405702a 100644 --- a/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp +++ b/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp @@ -22,8 +22,8 @@ #include "swift/SIL/SILUndef.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" diff --git a/lib/SILOptimizer/Mandatory/IRGenPrepare.cpp b/lib/SILOptimizer/Mandatory/IRGenPrepare.cpp index 811b212bdd6..6da647c6944 100644 --- a/lib/SILOptimizer/Mandatory/IRGenPrepare.cpp +++ b/lib/SILOptimizer/Mandatory/IRGenPrepare.cpp @@ -27,7 +27,7 @@ #include "swift/SIL/SILModule.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/Strings.h" using namespace swift; diff --git a/lib/SILOptimizer/Mandatory/MandatoryCombine.cpp b/lib/SILOptimizer/Mandatory/MandatoryCombine.cpp index ea6126fa0f1..3e0d256aaeb 100644 --- a/lib/SILOptimizer/Mandatory/MandatoryCombine.cpp +++ b/lib/SILOptimizer/Mandatory/MandatoryCombine.cpp @@ -31,7 +31,7 @@ #include "swift/SIL/SILVisitor.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/raw_ostream.h" diff --git a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp index 76341b3f622..6504b6f338f 100644 --- a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp +++ b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp @@ -20,9 +20,9 @@ #include "swift/SIL/OwnershipUtils.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "swift/SILOptimizer/Utils/Devirtualize.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILInliner.h" #include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/Utils/StackNesting.h" diff --git a/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp b/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp index 09551d05779..e0e9026a256 100644 --- a/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp +++ b/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp @@ -87,7 +87,7 @@ #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Utils/ConstExpr.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILInliner.h" #include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "llvm/ADT/MapVector.h" diff --git a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp index df5a0c71421..2e814332b30 100644 --- a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp +++ b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp @@ -19,7 +19,7 @@ #include "swift/SIL/SILBuilder.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILSSAUpdater.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/Statistic.h" diff --git a/lib/SILOptimizer/Mandatory/SILGenCleanup.cpp b/lib/SILOptimizer/Mandatory/SILGenCleanup.cpp index 5b51c722ec2..eb4c12f4d99 100644 --- a/lib/SILOptimizer/Mandatory/SILGenCleanup.cpp +++ b/lib/SILOptimizer/Mandatory/SILGenCleanup.cpp @@ -19,7 +19,7 @@ #include "swift/SIL/SILInstruction.h" #include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Utils/CanonicalizeInstruction.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" using namespace swift; diff --git a/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp b/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp index 3894db77610..72fa8368a7f 100644 --- a/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp +++ b/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp @@ -24,7 +24,7 @@ #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" diff --git a/lib/SILOptimizer/PassManager/PassPipeline.cpp b/lib/SILOptimizer/PassManager/PassPipeline.cpp index 997efa8264c..79974aaa9db 100644 --- a/lib/SILOptimizer/PassManager/PassPipeline.cpp +++ b/lib/SILOptimizer/PassManager/PassPipeline.cpp @@ -27,7 +27,7 @@ #include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" diff --git a/lib/SILOptimizer/PassManager/Passes.cpp b/lib/SILOptimizer/PassManager/Passes.cpp index 4317e83ffad..ce715dbd658 100644 --- a/lib/SILOptimizer/PassManager/Passes.cpp +++ b/lib/SILOptimizer/PassManager/Passes.cpp @@ -21,14 +21,14 @@ #define DEBUG_TYPE "sil-optimizer" +#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Module.h" #include "swift/SIL/SILModule.h" #include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SILOptimizer/PassManager/PassManager.h" -#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" diff --git a/lib/SILOptimizer/SILCombiner/SILCombine.cpp b/lib/SILOptimizer/SILCombiner/SILCombine.cpp index 7f0893d0b8f..e0b9dae9019 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombine.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombine.cpp @@ -28,7 +28,7 @@ #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Utils/CanonicalizeInstruction.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" diff --git a/lib/SILOptimizer/SILCombiner/SILCombiner.h b/lib/SILOptimizer/SILCombiner/SILCombiner.h index 1a76e0d8425..609bfe79df3 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombiner.h +++ b/lib/SILOptimizer/SILCombiner/SILCombiner.h @@ -30,7 +30,7 @@ #include "swift/SILOptimizer/Analysis/ProtocolConformanceAnalysis.h" #include "swift/SILOptimizer/Utils/CastOptimizer.h" #include "swift/SILOptimizer/Utils/Existential.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp index aefddbd51de..6f9af158319 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp @@ -24,9 +24,10 @@ #include "swift/SIL/SILVisitor.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" -#include "swift/SILOptimizer/Analysis/CFG.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "swift/SILOptimizer/Utils/Existential.h" +#include "swift/SILOptimizer/Utils/ValueLifetime.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerBuiltinVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerBuiltinVisitors.cpp index 9227db10cf1..7c37686e464 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerBuiltinVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerBuiltinVisitors.cpp @@ -12,19 +12,19 @@ #define DEBUG_TYPE "sil-combine" #include "SILCombiner.h" +#include "swift/SIL/DebugUtils.h" #include "swift/SIL/DynamicCasts.h" #include "swift/SIL/PatternMatch.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILVisitor.h" -#include "swift/SIL/DebugUtils.h" -#include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" -#include "swift/SILOptimizer/Analysis/CFG.h" +#include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/DenseMap.h" using namespace swift; using namespace swift::PatternMatch; diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp index 9d020bbb4ff..eee7bf3a22f 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp @@ -12,19 +12,19 @@ #define DEBUG_TYPE "sil-combine" #include "SILCombiner.h" +#include "swift/SIL/DebugUtils.h" #include "swift/SIL/DynamicCasts.h" #include "swift/SIL/PatternMatch.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILVisitor.h" -#include "swift/SIL/DebugUtils.h" -#include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" -#include "swift/SILOptimizer/Analysis/CFG.h" +#include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/DenseMap.h" using namespace swift; using namespace swift::PatternMatch; diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp index 0cf87916044..aa41f2c8d55 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp @@ -22,10 +22,10 @@ #include "swift/SIL/SILVisitor.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" -#include "swift/SILOptimizer/Analysis/CFG.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "swift/SILOptimizer/Utils/Devirtualize.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" diff --git a/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp b/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp index 8815b5be162..22af78be9fc 100644 --- a/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp +++ b/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp @@ -80,8 +80,8 @@ #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/Strings.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallPtrSet.h" diff --git a/lib/SILOptimizer/Transforms/AccessEnforcementDom.cpp b/lib/SILOptimizer/Transforms/AccessEnforcementDom.cpp index a9a6a88512b..d454493053f 100644 --- a/lib/SILOptimizer/Transforms/AccessEnforcementDom.cpp +++ b/lib/SILOptimizer/Transforms/AccessEnforcementDom.cpp @@ -56,7 +56,7 @@ #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/Analysis/LoopAnalysis.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/DepthFirstIterator.h" using namespace swift; diff --git a/lib/SILOptimizer/Transforms/AccessEnforcementOpts.cpp b/lib/SILOptimizer/Transforms/AccessEnforcementOpts.cpp index 9ea227ae398..8aadfb4ce1f 100644 --- a/lib/SILOptimizer/Transforms/AccessEnforcementOpts.cpp +++ b/lib/SILOptimizer/Transforms/AccessEnforcementOpts.cpp @@ -84,7 +84,7 @@ #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/Analysis/LoopRegionAnalysis.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SCCIterator.h" diff --git a/lib/SILOptimizer/Transforms/AccessEnforcementWMO.cpp b/lib/SILOptimizer/Transforms/AccessEnforcementWMO.cpp index 3dd7fd1bfc2..65df81551ad 100644 --- a/lib/SILOptimizer/Transforms/AccessEnforcementWMO.cpp +++ b/lib/SILOptimizer/Transforms/AccessEnforcementWMO.cpp @@ -59,7 +59,7 @@ #include "swift/SIL/MemAccessUtils.h" #include "swift/SIL/SILFunction.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" using namespace swift; diff --git a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp index 5168f730e1b..3f52bb1c059 100644 --- a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp +++ b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp @@ -11,16 +11,17 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "allocbox-to-stack" +#include "swift/SIL/ApplySite.h" #include "swift/SIL/Dominance.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILCloner.h" -#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/Utils/SpecializationMangler.h" #include "swift/SILOptimizer/Utils/StackNesting.h" +#include "swift/SILOptimizer/Utils/ValueLifetime.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" diff --git a/lib/SILOptimizer/Transforms/AssumeSingleThreaded.cpp b/lib/SILOptimizer/Transforms/AssumeSingleThreaded.cpp index 558752006ea..8668a6971fc 100644 --- a/lib/SILOptimizer/Transforms/AssumeSingleThreaded.cpp +++ b/lib/SILOptimizer/Transforms/AssumeSingleThreaded.cpp @@ -25,12 +25,12 @@ // //===----------------------------------------------------------------------===// -#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILModule.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/Support/CommandLine.h" using namespace swift; diff --git a/lib/SILOptimizer/Transforms/CSE.cpp b/lib/SILOptimizer/Transforms/CSE.cpp index 79d57506eba..8021602717f 100644 --- a/lib/SILOptimizer/Transforms/CSE.cpp +++ b/lib/SILOptimizer/Transforms/CSE.cpp @@ -16,24 +16,25 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "sil-cse" -#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SIL/DebugUtils.h" #include "swift/SIL/Dominance.h" +#include "swift/SIL/SILCloner.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILOpenedArchetypesTracker.h" #include "swift/SIL/SILType.h" #include "swift/SIL/SILValue.h" #include "swift/SIL/SILVisitor.h" -#include "swift/SIL/DebugUtils.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Analysis/ArraySemantic.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" -#include "swift/SILOptimizer/Analysis/SimplifyInstruction.h" #include "swift/SILOptimizer/Analysis/SideEffectAnalysis.h" +#include "swift/SILOptimizer/Analysis/SimplifyInstruction.h" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/Hashing.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ScopedHashTable.h" #include "llvm/ADT/Statistic.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" #include "llvm/Support/RecyclingAllocator.h" diff --git a/lib/SILOptimizer/Transforms/CopyForwarding.cpp b/lib/SILOptimizer/Transforms/CopyForwarding.cpp index ae4d669aa85..c33bf4bddbf 100644 --- a/lib/SILOptimizer/Transforms/CopyForwarding.cpp +++ b/lib/SILOptimizer/Transforms/CopyForwarding.cpp @@ -68,7 +68,7 @@ #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/CommandLine.h" diff --git a/lib/SILOptimizer/Transforms/CopyPropagation.cpp b/lib/SILOptimizer/Transforms/CopyPropagation.cpp index 72fd3d8c259..185e900052f 100644 --- a/lib/SILOptimizer/Transforms/CopyPropagation.cpp +++ b/lib/SILOptimizer/Transforms/CopyPropagation.cpp @@ -127,9 +127,9 @@ #include "swift/SIL/Projection.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "swift/SILOptimizer/Utils/IndexTrie.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Statistic.h" diff --git a/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp b/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp index c8e2bee00b9..bc9dc78059b 100644 --- a/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp +++ b/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp @@ -11,19 +11,19 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "sil-dce" +#include "swift/SIL/DebugUtils.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBasicBlock.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILUndef.h" -#include "swift/SIL/DebugUtils.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" diff --git a/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp b/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp index 442978d1383..6056b412224 100644 --- a/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp +++ b/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp @@ -24,8 +24,10 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "dead-object-elim" -#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/AST/ResilienceExpansion.h" +#include "swift/SIL/BasicBlockUtils.h" +#include "swift/SIL/DebugUtils.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SIL/Projection.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILDeclRef.h" @@ -33,14 +35,13 @@ #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILUndef.h" -#include "swift/SIL/DebugUtils.h" -#include "swift/SIL/InstructionUtils.h" -#include "swift/SIL/BasicBlockUtils.h" #include "swift/SILOptimizer/Analysis/ArraySemantic.h" -#include "swift/SILOptimizer/Utils/IndexTrie.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SILOptimizer/Utils/SILSSAUpdater.h" +#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/IndexTrie.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/SILSSAUpdater.h" +#include "swift/SILOptimizer/Utils/ValueLifetime.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" diff --git a/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp b/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp index 057d122b01b..9dc817b7337 100644 --- a/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp +++ b/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp @@ -64,12 +64,12 @@ #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/LoadStoreOptUtils.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/BitVector.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/Statistic.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" diff --git a/lib/SILOptimizer/Transforms/DestroyHoisting.cpp b/lib/SILOptimizer/Transforms/DestroyHoisting.cpp index e23458a2cf1..d3ab5ab15fd 100644 --- a/lib/SILOptimizer/Transforms/DestroyHoisting.cpp +++ b/lib/SILOptimizer/Transforms/DestroyHoisting.cpp @@ -13,9 +13,9 @@ #define DEBUG_TYPE "sil-destroy-hoisting" #include "swift/SIL/MemoryLifetime.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/Transforms/GenericSpecializer.cpp b/lib/SILOptimizer/Transforms/GenericSpecializer.cpp index 14965b38849..82dd9d4d33c 100644 --- a/lib/SILOptimizer/Transforms/GenericSpecializer.cpp +++ b/lib/SILOptimizer/Transforms/GenericSpecializer.cpp @@ -20,9 +20,9 @@ #include "swift/SIL/OptimizationRemark.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" -#include "swift/SILOptimizer/Utils/Generics.h" -#include "swift/SILOptimizer/Utils/Local.h" #include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/Generics.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "llvm/ADT/SmallVector.h" diff --git a/lib/SILOptimizer/Transforms/MergeCondFail.cpp b/lib/SILOptimizer/Transforms/MergeCondFail.cpp index e8ad4f8fc5c..0b293850eb7 100644 --- a/lib/SILOptimizer/Transforms/MergeCondFail.cpp +++ b/lib/SILOptimizer/Transforms/MergeCondFail.cpp @@ -12,12 +12,12 @@ #define DEBUG_TYPE "merge-cond_fail" +#include "swift/SIL/SILBuilder.h" +#include "swift/SIL/SILInstruction.h" #include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SIL/SILBuilder.h" -#include "swift/SIL/SILInstruction.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/Support/Debug.h" diff --git a/lib/SILOptimizer/Transforms/ObjectOutliner.cpp b/lib/SILOptimizer/Transforms/ObjectOutliner.cpp index 71c67baedc9..688ca6c30db 100644 --- a/lib/SILOptimizer/Transforms/ObjectOutliner.cpp +++ b/lib/SILOptimizer/Transforms/ObjectOutliner.cpp @@ -14,9 +14,9 @@ #include "swift/AST/ASTMangler.h" #include "swift/SIL/DebugUtils.h" #include "swift/SIL/SILBuilder.h" -#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" +#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp b/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp index 4dfdf1f3a04..dce868a8902 100644 --- a/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp +++ b/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp @@ -29,7 +29,7 @@ #include "swift/SIL/SILVisitor.h" #include "swift/SILOptimizer/Analysis/SimplifyInstruction.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/Support/CommandLine.h" using namespace swift; diff --git a/lib/SILOptimizer/Transforms/PerformanceInliner.cpp b/lib/SILOptimizer/Transforms/PerformanceInliner.cpp index a8f04bb04c9..961c6b57419 100644 --- a/lib/SILOptimizer/Transforms/PerformanceInliner.cpp +++ b/lib/SILOptimizer/Transforms/PerformanceInliner.cpp @@ -17,7 +17,7 @@ #include "swift/SILOptimizer/Analysis/SideEffectAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "swift/SILOptimizer/Utils/Devirtualize.h" #include "swift/SILOptimizer/Utils/Generics.h" #include "swift/SILOptimizer/Utils/PerformanceInlinerUtils.h" diff --git a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp b/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp index 6bfe200e5c5..51af6042e5a 100644 --- a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp +++ b/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp @@ -76,15 +76,15 @@ #include "swift/SIL/Projection.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBuilder.h" -#include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" +#include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/LoadStoreOptUtils.h" #include "swift/SILOptimizer/Utils/SILSSAUpdater.h" #include "llvm/ADT/BitVector.h" diff --git a/lib/SILOptimizer/Transforms/RedundantOverflowCheckRemoval.cpp b/lib/SILOptimizer/Transforms/RedundantOverflowCheckRemoval.cpp index 483ec3eab3d..63615c2c5cc 100644 --- a/lib/SILOptimizer/Transforms/RedundantOverflowCheckRemoval.cpp +++ b/lib/SILOptimizer/Transforms/RedundantOverflowCheckRemoval.cpp @@ -16,13 +16,13 @@ #define DEBUG_TYPE "remove-redundant-overflow-checks" #include "swift/SIL/Dominance.h" +#include "swift/SIL/SILInstruction.h" +#include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" -#include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SIL/SILInstruction.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" diff --git a/lib/SILOptimizer/Transforms/SILCodeMotion.cpp b/lib/SILOptimizer/Transforms/SILCodeMotion.cpp index cbb85bf7e16..a732dc12d8b 100644 --- a/lib/SILOptimizer/Transforms/SILCodeMotion.cpp +++ b/lib/SILOptimizer/Transforms/SILCodeMotion.cpp @@ -11,21 +11,21 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "sil-codemotion" -#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/AST/Module.h" #include "swift/Basic/BlotMapVector.h" +#include "swift/SIL/DebugUtils.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILType.h" #include "swift/SIL/SILValue.h" #include "swift/SIL/SILVisitor.h" -#include "swift/SIL/DebugUtils.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" +#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Statistic.h" diff --git a/lib/SILOptimizer/Transforms/SILLowerAggregateInstrs.cpp b/lib/SILOptimizer/Transforms/SILLowerAggregateInstrs.cpp index ad6f1f757d0..bb03fe51795 100644 --- a/lib/SILOptimizer/Transforms/SILLowerAggregateInstrs.cpp +++ b/lib/SILOptimizer/Transforms/SILLowerAggregateInstrs.cpp @@ -23,7 +23,7 @@ #include "swift/SIL/TypeLowering.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/Transforms/SILMem2Reg.cpp b/lib/SILOptimizer/Transforms/SILMem2Reg.cpp index 7386f16c3b9..51a4493a7da 100644 --- a/lib/SILOptimizer/Transforms/SILMem2Reg.cpp +++ b/lib/SILOptimizer/Transforms/SILMem2Reg.cpp @@ -20,23 +20,23 @@ #define DEBUG_TYPE "sil-mem2reg" -#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/AST/DiagnosticsSIL.h" #include "swift/SIL/Dominance.h" +#include "swift/SIL/Projection.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILModule.h" -#include "swift/SIL/Projection.h" #include "swift/SIL/TypeLowering.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" -#include "llvm/ADT/DenseSet.h" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" #include #include diff --git a/lib/SILOptimizer/Transforms/SILSROA.cpp b/lib/SILOptimizer/Transforms/SILSROA.cpp index 50fa0d4f5a7..a15fe415ebf 100644 --- a/lib/SILOptimizer/Transforms/SILSROA.cpp +++ b/lib/SILOptimizer/Transforms/SILSROA.cpp @@ -26,7 +26,7 @@ #include "swift/SIL/SILUndef.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Debug.h" diff --git a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp index 95c3663dda1..bb4c3fb97d8 100644 --- a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp +++ b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp @@ -24,12 +24,13 @@ #include "swift/SILOptimizer/Analysis/SimplifyInstruction.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "swift/SILOptimizer/Utils/CastOptimizer.h" -#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" -#include "swift/SILOptimizer/Utils/Local.h" #include "swift/SILOptimizer/Utils/ConstantFolding.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILInliner.h" +#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/Utils/SILSSAUpdater.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" @@ -201,125 +202,6 @@ namespace { } // end anonymous namespace -/// Return true if there are any users of V outside the specified block. -static bool isUsedOutsideOfBlock(SILValue V, SILBasicBlock *BB) { - for (auto UI : V->getUses()) - if (UI->getUser()->getParent() != BB) - return true; - return false; -} - -// Populate 'projections' with the chain of address projections leading -// to and including 'inst'. -// -// Populate 'inBlockDefs' with all the non-address value definitions in -// the block that will be used outside this block after projection sinking. -// -// Return true on success, even if projections is empty. -bool SinkAddressProjections::analyzeAddressProjections(SILInstruction *inst) { - projections.clear(); - inBlockDefs.clear(); - - SILBasicBlock *bb = inst->getParent(); - auto pushOperandVal = [&](SILValue def) { - if (def->getParentBlock() != bb) - return true; - - if (!def->getType().isAddress()) { - inBlockDefs.insert(def); - return true; - } - if (auto *addressProj = dyn_cast(def)) { - if (addressProj->isTriviallyDuplicatable()) { - projections.push_back(addressProj); - return true; - } - } - // Can't handle a multi-value or unclonable address producer. - return false; - }; - // Check the given instruction for any address-type results. - for (auto result : inst->getResults()) { - if (!isUsedOutsideOfBlock(result, bb)) - continue; - if (!pushOperandVal(result)) - return false; - } - // Recurse upward through address projections. - for (unsigned idx = 0; idx < projections.size(); ++idx) { - // Only one address result/operand can be handled per instruction. - if (projections.size() != idx + 1) - return false; - - for (SILValue operandVal : projections[idx]->getOperandValues()) - pushOperandVal(operandVal); - } - return true; -} - -// Clone the projections gathered by 'analyzeAddressProjections' at -// their use site outside this block. -bool SinkAddressProjections::cloneProjections() { - if (projections.empty()) - return false; - - SILBasicBlock *bb = projections.front()->getParent(); - SmallVector usesToReplace; - // Clone projections in last-to-first order. - for (unsigned idx = 0; idx < projections.size(); ++idx) { - auto *oldProj = projections[idx]; - assert(oldProj->getParent() == bb); - usesToReplace.clear(); - for (Operand *use : oldProj->getUses()) { - if (use->getUser()->getParent() != bb) - usesToReplace.push_back(use); - } - for (Operand *use : usesToReplace) { - auto *newProj = oldProj->clone(use->getUser()); - use->set(cast(newProj)); - } - } - return true; -} - -/// Helper function to perform SSA updates in case of jump threading. -void swift::updateSSAAfterCloning(BasicBlockCloner &Cloner, - SILBasicBlock *SrcBB, SILBasicBlock *DestBB) { - SILSSAUpdater SSAUp; - for (auto AvailValPair : Cloner.AvailVals) { - ValueBase *Inst = AvailValPair.first; - if (Inst->use_empty()) - continue; - - SILValue NewRes(AvailValPair.second); - - SmallVector UseList; - // Collect the uses of the value. - for (auto Use : Inst->getUses()) - UseList.push_back(UseWrapper(Use)); - - SSAUp.Initialize(Inst->getType()); - SSAUp.AddAvailableValue(DestBB, Inst); - SSAUp.AddAvailableValue(SrcBB, NewRes); - - if (UseList.empty()) - continue; - - // Update all the uses. - for (auto U : UseList) { - Operand *Use = U; - SILInstruction *User = Use->getUser(); - assert(User && "Missing user"); - - // Ignore uses in the same basic block. - if (User->getParent() == DestBB) - continue; - - SSAUp.RewriteUse(*Use); - } - } -} - static SILValue getTerminatorCondition(TermInst *Term) { if (auto *CondBr = dyn_cast(Term)) return stripExpectIntrinsic(CondBr->getCondition()); @@ -1044,7 +926,7 @@ bool SimplifyCFG::tryJumpThreading(BranchInst *BI) { // Are the arguments to this block used outside of the block. for (auto Arg : DestBB->getArguments()) - if ((NeedToUpdateSSA |= isUsedOutsideOfBlock(Arg, DestBB))) { + if ((NeedToUpdateSSA |= isUsedOutsideOfBlock(Arg))) { break; } diff --git a/lib/SILOptimizer/Transforms/Sink.cpp b/lib/SILOptimizer/Transforms/Sink.cpp index a1077f0cf0c..b9b7342c9f7 100644 --- a/lib/SILOptimizer/Transforms/Sink.cpp +++ b/lib/SILOptimizer/Transforms/Sink.cpp @@ -19,18 +19,18 @@ #define DEBUG_TYPE "sink-instructions" -#include "swift/SIL/Dominance.h" -#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" -#include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" -#include "swift/SILOptimizer/Analysis/LoopAnalysis.h" -#include "swift/SILOptimizer/PassManager/Passes.h" -#include "swift/SIL/SILArgument.h" -#include "swift/SIL/SILValue.h" -#include "swift/SIL/SILDebugScope.h" #include "swift/SIL/DebugUtils.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SIL/Dominance.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILDebugScope.h" #include "swift/SIL/SILInstruction.h" +#include "swift/SIL/SILValue.h" +#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" +#include "swift/SILOptimizer/Analysis/LoopAnalysis.h" +#include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" diff --git a/lib/SILOptimizer/Transforms/SpecializeOpaqueArchetypes.cpp b/lib/SILOptimizer/Transforms/SpecializeOpaqueArchetypes.cpp index 25d43696336..b8968e0414e 100644 --- a/lib/SILOptimizer/Transforms/SpecializeOpaqueArchetypes.cpp +++ b/lib/SILOptimizer/Transforms/SpecializeOpaqueArchetypes.cpp @@ -18,10 +18,10 @@ #include "swift/AST/Types.h" #include "swift/SIL/SILFunction.h" -#include "swift/SIL/TypeSubstCloner.h" #include "swift/SIL/SILInstruction.h" +#include "swift/SIL/TypeSubstCloner.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" #include "llvm/Support/CommandLine.h" diff --git a/lib/SILOptimizer/Transforms/StackPromotion.cpp b/lib/SILOptimizer/Transforms/StackPromotion.cpp index 1d3775668a4..b0243dc3198 100644 --- a/lib/SILOptimizer/Transforms/StackPromotion.cpp +++ b/lib/SILOptimizer/Transforms/StackPromotion.cpp @@ -10,15 +10,16 @@ // //===----------------------------------------------------------------------===// -#include "swift/SILOptimizer/PassManager/Passes.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Analysis/EscapeAnalysis.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SILOptimizer/Utils/StackNesting.h" -#include "swift/SIL/SILArgument.h" -#include "swift/SIL/SILBuilder.h" #include "swift/SIL/BasicBlockUtils.h" #include "swift/SIL/CFG.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILBuilder.h" +#include "swift/SILOptimizer/Analysis/EscapeAnalysis.h" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/StackNesting.h" +#include "swift/SILOptimizer/Utils/ValueLifetime.h" #include "llvm/ADT/Statistic.h" #define DEBUG_TYPE "stack-promotion" diff --git a/lib/SILOptimizer/Transforms/UnsafeGuaranteedPeephole.cpp b/lib/SILOptimizer/Transforms/UnsafeGuaranteedPeephole.cpp index 9aa693dc8f6..aa2de64bc4c 100644 --- a/lib/SILOptimizer/Transforms/UnsafeGuaranteedPeephole.cpp +++ b/lib/SILOptimizer/Transforms/UnsafeGuaranteedPeephole.cpp @@ -31,7 +31,6 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "unsafe-guaranteed-peephole" -#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SIL/DebugUtils.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" @@ -39,8 +38,9 @@ #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" +#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" using namespace swift; diff --git a/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp b/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp new file mode 100644 index 00000000000..88f11083c49 --- /dev/null +++ b/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp @@ -0,0 +1,244 @@ +//===--- BasicBlockOptUtils.cpp - SILOptimizer basic block utilities ------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 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 +// +//===----------------------------------------------------------------------===// + +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/SILSSAUpdater.h" + +using namespace swift; + +/// Remove all instructions in the body of \p bb in safe manner by using +/// undef. +void swift::clearBlockBody(SILBasicBlock *bb) { + // Instructions in the dead block may be used by other dead blocks. Replace + // any uses of them with undef values. + while (!bb->empty()) { + // Grab the last instruction in the bb. + auto *inst = &bb->back(); + + // Replace any still-remaining uses with undef values and erase. + inst->replaceAllUsesOfAllResultsWithUndef(); + inst->eraseFromParent(); + } +} + +// Handle the mechanical aspects of removing an unreachable block. +void swift::removeDeadBlock(SILBasicBlock *bb) { + // Clear the body of bb. + clearBlockBody(bb); + + // Now that the bb is empty, eliminate it. + bb->eraseFromParent(); +} + +bool swift::removeUnreachableBlocks(SILFunction &f) { + // All reachable blocks, but does not include the entry block. + llvm::SmallPtrSet visited; + + // Walk over the CFG, starting at the entry block, until all reachable blocks are visited. + llvm::SmallVector worklist(1, f.getEntryBlock()); + while (!worklist.empty()) { + SILBasicBlock *bb = worklist.pop_back_val(); + for (auto &Succ : bb->getSuccessors()) { + if (visited.insert(Succ).second) + worklist.push_back(Succ); + } + } + + // Remove the blocks we never reached. Exclude the entry block from the iteration because it's + // not included in the Visited set. + bool changed = false; + for (auto ii = std::next(f.begin()), end = f.end(); ii != end;) { + auto *bb = &*ii++; + if (!visited.count(bb)) { + removeDeadBlock(bb); + changed = true; + } + } + return changed; +} + +/// Helper function to perform SSA updates in case of jump threading. +void swift::updateSSAAfterCloning(BasicBlockCloner &cloner, + SILBasicBlock *srcBB, SILBasicBlock *destBB) { + SILSSAUpdater ssaUpdater; + for (auto availValPair : cloner.AvailVals) { + ValueBase *inst = availValPair.first; + if (inst->use_empty()) + continue; + + SILValue newResult(availValPair.second); + + SmallVector useList; + // Collect the uses of the value. + for (auto *use : inst->getUses()) + useList.push_back(UseWrapper(use)); + + ssaUpdater.Initialize(inst->getType()); + ssaUpdater.AddAvailableValue(destBB, inst); + ssaUpdater.AddAvailableValue(srcBB, newResult); + + if (useList.empty()) + continue; + + // Update all the uses. + for (auto useWrapper : useList) { + Operand *use = useWrapper; + SILInstruction *user = use->getUser(); + assert(user && "Missing user"); + + // Ignore uses in the same basic block. + if (user->getParent() == destBB) + continue; + + ssaUpdater.RewriteUse(*use); + } + } +} + +// FIXME: Remove this. SILCloner should not create critical edges. +bool BasicBlockCloner::splitCriticalEdges(DominanceInfo *domInfo, + SILLoopInfo *loopInfo) { + bool changed = false; + // Remove any critical edges that the EdgeThreadingCloner may have + // accidentally created. + for (unsigned succIdx = 0, succEnd = origBB->getSuccessors().size(); + succIdx != succEnd; ++succIdx) { + if (nullptr + != splitCriticalEdge(origBB->getTerminator(), succIdx, domInfo, + loopInfo)) + changed |= true; + } + for (unsigned succIdx = 0, succEnd = getNewBB()->getSuccessors().size(); + succIdx != succEnd; ++succIdx) { + auto *newBB = splitCriticalEdge(getNewBB()->getTerminator(), succIdx, + domInfo, loopInfo); + changed |= (newBB != nullptr); + } + return changed; +} + +// Populate 'projections' with the chain of address projections leading +// to and including 'inst'. +// +// Populate 'inBlockDefs' with all the non-address value definitions in +// the block that will be used outside this block after projection sinking. +// +// Return true on success, even if projections is empty. +bool SinkAddressProjections::analyzeAddressProjections(SILInstruction *inst) { + projections.clear(); + inBlockDefs.clear(); + + SILBasicBlock *bb = inst->getParent(); + auto pushOperandVal = [&](SILValue def) { + if (def->getParentBlock() != bb) + return true; + + if (!def->getType().isAddress()) { + inBlockDefs.insert(def); + return true; + } + if (auto *addressProj = dyn_cast(def)) { + if (addressProj->isTriviallyDuplicatable()) { + projections.push_back(addressProj); + return true; + } + } + // Can't handle a multi-value or unclonable address producer. + return false; + }; + // Check the given instruction for any address-type results. + for (auto result : inst->getResults()) { + if (!isUsedOutsideOfBlock(result)) + continue; + if (!pushOperandVal(result)) + return false; + } + // Recurse upward through address projections. + for (unsigned idx = 0; idx < projections.size(); ++idx) { + // Only one address result/operand can be handled per instruction. + if (projections.size() != idx + 1) + return false; + + for (SILValue operandVal : projections[idx]->getOperandValues()) + pushOperandVal(operandVal); + } + return true; +} + +// Clone the projections gathered by 'analyzeAddressProjections' at +// their use site outside this block. +bool SinkAddressProjections::cloneProjections() { + if (projections.empty()) + return false; + + SILBasicBlock *bb = projections.front()->getParent(); + SmallVector usesToReplace; + // Clone projections in last-to-first order. + for (unsigned idx = 0; idx < projections.size(); ++idx) { + auto *oldProj = projections[idx]; + assert(oldProj->getParent() == bb); + usesToReplace.clear(); + for (Operand *use : oldProj->getUses()) { + if (use->getUser()->getParent() != bb) + usesToReplace.push_back(use); + } + for (Operand *use : usesToReplace) { + auto *newProj = oldProj->clone(use->getUser()); + use->set(cast(newProj)); + } + } + return true; +} + +void StaticInitCloner::add(SILInstruction *initVal) { + // Don't schedule an instruction twice for cloning. + if (numOpsToClone.count(initVal) != 0) + return; + + ArrayRef operands = initVal->getAllOperands(); + numOpsToClone[initVal] = operands.size(); + if (operands.empty()) { + // It's an instruction without operands, e.g. a literal. It's ready to be + // cloned first. + readyToClone.push_back(initVal); + } else { + // Recursively add all operands. + for (const Operand &operand : operands) { + add(cast(operand.get())); + } + } +} + +SingleValueInstruction * +StaticInitCloner::clone(SingleValueInstruction *initVal) { + assert(numOpsToClone.count(initVal) != 0 && "initVal was not added"); + // Find the right order to clone: all operands of an instruction must be + // cloned before the instruction itself. + while (!readyToClone.empty()) { + SILInstruction *inst = readyToClone.pop_back_val(); + + // Clone the instruction into the SILGlobalVariable + visit(inst); + + // Check if users of I can now be cloned. + for (SILValue result : inst->getResults()) { + for (Operand *use : result->getUses()) { + SILInstruction *user = use->getUser(); + if (numOpsToClone.count(user) != 0 && --numOpsToClone[user] == 0) + readyToClone.push_back(user); + } + } + } + return cast(getMappedValue(initVal)); +} diff --git a/lib/SILOptimizer/Utils/CFG.cpp b/lib/SILOptimizer/Utils/CFG.cpp deleted file mode 100644 index e92b57bb9ed..00000000000 --- a/lib/SILOptimizer/Utils/CFG.cpp +++ /dev/null @@ -1,743 +0,0 @@ -//===--- CFG.cpp - Utilities for SIL CFG transformations ------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -#include "swift/SIL/BasicBlockUtils.h" -#include "swift/SIL/Dominance.h" -#include "swift/SIL/LoopInfo.h" -#include "swift/SIL/BasicBlockUtils.h" -#include "swift/SIL/SILArgument.h" -#include "swift/SIL/SILBuilder.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" - -using namespace swift; - -/// Adds a new argument to an edge between a branch and a destination -/// block. -/// -/// \param Branch The terminator to add the argument to. -/// \param Dest The destination block of the edge. -/// \param Val The value to the arguments of the branch. -/// \return The created branch. The old branch is deleted. -/// The argument is appended at the end of the argument tuple. -TermInst *swift::addNewEdgeValueToBranch(TermInst *Branch, SILBasicBlock *Dest, - SILValue Val) { - SILBuilderWithScope Builder(Branch); - TermInst *NewBr = nullptr; - - if (auto *CBI = dyn_cast(Branch)) { - SmallVector TrueArgs; - SmallVector FalseArgs; - - for (auto A : CBI->getTrueArgs()) - TrueArgs.push_back(A); - - for (auto A : CBI->getFalseArgs()) - FalseArgs.push_back(A); - - if (Dest == CBI->getTrueBB()) { - TrueArgs.push_back(Val); - assert(TrueArgs.size() == Dest->getNumArguments()); - } - if (Dest == CBI->getFalseBB()) { - FalseArgs.push_back(Val); - assert(FalseArgs.size() == Dest->getNumArguments()); - } - - NewBr = Builder.createCondBranch( - CBI->getLoc(), CBI->getCondition(), CBI->getTrueBB(), TrueArgs, - CBI->getFalseBB(), FalseArgs, CBI->getTrueBBCount(), - CBI->getFalseBBCount()); - } else if (auto *BI = dyn_cast(Branch)) { - SmallVector Args; - - for (auto A : BI->getArgs()) - Args.push_back(A); - - Args.push_back(Val); - assert(Args.size() == Dest->getNumArguments()); - NewBr = Builder.createBranch(BI->getLoc(), BI->getDestBB(), Args); - } else { - // At the moment we can only add arguments to br and cond_br. - llvm_unreachable("Can't add argument to terminator"); - } - - Branch->dropAllReferences(); - Branch->eraseFromParent(); - - return NewBr; -} - -static void -deleteTriviallyDeadOperandsOfDeadArgument(MutableArrayRef termOperands, - unsigned deadArgIndex) { - Operand &op = termOperands[deadArgIndex]; - auto *i = op.get()->getDefiningInstruction(); - if (!i) - return; - op.set(SILUndef::get(op.get()->getType(), *i->getFunction())); - recursivelyDeleteTriviallyDeadInstructions(i); -} - -// Our implementation assumes that our caller is attempting to remove a dead -// SILPhiArgument from a SILBasicBlock and has already RAUWed the argument. -TermInst *swift::deleteEdgeValue(TermInst *branch, SILBasicBlock *destBlock, - size_t argIndex) { - if (auto *cbi = dyn_cast(branch)) { - SmallVector trueArgs; - SmallVector falseArgs; - - llvm::copy(cbi->getTrueArgs(), std::back_inserter(trueArgs)); - llvm::copy(cbi->getFalseArgs(), std::back_inserter(falseArgs)); - - if (destBlock == cbi->getTrueBB()) { - deleteTriviallyDeadOperandsOfDeadArgument(cbi->getTrueOperands(), argIndex); - trueArgs.erase(trueArgs.begin() + argIndex); - } - - if (destBlock == cbi->getFalseBB()) { - deleteTriviallyDeadOperandsOfDeadArgument(cbi->getFalseOperands(), argIndex); - falseArgs.erase(falseArgs.begin() + argIndex); - } - - SILBuilderWithScope builder(cbi); - auto *result = builder.createCondBranch(cbi->getLoc(), cbi->getCondition(), - cbi->getTrueBB(), trueArgs, cbi->getFalseBB(), - falseArgs, cbi->getTrueBBCount(), - cbi->getFalseBBCount()); - branch->eraseFromParent(); - return result; - } - - if (auto *bi = dyn_cast(branch)) { - SmallVector args; - llvm::copy(bi->getArgs(), std::back_inserter(args)); - - deleteTriviallyDeadOperandsOfDeadArgument(bi->getAllOperands(), argIndex); - args.erase(args.begin() + argIndex); - auto *result = SILBuilderWithScope(bi).createBranch(bi->getLoc(), bi->getDestBB(), args); - branch->eraseFromParent(); - return result; - } - - llvm_unreachable("unsupported terminator"); -} - -void swift::erasePhiArgument(SILBasicBlock *block, unsigned argIndex) { - assert(block->getArgument(argIndex)->isPhiArgument() && - "Only should be used on phi arguments"); - block->eraseArgument(argIndex); - - // Determine the set of predecessors in case any predecessor has - // two edges to this block (e.g. a conditional branch where both - // sides reach this block). - // - // NOTE: This needs to be a SmallSetVector since we need both uniqueness /and/ - // insertion order. Otherwise non-determinism can result. - SmallSetVector predBlocks; - - for (auto *pred : block->getPredecessorBlocks()) - predBlocks.insert(pred); - - for (auto *pred : predBlocks) - deleteEdgeValue(pred->getTerminator(), block, argIndex); -} - -/// Changes the edge value between a branch and destination basic block -/// at the specified index. Changes all edges from \p Branch to \p Dest to carry -/// the value. -/// -/// \param Branch The branch to modify. -/// \param Dest The destination of the edge. -/// \param Idx The index of the argument to modify. -/// \param Val The new value to use. -/// \return The new branch. Deletes the old one. -/// Changes the edge value between a branch and destination basic block at the -/// specified index. -TermInst *swift::changeEdgeValue(TermInst *Branch, SILBasicBlock *Dest, - size_t Idx, SILValue Val) { - SILBuilderWithScope Builder(Branch); - - if (auto *CBI = dyn_cast(Branch)) { - SmallVector TrueArgs; - SmallVector FalseArgs; - - OperandValueArrayRef OldTrueArgs = CBI->getTrueArgs(); - bool BranchOnTrue = CBI->getTrueBB() == Dest; - assert((!BranchOnTrue || Idx < OldTrueArgs.size()) && "Not enough edges"); - - // Copy the edge values overwriting the edge at Idx. - for (unsigned i = 0, e = OldTrueArgs.size(); i != e; ++i) { - if (BranchOnTrue && Idx == i) - TrueArgs.push_back(Val); - else - TrueArgs.push_back(OldTrueArgs[i]); - } - assert(TrueArgs.size() == CBI->getTrueBB()->getNumArguments() && - "Destination block's number of arguments must match"); - - OperandValueArrayRef OldFalseArgs = CBI->getFalseArgs(); - bool BranchOnFalse = CBI->getFalseBB() == Dest; - assert((!BranchOnFalse || Idx < OldFalseArgs.size()) && "Not enough edges"); - - // Copy the edge values overwriting the edge at Idx. - for (unsigned i = 0, e = OldFalseArgs.size(); i != e; ++i) { - if (BranchOnFalse && Idx == i) - FalseArgs.push_back(Val); - else - FalseArgs.push_back(OldFalseArgs[i]); - } - assert(FalseArgs.size() == CBI->getFalseBB()->getNumArguments() && - "Destination block's number of arguments must match"); - - CBI = Builder.createCondBranch( - CBI->getLoc(), CBI->getCondition(), CBI->getTrueBB(), TrueArgs, - CBI->getFalseBB(), FalseArgs, CBI->getTrueBBCount(), - CBI->getFalseBBCount()); - Branch->dropAllReferences(); - Branch->eraseFromParent(); - return CBI; - } - - if (auto *BI = dyn_cast(Branch)) { - SmallVector Args; - - assert(Idx < BI->getNumArgs() && "Not enough edges"); - OperandValueArrayRef OldArgs = BI->getArgs(); - - // Copy the edge values overwriting the edge at Idx. - for (unsigned i = 0, e = OldArgs.size(); i != e; ++i) { - if (Idx == i) - Args.push_back(Val); - else - Args.push_back(OldArgs[i]); - } - assert(Args.size() == Dest->getNumArguments()); - - BI = Builder.createBranch(BI->getLoc(), BI->getDestBB(), Args); - Branch->dropAllReferences(); - Branch->eraseFromParent(); - return BI; - } - - llvm_unreachable("Unhandled terminator leading to merge block"); -} - -template -SILBasicBlock *replaceSwitchDest(SwitchEnumTy *S, - SmallVectorImpl &Cases, - unsigned EdgeIdx, SILBasicBlock *NewDest) { - auto *DefaultBB = S->hasDefault() ? S->getDefaultBB() : nullptr; - for (unsigned i = 0, e = S->getNumCases(); i != e; ++i) - if (EdgeIdx != i) - Cases.push_back(S->getCase(i)); - else - Cases.push_back(std::make_pair(S->getCase(i).first, NewDest)); - if (EdgeIdx == S->getNumCases()) - DefaultBB = NewDest; - return DefaultBB; -} - -template -SILBasicBlock *replaceSwitchDest(SwitchEnumTy *S, - SmallVectorImpl &Cases, - SILBasicBlock *OldDest, SILBasicBlock *NewDest) { - auto *DefaultBB = S->hasDefault() ? S->getDefaultBB() : nullptr; - for (unsigned i = 0, e = S->getNumCases(); i != e; ++i) - if (S->getCase(i).second != OldDest) - Cases.push_back(S->getCase(i)); - else - Cases.push_back(std::make_pair(S->getCase(i).first, NewDest)); - if (OldDest == DefaultBB) - DefaultBB = NewDest; - return DefaultBB; -} - -/// Replace a branch target. -/// -/// \param T The terminating instruction to modify. -/// \param OldDest The successor block that will be replaced. -/// \param NewDest The new target block. -/// \param PreserveArgs If set, preserve arguments on the replaced edge. -void swift::replaceBranchTarget(TermInst *T, SILBasicBlock *OldDest, - SILBasicBlock *NewDest, bool PreserveArgs) { - SILBuilderWithScope B(T); - - switch (T->getTermKind()) { - // Only Branch and CondBranch may have arguments. - case TermKind::BranchInst: { - auto Br = cast(T); - assert(OldDest == Br->getDestBB() && "wrong branch target"); - SmallVector Args; - if (PreserveArgs) { - for (auto Arg : Br->getArgs()) - Args.push_back(Arg); - } - B.createBranch(T->getLoc(), NewDest, Args); - Br->dropAllReferences(); - Br->eraseFromParent(); - return; - } - - case TermKind::CondBranchInst: { - auto CondBr = cast(T); - SmallVector TrueArgs; - if (OldDest == CondBr->getFalseBB() || PreserveArgs) { - for (auto Arg : CondBr->getTrueArgs()) - TrueArgs.push_back(Arg); - } - SmallVector FalseArgs; - if (OldDest == CondBr->getTrueBB() || PreserveArgs) { - for (auto Arg : CondBr->getFalseArgs()) - FalseArgs.push_back(Arg); - } - SILBasicBlock *TrueDest = CondBr->getTrueBB(); - SILBasicBlock *FalseDest = CondBr->getFalseBB(); - if (OldDest == CondBr->getTrueBB()) { - TrueDest = NewDest; - } else { - assert(OldDest == CondBr->getFalseBB() && "wrong cond_br target"); - FalseDest = NewDest; - } - - B.createCondBranch(CondBr->getLoc(), CondBr->getCondition(), TrueDest, - TrueArgs, FalseDest, FalseArgs, CondBr->getTrueBBCount(), - CondBr->getFalseBBCount()); - CondBr->dropAllReferences(); - CondBr->eraseFromParent(); - return; - } - - case TermKind::SwitchValueInst: { - auto SII = cast(T); - SmallVector, 8> Cases; - auto *DefaultBB = replaceSwitchDest(SII, Cases, OldDest, NewDest); - B.createSwitchValue(SII->getLoc(), SII->getOperand(), DefaultBB, Cases); - SII->eraseFromParent(); - return; - } - - case TermKind::SwitchEnumInst: { - auto SEI = cast(T); - SmallVector, 8> Cases; - auto *DefaultBB = replaceSwitchDest(SEI, Cases, OldDest, NewDest); - B.createSwitchEnum(SEI->getLoc(), SEI->getOperand(), DefaultBB, Cases); - SEI->eraseFromParent(); - return; - } - - case TermKind::SwitchEnumAddrInst: { - auto SEI = cast(T); - SmallVector, 8> Cases; - auto *DefaultBB = replaceSwitchDest(SEI, Cases, OldDest, NewDest); - B.createSwitchEnumAddr(SEI->getLoc(), SEI->getOperand(), DefaultBB, Cases); - SEI->eraseFromParent(); - return; - } - - case TermKind::DynamicMethodBranchInst: { - auto DMBI = cast(T); - assert(OldDest == DMBI->getHasMethodBB() || OldDest == DMBI->getNoMethodBB() && "Invalid edge index"); - auto HasMethodBB = OldDest == DMBI->getHasMethodBB() ? NewDest : DMBI->getHasMethodBB(); - auto NoMethodBB = OldDest == DMBI->getNoMethodBB() ? NewDest : DMBI->getNoMethodBB(); - B.createDynamicMethodBranch(DMBI->getLoc(), DMBI->getOperand(), - DMBI->getMember(), HasMethodBB, NoMethodBB); - DMBI->eraseFromParent(); - return; - } - - case TermKind::CheckedCastBranchInst: { - auto CBI = cast(T); - assert(OldDest == CBI->getSuccessBB() || OldDest == CBI->getFailureBB() && "Invalid edge index"); - auto SuccessBB = OldDest == CBI->getSuccessBB() ? NewDest : CBI->getSuccessBB(); - auto FailureBB = OldDest == CBI->getFailureBB() ? NewDest : CBI->getFailureBB(); - B.createCheckedCastBranch(CBI->getLoc(), CBI->isExact(), CBI->getOperand(), - CBI->getCastType(), SuccessBB, FailureBB, - CBI->getTrueBBCount(), CBI->getFalseBBCount()); - CBI->eraseFromParent(); - return; - } - - case TermKind::CheckedCastValueBranchInst: { - auto CBI = cast(T); - assert(OldDest == CBI->getSuccessBB() || - OldDest == CBI->getFailureBB() && "Invalid edge index"); - auto SuccessBB = - OldDest == CBI->getSuccessBB() ? NewDest : CBI->getSuccessBB(); - auto FailureBB = - OldDest == CBI->getFailureBB() ? NewDest : CBI->getFailureBB(); - B.createCheckedCastValueBranch(CBI->getLoc(), CBI->getOperand(), - CBI->getCastType(), SuccessBB, FailureBB); - CBI->eraseFromParent(); - return; - } - - case TermKind::CheckedCastAddrBranchInst: { - auto CBI = cast(T); - assert(OldDest == CBI->getSuccessBB() || OldDest == CBI->getFailureBB() && "Invalid edge index"); - auto SuccessBB = OldDest == CBI->getSuccessBB() ? NewDest : CBI->getSuccessBB(); - auto FailureBB = OldDest == CBI->getFailureBB() ? NewDest : CBI->getFailureBB(); - auto TrueCount = CBI->getTrueBBCount(); - auto FalseCount = CBI->getFalseBBCount(); - B.createCheckedCastAddrBranch(CBI->getLoc(), CBI->getConsumptionKind(), - CBI->getSrc(), CBI->getSourceType(), - CBI->getDest(), CBI->getTargetType(), - SuccessBB, FailureBB, TrueCount, FalseCount); - CBI->eraseFromParent(); - return; - } - - case TermKind::ReturnInst: - case TermKind::ThrowInst: - case TermKind::TryApplyInst: - case TermKind::UnreachableInst: - case TermKind::UnwindInst: - case TermKind::YieldInst: - llvm_unreachable("Branch target cannot be replaced for this terminator instruction!"); - } - llvm_unreachable("Not yet implemented!"); -} - -/// Check if the edge from the terminator is critical. -bool swift::isCriticalEdge(TermInst *T, unsigned EdgeIdx) { - assert(T->getSuccessors().size() > EdgeIdx && "Not enough successors"); - - auto SrcSuccs = T->getSuccessors(); - - if (SrcSuccs.size() <= 1 && - // Also consider non-branch instructions with a single successor for - // critical edges, for example: a switch_enum of a single-case enum. - (isa(T) || isa(T))) - return false; - - SILBasicBlock *DestBB = SrcSuccs[EdgeIdx]; - assert(!DestBB->pred_empty() && "There should be a predecessor"); - if (DestBB->getSinglePredecessorBlock()) - return false; - - return true; -} - -/// Splits the basic block at the iterator with an unconditional branch and -/// updates the dominator tree and loop info. -SILBasicBlock *swift::splitBasicBlockAndBranch(SILBuilder &B, - SILInstruction *SplitBeforeInst, - DominanceInfo *DT, - SILLoopInfo *LI) { - auto *OrigBB = SplitBeforeInst->getParent(); - auto *NewBB = OrigBB->split(SplitBeforeInst->getIterator()); - B.setInsertionPoint(OrigBB); - B.createBranch(SplitBeforeInst->getLoc(), NewBB); - - // Update the dominator tree. - if (DT) { - auto OrigBBDTNode = DT->getNode(OrigBB); - if (OrigBBDTNode) { - // Change the immediate dominators of the children of the block we - // splitted to the splitted block. - SmallVector Adoptees(OrigBBDTNode->begin(), - OrigBBDTNode->end()); - - auto NewBBDTNode = DT->addNewBlock(NewBB, OrigBB); - for (auto *Adoptee : Adoptees) - DT->changeImmediateDominator(Adoptee, NewBBDTNode); - } - } - - // Update loop info. - if (LI) - if (auto *OrigBBLoop = LI->getLoopFor(OrigBB)) { - OrigBBLoop->addBasicBlockToLoop(NewBB, LI->getBase()); - } - - return NewBB; -} - -/// Split every edge between two basic blocks. -void swift::splitEdgesFromTo(SILBasicBlock *From, SILBasicBlock *To, - DominanceInfo *DT, SILLoopInfo *LI) { - for (unsigned EdgeIndex = 0, E = From->getSuccessors().size(); EdgeIndex != E; - ++EdgeIndex) { - SILBasicBlock *SuccBB = From->getSuccessors()[EdgeIndex]; - if (SuccBB != To) - continue; - splitEdge(From->getTerminator(), EdgeIndex, DT, LI); - } -} - -/// Splits the n-th critical edge from the terminator and updates dominance and -/// loop info if set. -/// Returns the newly created basic block on success or nullptr otherwise (if -/// the edge was not critical. -SILBasicBlock *swift::splitCriticalEdge(TermInst *T, unsigned EdgeIdx, - DominanceInfo *DT, SILLoopInfo *LI) { - if (!isCriticalEdge(T, EdgeIdx)) - return nullptr; - - return splitEdge(T, EdgeIdx, DT, LI); -} - -bool swift::splitCriticalEdgesFrom(SILBasicBlock *fromBB, DominanceInfo *DT, - SILLoopInfo *LI) { - bool Changed = false; - for (unsigned idx = 0, e = fromBB->getSuccessors().size(); idx != e; ++idx) { - auto *NewBB = splitCriticalEdge(fromBB->getTerminator(), idx, DT, LI); - Changed |= (NewBB != nullptr); - } - return Changed; -} - -bool swift::hasCriticalEdges(SILFunction &F, bool OnlyNonCondBr) { - for (SILBasicBlock &BB : F) { - // Only consider critical edges for terminators that don't support block - // arguments. - if (OnlyNonCondBr && isa(BB.getTerminator())) - continue; - - if (isa(BB.getTerminator())) - continue; - - for (unsigned Idx = 0, e = BB.getSuccessors().size(); Idx != e; ++Idx) - if (isCriticalEdge(BB.getTerminator(), Idx)) - return true; - } - return false; -} - -/// Split all critical edges in the function updating the dominator tree and -/// loop information (if they are not set to null). -bool swift::splitAllCriticalEdges(SILFunction &F, DominanceInfo *DT, - SILLoopInfo *LI) { - bool Changed = false; - - for (SILBasicBlock &BB : F) { - if (isa(BB.getTerminator())) - continue; - - for (unsigned Idx = 0, e = BB.getSuccessors().size(); Idx != e; ++Idx) { - auto *NewBB = splitCriticalEdge(BB.getTerminator(), Idx, DT, LI); - assert(!NewBB - || isa(BB.getTerminator()) - && "Only cond_br may have a critical edge."); - Changed |= (NewBB != nullptr); - } - } - return Changed; -} - -/// Merge the basic block with its successor if possible. If dominance -/// information or loop info is non null update it. Return true if block was -/// merged. -bool swift::mergeBasicBlockWithSuccessor(SILBasicBlock *BB, DominanceInfo *DT, - SILLoopInfo *LI) { - auto *Branch = dyn_cast(BB->getTerminator()); - if (!Branch) - return false; - - auto *SuccBB = Branch->getDestBB(); - if (BB == SuccBB || !SuccBB->getSinglePredecessorBlock()) - return false; - - if (DT) - if (auto *SuccBBNode = DT->getNode(SuccBB)) { - // Change the immediate dominator for children of the successor to be the - // current block. - auto *BBNode = DT->getNode(BB); - SmallVector Children(SuccBBNode->begin(), - SuccBBNode->end()); - for (auto *ChildNode : Children) - DT->changeImmediateDominator(ChildNode, BBNode); - - DT->eraseNode(SuccBB); - } - - if (LI) - LI->removeBlock(SuccBB); - - mergeBasicBlockWithSingleSuccessor(BB, SuccBB); - - return true; -} - -bool swift::mergeBasicBlocks(SILFunction *F) { - bool merged = false; - for (auto BBIter = F->begin(); BBIter != F->end();) { - if (mergeBasicBlockWithSuccessor(&*BBIter, /*DT*/ nullptr, /*LI*/ nullptr)) { - merged = true; - // Continue to merge the current block without advancing. - continue; - } - ++BBIter; - } - return merged; -} - -/// Splits the critical edges between from and to. This code assumes there is -/// only one edge between the two basic blocks. -SILBasicBlock *swift::splitIfCriticalEdge(SILBasicBlock *From, - SILBasicBlock *To, - DominanceInfo *DT, - SILLoopInfo *LI) { - auto *T = From->getTerminator(); - for (unsigned i = 0, e = T->getSuccessors().size(); i != e; ++i) { - if (T->getSuccessors()[i] == To) - return splitCriticalEdge(T, i, DT, LI); - } - llvm_unreachable("Destination block not found"); -} - -void swift::completeJointPostDominanceSet( - ArrayRef UserBlocks, ArrayRef DefBlocks, - llvm::SmallVectorImpl &Result) { - assert(!UserBlocks.empty() && "Must have at least 1 user block"); - assert(!DefBlocks.empty() && "Must have at least 1 def block"); - - // If we have only one def block and one user block and they are the same - // block, then just return. - if (DefBlocks.size() == 1 && UserBlocks.size() == 1 && - UserBlocks[0] == DefBlocks[0]) { - return; - } - - // Some notes on the algorithm: - // - // 1. Our VisitedBlocks set just states that a value has been added to the - // worklist and should not be added to the worklist. - // 2. Our targets of the CFG block are DefBlockSet. - // 3. We find the missing post-domination blocks by finding successors of - // blocks on our walk that we have not visited by the end of the walk. For - // joint post-dominance to be true, no such successors should exist. - - // Our set of target blocks where we stop walking. - llvm::SmallPtrSet DefBlockSet(DefBlocks.begin(), - DefBlocks.end()); - - // The set of successor blocks of blocks that we visit. Any blocks still in - // this set at the end of the walk act as a post-dominating closure around our - // UserBlock set. - llvm::SmallSetVector MustVisitSuccessorBlocks; - - // Add our user and def blocks to the VisitedBlock set. We never want to find - // these in our worklist. - llvm::SmallPtrSet VisitedBlocks(UserBlocks.begin(), - UserBlocks.end()); - - // Finally setup our worklist by adding our user block predecessors. We only - // add the predecessors to the worklist once. - llvm::SmallVector Worklist; - for (auto *Block : UserBlocks) { - llvm::copy_if(Block->getPredecessorBlocks(), std::back_inserter(Worklist), - [&](SILBasicBlock *PredBlock) -> bool { - return VisitedBlocks.insert(PredBlock).second; - }); - } - - // Then until we reach a fix point. - while (!Worklist.empty()) { - // Grab the next block from the worklist. - auto *Block = Worklist.pop_back_val(); - assert(VisitedBlocks.count(Block) && "All blocks from worklist should be " - "in the visited blocks set."); - - // Since we are visiting this block now, we know that this block can not be - // apart of a the post-dominance closure of our UseBlocks. - MustVisitSuccessorBlocks.remove(Block); - - // Then add each successor block of Block that has not been visited yet to - // the MustVisitSuccessorBlocks set. - for (auto *SuccBlock : Block->getSuccessorBlocks()) { - if (!VisitedBlocks.count(SuccBlock)) { - MustVisitSuccessorBlocks.insert(SuccBlock); - } - } - - // If this is a def block, then do not add its predecessors to the - // worklist. - if (DefBlockSet.count(Block)) - continue; - - // Otherwise add all unvisited predecessors to the worklist. - llvm::copy_if(Block->getPredecessorBlocks(), std::back_inserter(Worklist), - [&](SILBasicBlock *Block) -> bool { - return VisitedBlocks.insert(Block).second; - }); - } - - // Now that we are done, add all remaining must visit blocks to our result - // list. These are the remaining parts of our joint post-dominance closure. - llvm::copy(MustVisitSuccessorBlocks, std::back_inserter(Result)); -} - -bool swift::splitAllCondBrCriticalEdgesWithNonTrivialArgs(SILFunction &Fn, - DominanceInfo *DT, - SILLoopInfo *LI) { - // Find our targets. - llvm::SmallVector, 8> Targets; - for (auto &Block : Fn) { - auto *CBI = dyn_cast(Block.getTerminator()); - if (!CBI) - continue; - - // See if our true index is a critical edge. If so, add block to the list - // and continue. If the false edge is also critical, we will handle it at - // the same time. - if (isCriticalEdge(CBI, CondBranchInst::TrueIdx)) { - Targets.emplace_back(&Block, CondBranchInst::TrueIdx); - } - - if (!isCriticalEdge(CBI, CondBranchInst::FalseIdx)) { - continue; - } - - Targets.emplace_back(&Block, CondBranchInst::FalseIdx); - } - - if (Targets.empty()) - return false; - - for (auto P : Targets) { - SILBasicBlock *Block = P.first; - unsigned Index = P.second; - auto *Result = splitCriticalEdge(Block->getTerminator(), Index, DT, LI); - (void)Result; - assert(Result); - } - - return true; -} - -bool swift::removeUnreachableBlocks(SILFunction &Fn) { - // All reachable blocks, but does not include the entry block. - llvm::SmallPtrSet Visited; - - // Walk over the CFG, starting at the entry block, until all reachable blocks are visited. - llvm::SmallVector Worklist(1, Fn.getEntryBlock()); - while (!Worklist.empty()) { - SILBasicBlock *BB = Worklist.pop_back_val(); - for (auto &Succ : BB->getSuccessors()) { - if (Visited.insert(Succ).second) - Worklist.push_back(Succ); - } - } - - // Remove the blocks we never reached. Exclude the entry block from the iteration because it's - // not included in the Visited set. - bool Changed = false; - for (auto It = std::next(Fn.begin()), End = Fn.end(); It != End; ) { - auto *BB = &*It++; - if (!Visited.count(BB)) { - removeDeadBlock(BB); - Changed = true; - } - } - return Changed; -} diff --git a/lib/SILOptimizer/Utils/CFGOptUtils.cpp b/lib/SILOptimizer/Utils/CFGOptUtils.cpp new file mode 100644 index 00000000000..b310323cc27 --- /dev/null +++ b/lib/SILOptimizer/Utils/CFGOptUtils.cpp @@ -0,0 +1,826 @@ +//===--- CFGOptUtils.cpp - SIL CFG edge utilities -------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 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 +// +//===----------------------------------------------------------------------===// + +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/Demangling/ManglingMacros.h" +#include "swift/SIL/BasicBlockUtils.h" +#include "swift/SIL/Dominance.h" +#include "swift/SIL/LoopInfo.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILBuilder.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "llvm/ADT/TinyPtrVector.h" + +using namespace swift; + +/// Adds a new argument to an edge between a branch and a destination +/// block. +/// +/// \param branch The terminator to add the argument to. +/// \param dest The destination block of the edge. +/// \param Val The value to the arguments of the branch. +/// \return The created branch. The old branch is deleted. +/// The argument is appended at the end of the argument tuple. +TermInst *swift::addNewEdgeValueToBranch(TermInst *branch, SILBasicBlock *dest, + SILValue val) { + SILBuilderWithScope builder(branch); + TermInst *newBr = nullptr; + + if (auto *cbi = dyn_cast(branch)) { + SmallVector trueArgs; + SmallVector falseArgs; + + for (auto arg : cbi->getTrueArgs()) + trueArgs.push_back(arg); + + for (auto arg : cbi->getFalseArgs()) + falseArgs.push_back(arg); + + if (dest == cbi->getTrueBB()) { + trueArgs.push_back(val); + assert(trueArgs.size() == dest->getNumArguments()); + } + if (dest == cbi->getFalseBB()) { + falseArgs.push_back(val); + assert(falseArgs.size() == dest->getNumArguments()); + } + + newBr = builder.createCondBranch( + cbi->getLoc(), cbi->getCondition(), cbi->getTrueBB(), trueArgs, + cbi->getFalseBB(), falseArgs, cbi->getTrueBBCount(), + cbi->getFalseBBCount()); + } else if (auto *bi = dyn_cast(branch)) { + SmallVector args; + + for (auto arg : bi->getArgs()) + args.push_back(arg); + + args.push_back(val); + assert(args.size() == dest->getNumArguments()); + newBr = builder.createBranch(bi->getLoc(), bi->getDestBB(), args); + } else { + // At the moment we can only add arguments to br and cond_br. + llvm_unreachable("Can't add argument to terminator"); + } + + branch->dropAllReferences(); + branch->eraseFromParent(); + + return newBr; +} + +static void +deleteTriviallyDeadOperandsOfDeadArgument(MutableArrayRef termOperands, + unsigned deadArgIndex) { + Operand &op = termOperands[deadArgIndex]; + auto *i = op.get()->getDefiningInstruction(); + if (!i) + return; + op.set(SILUndef::get(op.get()->getType(), *i->getFunction())); + recursivelyDeleteTriviallyDeadInstructions(i); +} + +// Our implementation assumes that our caller is attempting to remove a dead +// SILPhiArgument from a SILBasicBlock and has already RAUWed the argument. +TermInst *swift::deleteEdgeValue(TermInst *branch, SILBasicBlock *destBlock, + size_t argIndex) { + if (auto *cbi = dyn_cast(branch)) { + SmallVector trueArgs; + SmallVector falseArgs; + + llvm::copy(cbi->getTrueArgs(), std::back_inserter(trueArgs)); + llvm::copy(cbi->getFalseArgs(), std::back_inserter(falseArgs)); + + if (destBlock == cbi->getTrueBB()) { + deleteTriviallyDeadOperandsOfDeadArgument(cbi->getTrueOperands(), + argIndex); + trueArgs.erase(trueArgs.begin() + argIndex); + } + + if (destBlock == cbi->getFalseBB()) { + deleteTriviallyDeadOperandsOfDeadArgument(cbi->getFalseOperands(), + argIndex); + falseArgs.erase(falseArgs.begin() + argIndex); + } + + SILBuilderWithScope builder(cbi); + auto *result = builder.createCondBranch( + cbi->getLoc(), cbi->getCondition(), cbi->getTrueBB(), trueArgs, + cbi->getFalseBB(), falseArgs, cbi->getTrueBBCount(), + cbi->getFalseBBCount()); + branch->eraseFromParent(); + return result; + } + + if (auto *bi = dyn_cast(branch)) { + SmallVector args; + llvm::copy(bi->getArgs(), std::back_inserter(args)); + + deleteTriviallyDeadOperandsOfDeadArgument(bi->getAllOperands(), argIndex); + args.erase(args.begin() + argIndex); + auto *result = SILBuilderWithScope(bi).createBranch(bi->getLoc(), + bi->getDestBB(), args); + branch->eraseFromParent(); + return result; + } + + llvm_unreachable("unsupported terminator"); +} + +void swift::erasePhiArgument(SILBasicBlock *block, unsigned argIndex) { + assert(block->getArgument(argIndex)->isPhiArgument() + && "Only should be used on phi arguments"); + block->eraseArgument(argIndex); + + // Determine the set of predecessors in case any predecessor has + // two edges to this block (e.g. a conditional branch where both + // sides reach this block). + // + // NOTE: This needs to be a SmallSetVector since we need both uniqueness /and/ + // insertion order. Otherwise non-determinism can result. + SmallSetVector predBlocks; + + for (auto *pred : block->getPredecessorBlocks()) + predBlocks.insert(pred); + + for (auto *pred : predBlocks) + deleteEdgeValue(pred->getTerminator(), block, argIndex); +} + +/// Changes the edge value between a branch and destination basic block +/// at the specified index. Changes all edges from \p branch to \p dest to carry +/// the value. +/// +/// \param branch The branch to modify. +/// \param dest The destination of the edge. +/// \param idx The index of the argument to modify. +/// \param Val The new value to use. +/// \return The new branch. Deletes the old one. +/// Changes the edge value between a branch and destination basic block at the +/// specified index. +TermInst *swift::changeEdgeValue(TermInst *branch, SILBasicBlock *dest, + size_t idx, SILValue Val) { + SILBuilderWithScope builder(branch); + + if (auto *cbi = dyn_cast(branch)) { + SmallVector trueArgs; + SmallVector falseArgs; + + OperandValueArrayRef oldTrueArgs = cbi->getTrueArgs(); + bool branchOnTrue = cbi->getTrueBB() == dest; + assert((!branchOnTrue || idx < oldTrueArgs.size()) && "Not enough edges"); + + // Copy the edge values overwriting the edge at idx. + for (unsigned i = 0, e = oldTrueArgs.size(); i != e; ++i) { + if (branchOnTrue && idx == i) + trueArgs.push_back(Val); + else + trueArgs.push_back(oldTrueArgs[i]); + } + assert(trueArgs.size() == cbi->getTrueBB()->getNumArguments() + && "Destination block's number of arguments must match"); + + OperandValueArrayRef oldFalseArgs = cbi->getFalseArgs(); + bool branchOnFalse = cbi->getFalseBB() == dest; + assert((!branchOnFalse || idx < oldFalseArgs.size()) && "Not enough edges"); + + // Copy the edge values overwriting the edge at idx. + for (unsigned i = 0, e = oldFalseArgs.size(); i != e; ++i) { + if (branchOnFalse && idx == i) + falseArgs.push_back(Val); + else + falseArgs.push_back(oldFalseArgs[i]); + } + assert(falseArgs.size() == cbi->getFalseBB()->getNumArguments() + && "Destination block's number of arguments must match"); + + cbi = builder.createCondBranch( + cbi->getLoc(), cbi->getCondition(), cbi->getTrueBB(), trueArgs, + cbi->getFalseBB(), falseArgs, cbi->getTrueBBCount(), + cbi->getFalseBBCount()); + branch->dropAllReferences(); + branch->eraseFromParent(); + return cbi; + } + + if (auto *bi = dyn_cast(branch)) { + SmallVector args; + + assert(idx < bi->getNumArgs() && "Not enough edges"); + OperandValueArrayRef oldArgs = bi->getArgs(); + + // Copy the edge values overwriting the edge at idx. + for (unsigned i = 0, e = oldArgs.size(); i != e; ++i) { + if (idx == i) + args.push_back(Val); + else + args.push_back(oldArgs[i]); + } + assert(args.size() == dest->getNumArguments()); + + bi = builder.createBranch(bi->getLoc(), bi->getDestBB(), args); + branch->dropAllReferences(); + branch->eraseFromParent(); + return bi; + } + + llvm_unreachable("Unhandled terminator leading to merge block"); +} + +template +SILBasicBlock *replaceSwitchDest(SwitchEnumTy *sTy, + SmallVectorImpl &cases, + unsigned edgeIdx, SILBasicBlock *newDest) { + auto *defaultBB = sTy->hasDefault() ? sTy->getDefaultBB() : nullptr; + for (unsigned i = 0, e = sTy->getNumCases(); i != e; ++i) + if (edgeIdx != i) + cases.push_back(sTy->getCase(i)); + else + cases.push_back(std::make_pair(sTy->getCase(i).first, newDest)); + if (edgeIdx == sTy->getNumCases()) + defaultBB = newDest; + return defaultBB; +} + +template +SILBasicBlock * +replaceSwitchDest(SwitchEnumTy *sTy, SmallVectorImpl &cases, + SILBasicBlock *oldDest, SILBasicBlock *newDest) { + auto *defaultBB = sTy->hasDefault() ? sTy->getDefaultBB() : nullptr; + for (unsigned i = 0, e = sTy->getNumCases(); i != e; ++i) + if (sTy->getCase(i).second != oldDest) + cases.push_back(sTy->getCase(i)); + else + cases.push_back(std::make_pair(sTy->getCase(i).first, newDest)); + if (oldDest == defaultBB) + defaultBB = newDest; + return defaultBB; +} + +/// Replace a branch target. +/// +/// \param T The terminating instruction to modify. +/// \param oldDest The successor block that will be replaced. +/// \param newDest The new target block. +/// \param preserveArgs If set, preserve arguments on the replaced edge. +void swift::replaceBranchTarget(TermInst *t, SILBasicBlock *oldDest, + SILBasicBlock *newDest, bool preserveArgs) { + SILBuilderWithScope builder(t); + + switch (t->getTermKind()) { + // Only Branch and CondBranch may have arguments. + case TermKind::BranchInst: { + auto br = cast(t); + assert(oldDest == br->getDestBB() && "wrong branch target"); + SmallVector args; + if (preserveArgs) { + for (auto arg : br->getArgs()) + args.push_back(arg); + } + builder.createBranch(t->getLoc(), newDest, args); + br->dropAllReferences(); + br->eraseFromParent(); + return; + } + + case TermKind::CondBranchInst: { + auto condBr = cast(t); + SmallVector trueArgs; + if (oldDest == condBr->getFalseBB() || preserveArgs) { + for (auto Arg : condBr->getTrueArgs()) + trueArgs.push_back(Arg); + } + SmallVector falseArgs; + if (oldDest == condBr->getTrueBB() || preserveArgs) { + for (auto arg : condBr->getFalseArgs()) + falseArgs.push_back(arg); + } + SILBasicBlock *trueDest = condBr->getTrueBB(); + SILBasicBlock *falseDest = condBr->getFalseBB(); + if (oldDest == condBr->getTrueBB()) { + trueDest = newDest; + } else { + assert(oldDest == condBr->getFalseBB() && "wrong cond_br target"); + falseDest = newDest; + } + + builder.createCondBranch( + condBr->getLoc(), condBr->getCondition(), trueDest, trueArgs, falseDest, + falseArgs, condBr->getTrueBBCount(), condBr->getFalseBBCount()); + condBr->dropAllReferences(); + condBr->eraseFromParent(); + return; + } + + case TermKind::SwitchValueInst: { + auto sii = cast(t); + SmallVector, 8> cases; + auto *defaultBB = replaceSwitchDest(sii, cases, oldDest, newDest); + builder.createSwitchValue(sii->getLoc(), sii->getOperand(), defaultBB, + cases); + sii->eraseFromParent(); + return; + } + + case TermKind::SwitchEnumInst: { + auto sei = cast(t); + SmallVector, 8> cases; + auto *defaultBB = replaceSwitchDest(sei, cases, oldDest, newDest); + builder.createSwitchEnum(sei->getLoc(), sei->getOperand(), defaultBB, + cases); + sei->eraseFromParent(); + return; + } + + case TermKind::SwitchEnumAddrInst: { + auto sei = cast(t); + SmallVector, 8> cases; + auto *defaultBB = replaceSwitchDest(sei, cases, oldDest, newDest); + builder.createSwitchEnumAddr(sei->getLoc(), sei->getOperand(), defaultBB, + cases); + sei->eraseFromParent(); + return; + } + + case TermKind::DynamicMethodBranchInst: { + auto dmbi = cast(t); + assert(oldDest == dmbi->getHasMethodBB() + || oldDest == dmbi->getNoMethodBB() && "Invalid edge index"); + auto hasMethodBB = + oldDest == dmbi->getHasMethodBB() ? newDest : dmbi->getHasMethodBB(); + auto noMethodBB = + oldDest == dmbi->getNoMethodBB() ? newDest : dmbi->getNoMethodBB(); + builder.createDynamicMethodBranch(dmbi->getLoc(), dmbi->getOperand(), + dmbi->getMember(), hasMethodBB, + noMethodBB); + dmbi->eraseFromParent(); + return; + } + + case TermKind::CheckedCastBranchInst: { + auto cbi = cast(t); + assert(oldDest == cbi->getSuccessBB() + || oldDest == cbi->getFailureBB() && "Invalid edge index"); + auto successBB = + oldDest == cbi->getSuccessBB() ? newDest : cbi->getSuccessBB(); + auto failureBB = + oldDest == cbi->getFailureBB() ? newDest : cbi->getFailureBB(); + builder.createCheckedCastBranch( + cbi->getLoc(), cbi->isExact(), cbi->getOperand(), cbi->getCastType(), + successBB, failureBB, cbi->getTrueBBCount(), cbi->getFalseBBCount()); + cbi->eraseFromParent(); + return; + } + + case TermKind::CheckedCastValueBranchInst: { + auto cbi = cast(t); + assert(oldDest == cbi->getSuccessBB() + || oldDest == cbi->getFailureBB() && "Invalid edge index"); + auto successBB = + oldDest == cbi->getSuccessBB() ? newDest : cbi->getSuccessBB(); + auto failureBB = + oldDest == cbi->getFailureBB() ? newDest : cbi->getFailureBB(); + builder.createCheckedCastValueBranch(cbi->getLoc(), cbi->getOperand(), + cbi->getCastType(), successBB, + failureBB); + cbi->eraseFromParent(); + return; + } + + case TermKind::CheckedCastAddrBranchInst: { + auto cbi = cast(t); + assert(oldDest == cbi->getSuccessBB() + || oldDest == cbi->getFailureBB() && "Invalid edge index"); + auto successBB = + oldDest == cbi->getSuccessBB() ? newDest : cbi->getSuccessBB(); + auto failureBB = + oldDest == cbi->getFailureBB() ? newDest : cbi->getFailureBB(); + auto trueCount = cbi->getTrueBBCount(); + auto falseCount = cbi->getFalseBBCount(); + builder.createCheckedCastAddrBranch( + cbi->getLoc(), cbi->getConsumptionKind(), cbi->getSrc(), + cbi->getSourceType(), cbi->getDest(), cbi->getTargetType(), successBB, + failureBB, trueCount, falseCount); + cbi->eraseFromParent(); + return; + } + + case TermKind::ReturnInst: + case TermKind::ThrowInst: + case TermKind::TryApplyInst: + case TermKind::UnreachableInst: + case TermKind::UnwindInst: + case TermKind::YieldInst: + llvm_unreachable( + "Branch target cannot be replaced for this terminator instruction!"); + } + llvm_unreachable("Not yet implemented!"); +} + +/// Check if the edge from the terminator is critical. +bool swift::isCriticalEdge(TermInst *t, unsigned edgeIdx) { + assert(t->getSuccessors().size() > edgeIdx && "Not enough successors"); + + auto srcSuccs = t->getSuccessors(); + + if (srcSuccs.size() <= 1 && + // Also consider non-branch instructions with a single successor for + // critical edges, for example: a switch_enum of a single-case enum. + (isa(t) || isa(t))) + return false; + + SILBasicBlock *destBB = srcSuccs[edgeIdx]; + assert(!destBB->pred_empty() && "There should be a predecessor"); + if (destBB->getSinglePredecessorBlock()) + return false; + + return true; +} + +/// Splits the basic block at the iterator with an unconditional branch and +/// updates the dominator tree and loop info. +SILBasicBlock *swift::splitBasicBlockAndBranch(SILBuilder &builder, + SILInstruction *splitBeforeInst, + DominanceInfo *domInfo, + SILLoopInfo *loopInfo) { + auto *origBB = splitBeforeInst->getParent(); + auto *newBB = origBB->split(splitBeforeInst->getIterator()); + builder.setInsertionPoint(origBB); + builder.createBranch(splitBeforeInst->getLoc(), newBB); + + // Update the dominator tree. + if (domInfo) { + auto origBBDTNode = domInfo->getNode(origBB); + if (origBBDTNode) { + // Change the immediate dominators of the children of the block we + // splitted to the splitted block. + SmallVector Adoptees(origBBDTNode->begin(), + origBBDTNode->end()); + + auto newBBDTNode = domInfo->addNewBlock(newBB, origBB); + for (auto *adoptee : Adoptees) + domInfo->changeImmediateDominator(adoptee, newBBDTNode); + } + } + + // Update loop info. + if (loopInfo) + if (auto *origBBLoop = loopInfo->getLoopFor(origBB)) { + origBBLoop->addBasicBlockToLoop(newBB, loopInfo->getBase()); + } + + return newBB; +} + +/// Split every edge between two basic blocks. +void swift::splitEdgesFromTo(SILBasicBlock *From, SILBasicBlock *To, + DominanceInfo *domInfo, SILLoopInfo *loopInfo) { + for (unsigned edgeIndex = 0, E = From->getSuccessors().size(); edgeIndex != E; + ++edgeIndex) { + SILBasicBlock *succBB = From->getSuccessors()[edgeIndex]; + if (succBB != To) + continue; + splitEdge(From->getTerminator(), edgeIndex, domInfo, loopInfo); + } +} + +/// Splits the n-th critical edge from the terminator and updates dominance and +/// loop info if set. +/// Returns the newly created basic block on success or nullptr otherwise (if +/// the edge was not critical. +SILBasicBlock *swift::splitCriticalEdge(TermInst *t, unsigned edgeIdx, + DominanceInfo *domInfo, + SILLoopInfo *loopInfo) { + if (!isCriticalEdge(t, edgeIdx)) + return nullptr; + + return splitEdge(t, edgeIdx, domInfo, loopInfo); +} + +bool swift::splitCriticalEdgesFrom(SILBasicBlock *fromBB, + DominanceInfo *domInfo, + SILLoopInfo *loopInfo) { + bool changed = false; + for (unsigned idx = 0, e = fromBB->getSuccessors().size(); idx != e; ++idx) { + auto *newBB = + splitCriticalEdge(fromBB->getTerminator(), idx, domInfo, loopInfo); + changed |= (newBB != nullptr); + } + return changed; +} + +bool swift::hasCriticalEdges(SILFunction &f, bool onlyNonCondBr) { + for (SILBasicBlock &bb : f) { + // Only consider critical edges for terminators that don't support block + // arguments. + if (onlyNonCondBr && isa(bb.getTerminator())) + continue; + + if (isa(bb.getTerminator())) + continue; + + for (unsigned idx = 0, e = bb.getSuccessors().size(); idx != e; ++idx) + if (isCriticalEdge(bb.getTerminator(), idx)) + return true; + } + return false; +} + +/// Split all critical edges in the function updating the dominator tree and +/// loop information (if they are not set to null). +bool swift::splitAllCriticalEdges(SILFunction &f, DominanceInfo *domInfo, + SILLoopInfo *loopInfo) { + bool changed = false; + + for (SILBasicBlock &bb : f) { + if (isa(bb.getTerminator())) + continue; + + for (unsigned idx = 0, e = bb.getSuccessors().size(); idx != e; ++idx) { + auto *newBB = + splitCriticalEdge(bb.getTerminator(), idx, domInfo, loopInfo); + assert(!newBB + || isa(bb.getTerminator()) + && "Only cond_br may have a critical edge."); + changed |= (newBB != nullptr); + } + } + return changed; +} + +/// Merge the basic block with its successor if possible. If dominance +/// information or loop info is non null update it. Return true if block was +/// merged. +bool swift::mergeBasicBlockWithSuccessor(SILBasicBlock *bb, + DominanceInfo *domInfo, + SILLoopInfo *loopInfo) { + auto *branch = dyn_cast(bb->getTerminator()); + if (!branch) + return false; + + auto *succBB = branch->getDestBB(); + if (bb == succBB || !succBB->getSinglePredecessorBlock()) + return false; + + if (domInfo) + if (auto *succBBNode = domInfo->getNode(succBB)) { + // Change the immediate dominator for children of the successor to be the + // current block. + auto *bbNode = domInfo->getNode(bb); + SmallVector Children(succBBNode->begin(), + succBBNode->end()); + for (auto *ChildNode : Children) + domInfo->changeImmediateDominator(ChildNode, bbNode); + + domInfo->eraseNode(succBB); + } + + if (loopInfo) + loopInfo->removeBlock(succBB); + + mergeBasicBlockWithSingleSuccessor(bb, succBB); + + return true; +} + +bool swift::mergeBasicBlocks(SILFunction *f) { + bool merged = false; + for (auto bbIter = f->begin(); bbIter != f->end();) { + if (mergeBasicBlockWithSuccessor(&*bbIter, /*domInfo*/ nullptr, + /*loopInfo*/ nullptr)) { + merged = true; + // Continue to merge the current block without advancing. + continue; + } + ++bbIter; + } + return merged; +} + +/// Splits the critical edges between from and to. This code assumes there is +/// only one edge between the two basic blocks. +SILBasicBlock *swift::splitIfCriticalEdge(SILBasicBlock *from, + SILBasicBlock *to, + DominanceInfo *domInfo, + SILLoopInfo *loopInfo) { + auto *t = from->getTerminator(); + for (unsigned i = 0, e = t->getSuccessors().size(); i != e; ++i) { + if (t->getSuccessors()[i] == to) + return splitCriticalEdge(t, i, domInfo, loopInfo); + } + llvm_unreachable("Destination block not found"); +} + +void swift::completeJointPostDominanceSet( + ArrayRef userBlocks, ArrayRef defBlocks, + llvm::SmallVectorImpl &result) { + assert(!userBlocks.empty() && "Must have at least 1 user block"); + assert(!defBlocks.empty() && "Must have at least 1 def block"); + + // If we have only one def block and one user block and they are the same + // block, then just return. + if (defBlocks.size() == 1 && userBlocks.size() == 1 + && userBlocks[0] == defBlocks[0]) { + return; + } + + // Some notes on the algorithm: + // + // 1. Our VisitedBlocks set just states that a value has been added to the + // worklist and should not be added to the worklist. + // 2. Our targets of the CFG block are DefBlockSet. + // 3. We find the missing post-domination blocks by finding successors of + // blocks on our walk that we have not visited by the end of the walk. For + // joint post-dominance to be true, no such successors should exist. + + // Our set of target blocks where we stop walking. + llvm::SmallPtrSet defBlockSet(defBlocks.begin(), + defBlocks.end()); + + // The set of successor blocks of blocks that we visit. Any blocks still in + // this set at the end of the walk act as a post-dominating closure around our + // userBlock set. + llvm::SmallSetVector mustVisitSuccessorBlocks; + + // Add our user and def blocks to the visitedBlock set. We never want to find + // these in our worklist. + llvm::SmallPtrSet visitedBlocks(userBlocks.begin(), + userBlocks.end()); + + // Finally setup our worklist by adding our user block predecessors. We only + // add the predecessors to the worklist once. + llvm::SmallVector worklist; + for (auto *block : userBlocks) { + llvm::copy_if(block->getPredecessorBlocks(), std::back_inserter(worklist), + [&](SILBasicBlock *predBlock) -> bool { + return visitedBlocks.insert(predBlock).second; + }); + } + + // Then until we reach a fix point. + while (!worklist.empty()) { + // Grab the next block from the worklist. + auto *block = worklist.pop_back_val(); + assert(visitedBlocks.count(block) + && "All blocks from worklist should be " + "in the visited blocks set."); + + // Since we are visiting this block now, we know that this block can not be + // apart of a the post-dominance closure of our UseBlocks. + mustVisitSuccessorBlocks.remove(block); + + // Then add each successor block of block that has not been visited yet to + // the mustVisitSuccessorBlocks set. + for (auto *succBlock : block->getSuccessorBlocks()) { + if (!visitedBlocks.count(succBlock)) { + mustVisitSuccessorBlocks.insert(succBlock); + } + } + + // If this is a def block, then do not add its predecessors to the + // worklist. + if (defBlockSet.count(block)) + continue; + + // Otherwise add all unvisited predecessors to the worklist. + llvm::copy_if(block->getPredecessorBlocks(), std::back_inserter(worklist), + [&](SILBasicBlock *block) -> bool { + return visitedBlocks.insert(block).second; + }); + } + + // Now that we are done, add all remaining must visit blocks to our result + // list. These are the remaining parts of our joint post-dominance closure. + llvm::copy(mustVisitSuccessorBlocks, std::back_inserter(result)); +} + +bool swift::splitAllCondBrCriticalEdgesWithNonTrivialArgs( + SILFunction &fn, DominanceInfo *domInfo, SILLoopInfo *loopInfo) { + // Find our targets. + llvm::SmallVector, 8> targets; + for (auto &block : fn) { + auto *cbi = dyn_cast(block.getTerminator()); + if (!cbi) + continue; + + // See if our true index is a critical edge. If so, add block to the list + // and continue. If the false edge is also critical, we will handle it at + // the same time. + if (isCriticalEdge(cbi, CondBranchInst::TrueIdx)) { + targets.emplace_back(&block, CondBranchInst::TrueIdx); + } + + if (!isCriticalEdge(cbi, CondBranchInst::FalseIdx)) { + continue; + } + + targets.emplace_back(&block, CondBranchInst::FalseIdx); + } + + if (targets.empty()) + return false; + + for (auto p : targets) { + SILBasicBlock *block = p.first; + unsigned index = p.second; + auto *result = + splitCriticalEdge(block->getTerminator(), index, domInfo, loopInfo); + (void)result; + assert(result); + } + + return true; +} + +static bool isSafeNonExitTerminator(TermInst *ti) { + switch (ti->getTermKind()) { + case TermKind::BranchInst: + case TermKind::CondBranchInst: + case TermKind::SwitchValueInst: + case TermKind::SwitchEnumInst: + case TermKind::SwitchEnumAddrInst: + case TermKind::DynamicMethodBranchInst: + case TermKind::CheckedCastBranchInst: + case TermKind::CheckedCastValueBranchInst: + case TermKind::CheckedCastAddrBranchInst: + return true; + case TermKind::UnreachableInst: + case TermKind::ReturnInst: + case TermKind::ThrowInst: + case TermKind::UnwindInst: + return false; + // yield is special because it can do arbitrary, + // potentially-process-terminating things. + case TermKind::YieldInst: + return false; + case TermKind::TryApplyInst: + return true; + } + + llvm_unreachable("Unhandled TermKind in switch."); +} + +static bool isTrapNoReturnFunction(ApplyInst *ai) { + const char *fatalName = MANGLE_AS_STRING( + MANGLE_SYM(s18_fatalErrorMessageyys12StaticStringV_AcCSutF)); + auto *fn = ai->getReferencedFunctionOrNull(); + + // We use endswith here since if we specialize fatal error we will always + // prepend the specialization records to fatalName. + if (!fn || !fn->getName().endswith(fatalName)) + return false; + + return true; +} + +bool swift::findAllNonFailureExitBBs( + SILFunction *f, llvm::TinyPtrVector &bbs) { + for (SILBasicBlock &bb : *f) { + TermInst *ti = bb.getTerminator(); + + // If we know that this terminator is not an exit terminator, continue. + if (isSafeNonExitTerminator(ti)) + continue; + + // A return inst is always a non-failure exit bb. + if (ti->isFunctionExiting()) { + bbs.push_back(&bb); + continue; + } + + // If we don't have an unreachable inst at this point, this is a terminator + // we don't understand. Be conservative and return false. + if (!isa(ti)) + return false; + + // Ok, at this point we know we have a terminator. If it is the only + // instruction in our bb, it is a failure bb. continue... + if (ti == &*bb.begin()) + continue; + + // If the unreachable is preceded by a no-return apply inst, then it is a + // non-failure exit bb. Add it to our list and continue. + auto prevIter = std::prev(SILBasicBlock::iterator(ti)); + if (auto *ai = dyn_cast(&*prevIter)) { + if (ai->isCalleeNoReturn() && !isTrapNoReturnFunction(ai)) { + bbs.push_back(&bb); + continue; + } + } + + // Otherwise, it must be a failure bb where we leak, continue. + continue; + } + + // We understood all terminators, return true. + return true; +} diff --git a/lib/SILOptimizer/Utils/CMakeLists.txt b/lib/SILOptimizer/Utils/CMakeLists.txt index b45f12afffd..36f43361f0a 100644 --- a/lib/SILOptimizer/Utils/CMakeLists.txt +++ b/lib/SILOptimizer/Utils/CMakeLists.txt @@ -1,5 +1,6 @@ silopt_register_sources( - CFG.cpp + BasicBlockOptUtils.cpp + CFGOptUtils.cpp CanonicalizeInstruction.cpp CastOptimizer.cpp CheckedCastBrJumpThreading.cpp @@ -9,8 +10,8 @@ silopt_register_sources( Existential.cpp GenericCloner.cpp Generics.cpp + InstOptUtils.cpp LoadStoreOptUtils.cpp - Local.cpp LoopUtils.cpp OptimizerStatsUtils.cpp PerformanceInlinerUtils.cpp @@ -18,4 +19,5 @@ silopt_register_sources( SILSSAUpdater.cpp SpecializationMangler.cpp StackNesting.cpp + ValueLifetime.cpp ) diff --git a/lib/SILOptimizer/Utils/CastOptimizer.cpp b/lib/SILOptimizer/Utils/CastOptimizer.cpp index da136f54532..8891d3bb643 100644 --- a/lib/SILOptimizer/Utils/CastOptimizer.cpp +++ b/lib/SILOptimizer/Utils/CastOptimizer.cpp @@ -26,15 +26,15 @@ #include "swift/SIL/InstructionUtils.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBuilder.h" -#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILUndef.h" #include "swift/SIL/TypeLowering.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringSwitch.h" @@ -1215,8 +1215,8 @@ CastOptimizer::optimizeCheckedCastBranchInst(CheckedCastBranchInst *Inst) { if (Inst->isExact()) return nullptr; - // Local helper we use to simplify replacing a checked_cast_branch with an - // optimized checked cast branch. + // InstOptUtils.helper we use to simplify replacing a checked_cast_branch with + // an optimized checked cast branch. auto replaceCastHelper = [](SILBuilderWithScope &B, SILDynamicCastInst dynamicCast, MetatypeInst *mi) -> SILInstruction * { diff --git a/lib/SILOptimizer/Utils/CheckedCastBrJumpThreading.cpp b/lib/SILOptimizer/Utils/CheckedCastBrJumpThreading.cpp index 3f49cae3c1d..390e6e826a6 100644 --- a/lib/SILOptimizer/Utils/CheckedCastBrJumpThreading.cpp +++ b/lib/SILOptimizer/Utils/CheckedCastBrJumpThreading.cpp @@ -11,15 +11,16 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "sil-simplify-cfg" +#include "swift/SIL/InstructionUtils.h" +#include "swift/SIL/SILInstruction.h" +#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/SILInliner.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Allocator.h" -#include "swift/SIL/SILInstruction.h" -#include "swift/SIL/InstructionUtils.h" -#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SILOptimizer/Utils/SILInliner.h" using namespace swift; diff --git a/lib/SILOptimizer/Utils/ConstantFolding.cpp b/lib/SILOptimizer/Utils/ConstantFolding.cpp index 978da5e7d29..dc276b27f4d 100644 --- a/lib/SILOptimizer/Utils/ConstantFolding.cpp +++ b/lib/SILOptimizer/Utils/ConstantFolding.cpp @@ -18,8 +18,7 @@ #include "swift/SIL/PatternMatch.h" #include "swift/SIL/SILBuilder.h" #include "swift/SILOptimizer/Utils/CastOptimizer.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SIL/InstructionUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/Statistic.h" diff --git a/lib/SILOptimizer/Utils/Devirtualize.cpp b/lib/SILOptimizer/Utils/Devirtualize.cpp index 4dff796e54c..6957266bc76 100644 --- a/lib/SILOptimizer/Utils/Devirtualize.cpp +++ b/lib/SILOptimizer/Utils/Devirtualize.cpp @@ -11,13 +11,13 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "sil-devirtualize-utility" -#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h" #include "swift/SILOptimizer/Utils/Devirtualize.h" #include "swift/AST/Decl.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/SubstitutionMap.h" #include "swift/AST/Types.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SIL/OptimizationRemark.h" #include "swift/SIL/SILDeclRef.h" #include "swift/SIL/SILFunction.h" @@ -25,8 +25,8 @@ #include "swift/SIL/SILModule.h" #include "swift/SIL/SILType.h" #include "swift/SIL/SILValue.h" -#include "swift/SIL/InstructionUtils.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" @@ -40,87 +40,83 @@ STATISTIC(NumWitnessDevirt, "Number of witness_method applies devirtualized"); // Class Method Optimization //===----------------------------------------------------------------------===// -void swift::getAllSubclasses(ClassHierarchyAnalysis *CHA, - ClassDecl *CD, - CanType ClassType, - SILModule &M, - ClassHierarchyAnalysis::ClassList &Subs) { +void swift::getAllSubclasses(ClassHierarchyAnalysis *cha, ClassDecl *cd, + CanType classType, SILModule &module, + ClassHierarchyAnalysis::ClassList &subs) { // Collect the direct and indirect subclasses for the class. // Sort these subclasses in the order they should be tested by the // speculative devirtualization. Different strategies could be used, // E.g. breadth-first, depth-first, etc. // Currently, let's use the breadth-first strategy. // The exact static type of the instance should be tested first. - auto &DirectSubs = CHA->getDirectSubClasses(CD); - auto &IndirectSubs = CHA->getIndirectSubClasses(CD); + auto &directSubs = cha->getDirectSubClasses(cd); + auto &indirectSubs = cha->getIndirectSubClasses(cd); - Subs.append(DirectSubs.begin(), DirectSubs.end()); - Subs.append(IndirectSubs.begin(), IndirectSubs.end()); + subs.append(directSubs.begin(), directSubs.end()); + subs.append(indirectSubs.begin(), indirectSubs.end()); // FIXME: This is wrong -- we could have a non-generic class nested // inside a generic class - if (isa(ClassType)) { + if (isa(classType)) { // Filter out any subclasses that do not inherit from this // specific bound class. - auto RemovedIt = std::remove_if(Subs.begin(), Subs.end(), - [&ClassType](ClassDecl *Sub){ + auto removedIt = + std::remove_if(subs.begin(), subs.end(), [&classType](ClassDecl *sub) { // FIXME: Add support for generic subclasses. - if (Sub->isGenericContext()) + if (sub->isGenericContext()) return false; - auto SubCanTy = Sub->getDeclaredInterfaceType()->getCanonicalType(); + auto subCanTy = sub->getDeclaredInterfaceType()->getCanonicalType(); // Handle the usual case here: the class in question // should be a real subclass of a bound generic class. - return !ClassType->isBindableToSuperclassOf( - SubCanTy); + return !classType->isBindableToSuperclassOf(subCanTy); }); - Subs.erase(RemovedIt, Subs.end()); + subs.erase(removedIt, subs.end()); } } /// Returns true, if a method implementation corresponding to -/// the class_method applied to an instance of the class CD is +/// the class_method applied to an instance of the class cd is /// effectively final, i.e. it is statically known to be not overridden -/// by any subclasses of the class CD. +/// by any subclasses of the class cd. /// -/// \p AI invocation instruction -/// \p ClassType type of the instance -/// \p CD static class of the instance whose method is being invoked -/// \p CHA class hierarchy analysis -static bool isEffectivelyFinalMethod(FullApplySite AI, - CanType ClassType, - ClassDecl *CD, - ClassHierarchyAnalysis *CHA) { - if (CD && CD->isFinal()) +/// \p applySite invocation instruction +/// \p classType type of the instance +/// \p cd static class of the instance whose method is being invoked +/// \p cha class hierarchy analysis +static bool isEffectivelyFinalMethod(FullApplySite applySite, CanType classType, + ClassDecl *cd, + ClassHierarchyAnalysis *cha) { + if (cd && cd->isFinal()) return true; - const DeclContext *DC = AI.getModule().getAssociatedContext(); + const DeclContext *dc = applySite.getModule().getAssociatedContext(); // Without an associated context we cannot perform any // access-based optimizations. - if (!DC) + if (!dc) return false; - auto *CMI = cast(AI.getCallee()); + auto *cmi = cast(applySite.getCallee()); - if (!calleesAreStaticallyKnowable(AI.getModule(), CMI->getMember())) + if (!calleesAreStaticallyKnowable(applySite.getModule(), cmi->getMember())) return false; - auto *Method = CMI->getMember().getAbstractFunctionDecl(); - assert(Method && "Expected abstract function decl!"); - assert(!Method->isFinal() && "Unexpected indirect call to final method!"); + auto *method = cmi->getMember().getAbstractFunctionDecl(); + assert(method && "Expected abstract function decl!"); + assert(!method->isFinal() && "Unexpected indirect call to final method!"); // If this method is not overridden in the module, // there is no other implementation. - if (!Method->isOverridden()) + if (!method->isOverridden()) return true; // Class declaration may be nullptr, e.g. for cases like: // func foo(c: C) {}, where C is a class, but // it does not have a class decl. - if (!CD) + if (!cd) return false; - if (!CHA) + if (!cha) return false; // This is a private or a module internal class. @@ -128,18 +124,18 @@ static bool isEffectivelyFinalMethod(FullApplySite AI, // We can analyze the class hierarchy rooted at it and // eventually devirtualize a method call more efficiently. - ClassHierarchyAnalysis::ClassList Subs; - getAllSubclasses(CHA, CD, ClassType, AI.getModule(), Subs); + ClassHierarchyAnalysis::ClassList subs; + getAllSubclasses(cha, cd, classType, applySite.getModule(), subs); // This is the implementation of the method to be used - // if the exact class of the instance would be CD. - auto *ImplMethod = CD->findImplementingMethod(Method); + // if the exact class of the instance would be cd. + auto *ImplMethod = cd->findImplementingMethod(method); // First, analyze all direct subclasses. - for (auto S : Subs) { + for (auto S : subs) { // Check if the subclass overrides a method and provides // a different implementation. - auto *ImplFD = S->findImplementingMethod(Method); + auto *ImplFD = S->findImplementingMethod(method); if (ImplFD != ImplMethod) return false; } @@ -153,32 +149,32 @@ static bool isEffectivelyFinalMethod(FullApplySite AI, /// - or it is private and has not sub-classes /// - or it is an internal class without sub-classes and /// it is a whole-module compilation. -static bool isKnownFinalClass(ClassDecl *CD, SILModule &M, - ClassHierarchyAnalysis *CHA) { - const DeclContext *DC = M.getAssociatedContext(); +static bool isKnownFinalClass(ClassDecl *cd, SILModule &module, + ClassHierarchyAnalysis *cha) { + const DeclContext *dc = module.getAssociatedContext(); - if (CD->isFinal()) + if (cd->isFinal()) return true; // Without an associated context we cannot perform any // access-based optimizations. - if (!DC) + if (!dc) return false; // Only handle classes defined within the SILModule's associated context. - if (!CD->isChildContextOf(DC)) + if (!cd->isChildContextOf(dc)) return false; - if (!CD->hasAccess()) + if (!cd->hasAccess()) return false; // Only consider 'private' members, unless we are in whole-module compilation. - switch (CD->getEffectiveAccess()) { + switch (cd->getEffectiveAccess()) { case AccessLevel::Open: return false; case AccessLevel::Public: case AccessLevel::Internal: - if (!M.isWholeModule()) + if (!module.isWholeModule()) return false; break; case AccessLevel::FilePrivate: @@ -192,14 +188,14 @@ static bool isKnownFinalClass(ClassDecl *CD, SILModule &M, // - or internal and it is a WMO compilation // then this class can be considered final for the purpose // of devirtualization. - if (CHA) { - if (!CHA->hasKnownDirectSubclasses(CD)) { - switch (CD->getEffectiveAccess()) { + if (cha) { + if (!cha->hasKnownDirectSubclasses(cd)) { + switch (cd->getEffectiveAccess()) { case AccessLevel::Open: return false; case AccessLevel::Public: case AccessLevel::Internal: - if (!M.isWholeModule()) + if (!module.isWholeModule()) return false; break; case AccessLevel::FilePrivate: @@ -214,57 +210,56 @@ static bool isKnownFinalClass(ClassDecl *CD, SILModule &M, return false; } - // 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 swift::getInstanceWithExactDynamicType(SILValue S, - ClassHierarchyAnalysis *CHA) { - auto *F = S->getFunction(); - auto &M = F->getModule(); +SILValue swift::getInstanceWithExactDynamicType(SILValue instance, + ClassHierarchyAnalysis *cha) { + auto *f = instance->getFunction(); + auto &module = f->getModule(); - while (S) { - S = stripCasts(S); + while (instance) { + instance = stripCasts(instance); - if (isa(S) || isa(S)) { - if (S->getType().getASTType()->hasDynamicSelfType()) + if (isa(instance) || isa(instance)) { + if (instance->getType().getASTType()->hasDynamicSelfType()) return SILValue(); - return S; + return instance; } - auto *Arg = dyn_cast(S); - if (!Arg) + auto *arg = dyn_cast(instance); + if (!arg) break; - auto *SinglePred = Arg->getParent()->getSinglePredecessorBlock(); - if (!SinglePred) { - if (!isa(Arg)) + auto *singlePred = arg->getParent()->getSinglePredecessorBlock(); + if (!singlePred) { + if (!isa(arg)) break; - auto *CD = Arg->getType().getClassOrBoundGenericClass(); + auto *cd = arg->getType().getClassOrBoundGenericClass(); // Check if this class is effectively final. - if (!CD || !isKnownFinalClass(CD, M, CHA)) + if (!cd || !isKnownFinalClass(cd, module, cha)) break; - return Arg; + return arg; } // Traverse the chain of predecessors. - if (isa(SinglePred->getTerminator()) || - isa(SinglePred->getTerminator())) { - S = cast(Arg)->getIncomingPhiValue(SinglePred); + if (isa(singlePred->getTerminator()) + || isa(singlePred->getTerminator())) { + instance = cast(arg)->getIncomingPhiValue(singlePred); continue; } // If it is a BB argument received on a success branch // of a checked_cast_br, then we know its exact type. - auto *CCBI = dyn_cast(SinglePred->getTerminator()); - if (!CCBI) + auto *ccbi = dyn_cast(singlePred->getTerminator()); + if (!ccbi) break; - if (!CCBI->isExact() || CCBI->getSuccessBB() != Arg->getParent()) + if (!ccbi->isExact() || ccbi->getSuccessBB() != arg->getParent()) break; - return S; + return instance; } return SILValue(); @@ -273,117 +268,117 @@ SILValue swift::getInstanceWithExactDynamicType(SILValue S, /// 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 swift::getExactDynamicType(SILValue S, - ClassHierarchyAnalysis *CHA, - bool ForUnderlyingObject) { - auto *F = S->getFunction(); - auto &M = F->getModule(); +SILType swift::getExactDynamicType(SILValue instance, + ClassHierarchyAnalysis *cha, + bool forUnderlyingObject) { + auto *f = instance->getFunction(); + auto &module = f->getModule(); // Set of values to be checked for their exact types. - SmallVector WorkList; + SmallVector worklist; // The detected type of the underlying object. - SILType ResultType; + SILType resultType; // Set of processed values. - llvm::SmallSet Processed; - WorkList.push_back(S); + llvm::SmallSet processed; + worklist.push_back(instance); - while (!WorkList.empty()) { - auto V = WorkList.pop_back_val(); - if (!V) + while (!worklist.empty()) { + auto v = worklist.pop_back_val(); + if (!v) return SILType(); - if (Processed.count(V)) + if (processed.count(v)) continue; - Processed.insert(V); + processed.insert(v); // For underlying object strip casts and projections. // For the object itself, simply strip casts. - V = ForUnderlyingObject ? getUnderlyingObject(V) : stripCasts(V); + v = forUnderlyingObject ? getUnderlyingObject(v) : stripCasts(v); - if (isa(V) || isa(V)) { - if (ResultType && ResultType != V->getType()) + if (isa(v) || isa(v)) { + if (resultType && resultType != v->getType()) return SILType(); - ResultType = V->getType(); + resultType = v->getType(); continue; } - if (isa(V)) { - if (ResultType && ResultType != V->getType()) + if (isa(v)) { + if (resultType && resultType != v->getType()) return SILType(); - ResultType = V->getType(); + resultType = v->getType(); continue; } - if (isa(V) || isa(V) || isa(V)) { - if (ResultType && ResultType != V->getType()) + if (isa(v) || isa(v) || isa(v)) { + if (resultType && resultType != v->getType()) return SILType(); - ResultType = V->getType(); + resultType = v->getType(); continue; } - if (ForUnderlyingObject) { - if (isa(V)) { - if (ResultType && ResultType != V->getType()) + if (forUnderlyingObject) { + if (isa(v)) { + if (resultType && resultType != v->getType()) return SILType(); - ResultType = V->getType(); + resultType = v->getType(); continue; } } - auto Arg = dyn_cast(V); - if (!Arg) { + auto arg = dyn_cast(v); + if (!arg) { // We don't know what it is. return SILType(); } - if (auto *FArg = dyn_cast(Arg)) { + if (auto *fArg = dyn_cast(arg)) { // Bail on metatypes for now. - if (FArg->getType().is()) { + if (fArg->getType().is()) { return SILType(); } - auto *CD = FArg->getType().getClassOrBoundGenericClass(); + auto *cd = fArg->getType().getClassOrBoundGenericClass(); // If it is not class and it is a trivial type, then it // should be the exact type. - if (!CD && FArg->getType().isTrivial(*F)) { - if (ResultType && ResultType != FArg->getType()) + if (!cd && fArg->getType().isTrivial(*f)) { + if (resultType && resultType != fArg->getType()) return SILType(); - ResultType = FArg->getType(); + resultType = fArg->getType(); continue; } - if (!CD) { + if (!cd) { // It is not a class or a trivial type, so we don't know what it is. return SILType(); } // Check if this class is effectively final. - if (!isKnownFinalClass(CD, M, CHA)) { + if (!isKnownFinalClass(cd, module, cha)) { return SILType(); } - if (ResultType && ResultType != FArg->getType()) + if (resultType && resultType != fArg->getType()) return SILType(); - ResultType = FArg->getType(); + resultType = fArg->getType(); continue; } - auto *SinglePred = Arg->getParent()->getSinglePredecessorBlock(); - if (SinglePred) { + auto *singlePred = arg->getParent()->getSinglePredecessorBlock(); + if (singlePred) { // If it is a BB argument received on a success branch // of a checked_cast_br, then we know its exact type. - auto *CCBI = dyn_cast(SinglePred->getTerminator()); - if (CCBI && CCBI->isExact() && CCBI->getSuccessBB() == Arg->getParent()) { - if (ResultType && ResultType != Arg->getType()) + auto *ccbi = dyn_cast(singlePred->getTerminator()); + if (ccbi && ccbi->isExact() && ccbi->getSuccessBB() == arg->getParent()) { + if (resultType && resultType != arg->getType()) return SILType(); - ResultType = Arg->getType(); + resultType = arg->getType(); continue; } } // It is a BB argument, look through incoming values. If they all have the // same exact type, then we consider it to be the type of the BB argument. - SmallVector IncomingValues; - if (Arg->getSingleTerminatorOperands(IncomingValues)) { - for (auto InValue : IncomingValues) { - WorkList.push_back(InValue); + SmallVector incomingValues; + if (arg->getSingleTerminatorOperands(incomingValues)) { + for (auto inValue : incomingValues) { + worklist.push_back(inValue); } continue; } @@ -392,27 +387,24 @@ SILType swift::getExactDynamicType(SILValue S, return SILType(); } - return ResultType; + return resultType; } - /// Try to determine the exact dynamic type of the underlying object. /// returns the exact dynamic type of a value, or an empty type if the exact /// type could not be determined. SILType -swift::getExactDynamicTypeOfUnderlyingObject(SILValue S, - ClassHierarchyAnalysis *CHA) { - return getExactDynamicType(S, CHA, /* ForUnderlyingObject */ true); +swift::getExactDynamicTypeOfUnderlyingObject(SILValue instance, + ClassHierarchyAnalysis *cha) { + return getExactDynamicType(instance, cha, /* forUnderlyingObject */ true); } // Start with the substitutions from the apply. // Try to propagate them to find out the real substitutions required // to invoke the method. static SubstitutionMap -getSubstitutionsForCallee(SILModule &M, - CanSILFunctionType baseCalleeType, - CanType derivedSelfType, - FullApplySite AI) { +getSubstitutionsForCallee(SILModule &module, CanSILFunctionType baseCalleeType, + CanType derivedSelfType, FullApplySite applySite) { // If the base method is not polymorphic, no substitutions are required, // even if we originally had substitutions for calling the derived method. @@ -439,12 +431,13 @@ getSubstitutionsForCallee(SILModule &M, if (auto metatypeType = derivedClass->getAs()) derivedClass = metatypeType->getInstanceType(); baseSubMap = derivedClass->getContextSubstitutionMap( - M.getSwiftModule(), baseClassDecl); + module.getSwiftModule(), baseClassDecl); } - SubstitutionMap origSubMap = AI.getSubstitutionMap(); + SubstitutionMap origSubMap = applySite.getSubstitutionMap(); - Type calleeSelfType = AI.getOrigCalleeType()->getSelfParameter().getType(); + Type calleeSelfType = + applySite.getOrigCalleeType()->getSelfParameter().getType(); if (auto metatypeType = calleeSelfType->getAs()) calleeSelfType = metatypeType->getInstanceType(); auto *calleeClassDecl = calleeSelfType->getClassOrBoundGenericClass(); @@ -467,264 +460,260 @@ getSubstitutionsForCallee(SILModule &M, baseCalleeSig); } -static ApplyInst *replaceApplyInst(SILBuilder &B, SILLocation Loc, - ApplyInst *OldAI, - SILValue NewFn, - SubstitutionMap NewSubs, - ArrayRef NewArgs, - ArrayRef NewArgBorrows) { - auto *NewAI = B.createApply(Loc, NewFn, NewSubs, NewArgs, - OldAI->isNonThrowing()); +static ApplyInst *replaceApplyInst(SILBuilder &builder, SILLocation loc, + ApplyInst *oldAI, SILValue newFn, + SubstitutionMap newSubs, + ArrayRef newArgs, + ArrayRef newArgBorrows) { + auto *newAI = + builder.createApply(loc, newFn, newSubs, newArgs, oldAI->isNonThrowing()); - if (!NewArgBorrows.empty()) { - for (SILValue Arg : NewArgBorrows) { - B.createEndBorrow(Loc, Arg); + if (!newArgBorrows.empty()) { + for (SILValue arg : newArgBorrows) { + builder.createEndBorrow(loc, arg); } } // Check if any casting is required for the return value. - SILValue ResultValue = - castValueToABICompatibleType(&B, Loc, NewAI, NewAI->getType(), - OldAI->getType()); + SILValue resultValue = castValueToABICompatibleType( + &builder, loc, newAI, newAI->getType(), oldAI->getType()); - OldAI->replaceAllUsesWith(ResultValue); - return NewAI; + oldAI->replaceAllUsesWith(resultValue); + return newAI; } -static TryApplyInst *replaceTryApplyInst(SILBuilder &B, SILLocation Loc, - TryApplyInst *OldTAI, SILValue NewFn, - SubstitutionMap NewSubs, - ArrayRef NewArgs, - SILFunctionConventions Conv, - ArrayRef NewArgBorrows) { - SILBasicBlock *NormalBB = OldTAI->getNormalBB(); - SILBasicBlock *ResultBB = nullptr; +static TryApplyInst *replaceTryApplyInst(SILBuilder &builder, SILLocation loc, + TryApplyInst *oldTAI, SILValue newFn, + SubstitutionMap newSubs, + ArrayRef newArgs, + SILFunctionConventions conv, + ArrayRef newArgBorrows) { + SILBasicBlock *normalBB = oldTAI->getNormalBB(); + SILBasicBlock *resultBB = nullptr; - SILType NewResultTy = Conv.getSILResultType(); + SILType newResultTy = conv.getSILResultType(); // Does the result value need to be casted? - auto OldResultTy = NormalBB->getArgument(0)->getType(); - bool ResultCastRequired = NewResultTy != OldResultTy; + auto oldResultTy = normalBB->getArgument(0)->getType(); + bool resultCastRequired = newResultTy != oldResultTy; // Create a new normal BB only if the result of the new apply differs // in type from the argument of the original normal BB. - if (!ResultCastRequired) { - ResultBB = NormalBB; + if (!resultCastRequired) { + resultBB = normalBB; } else { - ResultBB = B.getFunction().createBasicBlockBefore(NormalBB); - ResultBB->createPhiArgument(NewResultTy, ValueOwnershipKind::Owned); + resultBB = builder.getFunction().createBasicBlockBefore(normalBB); + resultBB->createPhiArgument(newResultTy, ValueOwnershipKind::Owned); } // We can always just use the original error BB because we'll be // deleting the edge to it from the old TAI. - SILBasicBlock *ErrorBB = OldTAI->getErrorBB(); + SILBasicBlock *errorBB = oldTAI->getErrorBB(); // Insert a try_apply here. // Note that this makes this block temporarily double-terminated! // We won't fix that until deleteDevirtualizedApply. - auto NewTAI = B.createTryApply(Loc, NewFn, NewSubs, NewArgs, - ResultBB, ErrorBB); + auto newTAI = + builder.createTryApply(loc, newFn, newSubs, newArgs, resultBB, errorBB); - if (!NewArgBorrows.empty()) { - B.setInsertionPoint(NormalBB->begin()); - for (SILValue Arg : NewArgBorrows) { - B.createEndBorrow(Loc, Arg); + if (!newArgBorrows.empty()) { + builder.setInsertionPoint(normalBB->begin()); + for (SILValue arg : newArgBorrows) { + builder.createEndBorrow(loc, arg); } - B.setInsertionPoint(ErrorBB->begin()); - for (SILValue Arg : NewArgBorrows) { - B.createEndBorrow(Loc, Arg); + builder.setInsertionPoint(errorBB->begin()); + for (SILValue arg : newArgBorrows) { + builder.createEndBorrow(loc, arg); } } - if (ResultCastRequired) { - B.setInsertionPoint(ResultBB); + if (resultCastRequired) { + builder.setInsertionPoint(resultBB); - SILValue ResultValue = ResultBB->getArgument(0); - ResultValue = castValueToABICompatibleType(&B, Loc, ResultValue, - NewResultTy, OldResultTy); - B.createBranch(Loc, NormalBB, { ResultValue }); + SILValue resultValue = resultBB->getArgument(0); + resultValue = castValueToABICompatibleType(&builder, loc, resultValue, + newResultTy, oldResultTy); + builder.createBranch(loc, normalBB, {resultValue}); } - B.setInsertionPoint(NormalBB->begin()); - return NewTAI; + builder.setInsertionPoint(normalBB->begin()); + return newTAI; } -static BeginApplyInst *replaceBeginApplyInst(SILBuilder &B, SILLocation Loc, - BeginApplyInst *OldBAI, - SILValue NewFn, - SubstitutionMap NewSubs, - ArrayRef NewArgs, - ArrayRef NewArgBorrows) { - auto *NewBAI = - B.createBeginApply(Loc, NewFn, NewSubs, NewArgs, OldBAI->isNonThrowing()); +static BeginApplyInst * +replaceBeginApplyInst(SILBuilder &builder, SILLocation loc, + BeginApplyInst *oldBAI, SILValue newFn, + SubstitutionMap newSubs, ArrayRef newArgs, + ArrayRef newArgBorrows) { + auto *newBAI = builder.createBeginApply(loc, newFn, newSubs, newArgs, + oldBAI->isNonThrowing()); // Forward the token. - OldBAI->getTokenResult()->replaceAllUsesWith(NewBAI->getTokenResult()); + oldBAI->getTokenResult()->replaceAllUsesWith(newBAI->getTokenResult()); - auto OldYields = OldBAI->getYieldedValues(); - auto NewYields = NewBAI->getYieldedValues(); - assert(OldYields.size() == NewYields.size()); + auto oldYields = oldBAI->getYieldedValues(); + auto newYields = newBAI->getYieldedValues(); + assert(oldYields.size() == newYields.size()); - for (auto i : indices(OldYields)) { - auto OldYield = OldYields[i]; - auto NewYield = NewYields[i]; - NewYield = castValueToABICompatibleType(&B, Loc, NewYield, - NewYield->getType(), - OldYield->getType()); - OldYield->replaceAllUsesWith(NewYield); + for (auto i : indices(oldYields)) { + auto oldYield = oldYields[i]; + auto newYield = newYields[i]; + newYield = castValueToABICompatibleType( + &builder, loc, newYield, newYield->getType(), oldYield->getType()); + oldYield->replaceAllUsesWith(newYield); } - if (NewArgBorrows.empty()) - return NewBAI; + if (newArgBorrows.empty()) + return newBAI; - SILValue token = NewBAI->getTokenResult(); + SILValue token = newBAI->getTokenResult(); // The token will only be used by end_apply and abort_apply. Use that to // insert the end_borrows we need. for (auto *use : token->getUses()) { - SILBuilderWithScope builder(use->getUser(), B.getBuilderContext()); - for (SILValue borrow : NewArgBorrows) { - builder.createEndBorrow(Loc, borrow); + SILBuilderWithScope borrowBuilder(use->getUser(), + builder.getBuilderContext()); + for (SILValue borrow : newArgBorrows) { + borrowBuilder.createEndBorrow(loc, borrow); } } - return NewBAI; + return newBAI; } -static PartialApplyInst *replacePartialApplyInst(SILBuilder &B, SILLocation Loc, - PartialApplyInst *OldPAI, - SILValue NewFn, - SubstitutionMap NewSubs, - ArrayRef NewArgs) { - auto Convention = - OldPAI->getType().getAs()->getCalleeConvention(); - auto *NewPAI = B.createPartialApply(Loc, NewFn, NewSubs, NewArgs, - Convention); +static PartialApplyInst * +replacePartialApplyInst(SILBuilder &builder, SILLocation loc, + PartialApplyInst *oldPAI, SILValue newFn, + SubstitutionMap newSubs, ArrayRef newArgs) { + auto convention = + oldPAI->getType().getAs()->getCalleeConvention(); + auto *newPAI = + builder.createPartialApply(loc, newFn, newSubs, newArgs, convention); // Check if any casting is required for the partially-applied function. - SILValue ResultValue = castValueToABICompatibleType( - &B, Loc, NewPAI, NewPAI->getType(), OldPAI->getType()); - OldPAI->replaceAllUsesWith(ResultValue); + SILValue resultValue = castValueToABICompatibleType( + &builder, loc, newPAI, newPAI->getType(), oldPAI->getType()); + oldPAI->replaceAllUsesWith(resultValue); - return NewPAI; + return newPAI; } -static ApplySite replaceApplySite(SILBuilder &B, SILLocation Loc, - ApplySite OldAS, SILValue NewFn, - SubstitutionMap NewSubs, - ArrayRef NewArgs, - SILFunctionConventions Conv, - ArrayRef NewArgBorrows) { - switch (OldAS.getKind()) { +static ApplySite replaceApplySite(SILBuilder &builder, SILLocation loc, + ApplySite oldAS, SILValue newFn, + SubstitutionMap newSubs, + ArrayRef newArgs, + SILFunctionConventions conv, + ArrayRef newArgBorrows) { + switch (oldAS.getKind()) { case ApplySiteKind::ApplyInst: { - auto *OldAI = cast(OldAS); - return replaceApplyInst(B, Loc, OldAI, NewFn, NewSubs, NewArgs, NewArgBorrows); + auto *oldAI = cast(oldAS); + return replaceApplyInst(builder, loc, oldAI, newFn, newSubs, newArgs, + newArgBorrows); } case ApplySiteKind::TryApplyInst: { - auto *OldTAI = cast(OldAS); - return replaceTryApplyInst(B, Loc, OldTAI, NewFn, NewSubs, NewArgs, Conv, - NewArgBorrows); + auto *oldTAI = cast(oldAS); + return replaceTryApplyInst(builder, loc, oldTAI, newFn, newSubs, newArgs, + conv, newArgBorrows); } case ApplySiteKind::BeginApplyInst: { - auto *OldBAI = dyn_cast(OldAS); - return replaceBeginApplyInst(B, Loc, OldBAI, NewFn, NewSubs, NewArgs, - NewArgBorrows); + auto *oldBAI = dyn_cast(oldAS); + return replaceBeginApplyInst(builder, loc, oldBAI, newFn, newSubs, newArgs, + newArgBorrows); } case ApplySiteKind::PartialApplyInst: { - assert(NewArgBorrows.empty()); - auto *OldPAI = cast(OldAS); - return replacePartialApplyInst(B, Loc, OldPAI, NewFn, NewSubs, NewArgs); + assert(newArgBorrows.empty()); + auto *oldPAI = cast(oldAS); + return replacePartialApplyInst(builder, loc, oldPAI, newFn, newSubs, + newArgs); } } llvm_unreachable("covered switch"); } /// Delete an apply site that's been successfully devirtualized. -void swift::deleteDevirtualizedApply(ApplySite Old) { - auto *OldApply = Old.getInstruction(); - recursivelyDeleteTriviallyDeadInstructions(OldApply, true); +void swift::deleteDevirtualizedApply(ApplySite old) { + auto *oldApply = old.getInstruction(); + recursivelyDeleteTriviallyDeadInstructions(oldApply, true); } -SILFunction *swift::getTargetClassMethod(SILModule &M, - ClassDecl *CD, - MethodInst *MI) { - assert((isa(MI) || isa(MI)) && - "Only class_method and super_method instructions are supported"); +SILFunction *swift::getTargetClassMethod(SILModule &module, ClassDecl *cd, + MethodInst *mi) { + assert((isa(mi) || isa(mi)) + && "Only class_method and super_method instructions are supported"); - SILDeclRef Member = MI->getMember(); - return M.lookUpFunctionInVTable(CD, Member); + SILDeclRef member = mi->getMember(); + return module.lookUpFunctionInVTable(cd, member); } -CanType swift::getSelfInstanceType(CanType ClassOrMetatypeType) { - if (auto MetaType = dyn_cast(ClassOrMetatypeType)) - ClassOrMetatypeType = MetaType.getInstanceType(); +CanType swift::getSelfInstanceType(CanType classOrMetatypeType) { + if (auto metaType = dyn_cast(classOrMetatypeType)) + classOrMetatypeType = metaType.getInstanceType(); - if (auto SelfType = dyn_cast(ClassOrMetatypeType)) - ClassOrMetatypeType = SelfType.getSelfType(); - - return ClassOrMetatypeType; + if (auto selfType = dyn_cast(classOrMetatypeType)) + classOrMetatypeType = selfType.getSelfType(); + + return classOrMetatypeType; } /// Check if it is possible to devirtualize an Apply instruction /// and a class member obtained using the class_method instruction into /// a direct call to a specific member of a specific class. /// -/// \p AI is the apply to devirtualize. -/// \p CD is the class declaration we are devirtualizing for. +/// \p applySite is the apply to devirtualize. +/// \p cd is the class declaration we are devirtualizing for. /// return true if it is possible to devirtualize, false - otherwise. -bool swift::canDevirtualizeClassMethod(FullApplySite AI, - ClassDecl *CD, - OptRemark::Emitter *ORE, +bool swift::canDevirtualizeClassMethod(FullApplySite applySite, ClassDecl *cd, + OptRemark::Emitter *ore, bool isEffectivelyFinalMethod) { LLVM_DEBUG(llvm::dbgs() << " Trying to devirtualize : " - << *AI.getInstruction()); + << *applySite.getInstruction()); - SILModule &Mod = AI.getModule(); + SILModule &module = applySite.getModule(); - auto *MI = cast(AI.getCallee()); + auto *mi = cast(applySite.getCallee()); // Find the implementation of the member which should be invoked. - auto *F = getTargetClassMethod(Mod, CD, MI); + auto *f = getTargetClassMethod(module, cd, mi); // If we do not find any such function, we have no function to devirtualize // to... so bail. - if (!F) { + if (!f) { LLVM_DEBUG(llvm::dbgs() << " FAIL: Could not find matching VTable " "or vtable method for this class.\n"); return false; } // We need to disable the “effectively final” opt if a function is inlinable - if (isEffectivelyFinalMethod && AI.getFunction()->isSerialized()) { + if (isEffectivelyFinalMethod && applySite.getFunction()->isSerialized()) { LLVM_DEBUG(llvm::dbgs() << " FAIL: Could not optimize function " "because it is an effectively-final inlinable: " - << AI.getFunction()->getName() << "\n"); + << applySite.getFunction()->getName() << "\n"); return false; } // Mandatory inlining does class method devirtualization. I'm not sure if this // is really needed, but some test rely on this. // So even for Onone functions we have to do it if the SILStage is raw. - if (F->getModule().getStage() != SILStage::Raw && !F->shouldOptimize()) { + if (f->getModule().getStage() != SILStage::Raw && !f->shouldOptimize()) { // Do not consider functions that should not be optimized. - LLVM_DEBUG(llvm::dbgs() << " FAIL: Could not optimize function " - << " because it is marked no-opt: " << F->getName() - << "\n"); + LLVM_DEBUG(llvm::dbgs() + << " FAIL: Could not optimize function " + << " because it is marked no-opt: " << f->getName() << "\n"); return false; } - if (AI.getFunction()->isSerialized()) { + if (applySite.getFunction()->isSerialized()) { // function_ref inside fragile function cannot reference a private or // hidden symbol. - if (!F->hasValidLinkageForFragileRef()) + if (!f->hasValidLinkageForFragileRef()) return false; } // devirtualizeClassMethod below does not support this case. It currently // assumes it can try_apply call the target. - if (!F->getLoweredFunctionType()->hasErrorResult() && - isa(AI.getInstruction())) { + if (!f->getLoweredFunctionType()->hasErrorResult() + && isa(applySite.getInstruction())) { LLVM_DEBUG(llvm::dbgs() << " FAIL: Trying to devirtualize a " "try_apply but vtable entry has no error result.\n"); return false; @@ -735,102 +724,100 @@ bool swift::canDevirtualizeClassMethod(FullApplySite AI, /// Devirtualize an apply of a class method. /// -/// \p AI is the apply to devirtualize. +/// \p applySite is the apply to devirtualize. /// \p ClassOrMetatype is a class value or metatype value that is the /// self argument of the apply we will devirtualize. /// return the result value of the new ApplyInst if created one or null. -FullApplySite swift::devirtualizeClassMethod(FullApplySite AI, - SILValue ClassOrMetatype, - ClassDecl *CD, - OptRemark::Emitter *ORE) { +FullApplySite swift::devirtualizeClassMethod(FullApplySite applySite, + SILValue classOrMetatype, + ClassDecl *cd, + OptRemark::Emitter *ore) { LLVM_DEBUG(llvm::dbgs() << " Trying to devirtualize : " - << *AI.getInstruction()); + << *applySite.getInstruction()); - SILModule &Mod = AI.getModule(); - auto *MI = cast(AI.getCallee()); + SILModule &module = applySite.getModule(); + auto *mi = cast(applySite.getCallee()); - auto *F = getTargetClassMethod(Mod, CD, MI); + auto *f = getTargetClassMethod(module, cd, mi); - CanSILFunctionType GenCalleeType = F->getLoweredFunctionType(); + CanSILFunctionType genCalleeType = f->getLoweredFunctionType(); - SubstitutionMap Subs = - getSubstitutionsForCallee(Mod, GenCalleeType, - ClassOrMetatype->getType().getASTType(), - AI); - CanSILFunctionType SubstCalleeType = GenCalleeType; - if (GenCalleeType->isPolymorphic()) - SubstCalleeType = GenCalleeType->substGenericArgs(Mod, Subs); - SILFunctionConventions substConv(SubstCalleeType, Mod); + SubstitutionMap subs = getSubstitutionsForCallee( + module, genCalleeType, classOrMetatype->getType().getASTType(), + applySite); + CanSILFunctionType substCalleeType = genCalleeType; + if (genCalleeType->isPolymorphic()) + substCalleeType = genCalleeType->substGenericArgs(module, subs); + SILFunctionConventions substConv(substCalleeType, module); - SILBuilderWithScope B(AI.getInstruction()); - SILLocation Loc = AI.getLoc(); - auto *FRI = B.createFunctionRefFor(Loc, F); + SILBuilderWithScope builder(applySite.getInstruction()); + SILLocation loc = applySite.getLoc(); + auto *fri = builder.createFunctionRefFor(loc, f); // Create the argument list for the new apply, casting when needed // in order to handle covariant indirect return types and // contravariant argument types. - SmallVector NewArgs; + SmallVector newArgs; // If we have a value that is owned, but that we are going to use in as a // guaranteed argument, we need to borrow/unborrow the argument. Otherwise, we // will introduce new consuming uses. In contrast, if we have an owned value, // we are ok due to the forwarding nature of upcasts. - SmallVector NewArgBorrows; + SmallVector newArgBorrows; - auto IndirectResultArgIter = AI.getIndirectSILResults().begin(); - for (auto ResultTy : substConv.getIndirectSILResultTypes()) { - NewArgs.push_back( - castValueToABICompatibleType(&B, Loc, *IndirectResultArgIter, - IndirectResultArgIter->getType(), ResultTy)); - ++IndirectResultArgIter; + auto indirectResultArgIter = applySite.getIndirectSILResults().begin(); + for (auto resultTy : substConv.getIndirectSILResultTypes()) { + newArgs.push_back(castValueToABICompatibleType( + &builder, loc, *indirectResultArgIter, indirectResultArgIter->getType(), + resultTy)); + ++indirectResultArgIter; } - auto ParamArgIter = AI.getArgumentsWithoutIndirectResults().begin(); + auto paramArgIter = applySite.getArgumentsWithoutIndirectResults().begin(); // Skip the last parameter, which is `self`. Add it below. for (auto param : substConv.getParameters()) { auto paramType = substConv.getSILType(param); - SILValue arg = *ParamArgIter; - if (B.hasOwnership() - && arg->getType().isObject() + SILValue arg = *paramArgIter; + if (builder.hasOwnership() && arg->getType().isObject() && arg.getOwnershipKind() == ValueOwnershipKind::Owned && param.isGuaranteed()) { - SILBuilderWithScope builder(AI.getInstruction(), B); - arg = builder.createBeginBorrow(Loc, arg); - NewArgBorrows.push_back(arg); + SILBuilderWithScope borrowBuilder(applySite.getInstruction(), builder); + arg = borrowBuilder.createBeginBorrow(loc, arg); + newArgBorrows.push_back(arg); } - arg = castValueToABICompatibleType(&B, Loc, arg, ParamArgIter->getType(), - paramType); - NewArgs.push_back(arg); - ++ParamArgIter; + arg = castValueToABICompatibleType(&builder, loc, arg, + paramArgIter->getType(), paramType); + newArgs.push_back(arg); + ++paramArgIter; } - ApplySite NewAS = replaceApplySite(B, Loc, AI, FRI, Subs, NewArgs, substConv, - NewArgBorrows); - FullApplySite NewAI = FullApplySite::isa(NewAS.getInstruction()); - assert(NewAI); + ApplySite newAS = replaceApplySite(builder, loc, applySite, fri, subs, + newArgs, substConv, newArgBorrows); + FullApplySite newAI = FullApplySite::isa(newAS.getInstruction()); + assert(newAI); - LLVM_DEBUG(llvm::dbgs() << " SUCCESS: " << F->getName() << "\n"); - if (ORE) - ORE->emit([&]() { - using namespace OptRemark; - return RemarkPassed("ClassMethodDevirtualized", *AI.getInstruction()) - << "Devirtualized call to class method " << NV("Method", F); - }); + LLVM_DEBUG(llvm::dbgs() << " SUCCESS: " << f->getName() << "\n"); + if (ore) + ore->emit([&]() { + using namespace OptRemark; + return RemarkPassed("ClassMethodDevirtualized", + *applySite.getInstruction()) + << "Devirtualized call to class method " << NV("Method", f); + }); NumClassDevirt++; - return NewAI; + return newAI; } -FullApplySite -swift::tryDevirtualizeClassMethod(FullApplySite AI, SILValue ClassInstance, - ClassDecl *CD, - OptRemark::Emitter *ORE, - bool isEffectivelyFinalMethod) { - if (!canDevirtualizeClassMethod(AI, CD, ORE, isEffectivelyFinalMethod)) +FullApplySite swift::tryDevirtualizeClassMethod(FullApplySite applySite, + SILValue classInstance, + ClassDecl *cd, + OptRemark::Emitter *ore, + bool isEffectivelyFinalMethod) { + if (!canDevirtualizeClassMethod(applySite, cd, ore, isEffectivelyFinalMethod)) return FullApplySite(); - return devirtualizeClassMethod(AI, ClassInstance, CD, ORE); + return devirtualizeClassMethod(applySite, classInstance, cd, ore); } - //===----------------------------------------------------------------------===// // Witness Method Optimization //===----------------------------------------------------------------------===// @@ -944,24 +931,24 @@ getWitnessMethodSubstitutions( } SubstitutionMap -swift::getWitnessMethodSubstitutions(SILModule &Module, ApplySite AI, - SILFunction *F, - ProtocolConformanceRef CRef) { - auto witnessFnTy = F->getLoweredFunctionType(); +swift::getWitnessMethodSubstitutions(SILModule &module, ApplySite applySite, + SILFunction *f, + ProtocolConformanceRef cRef) { + auto witnessFnTy = f->getLoweredFunctionType(); assert(witnessFnTy->getRepresentation() == SILFunctionTypeRepresentation::WitnessMethod); - auto requirementSig = AI.getOrigCalleeType()->getGenericSignature(); + auto requirementSig = applySite.getOrigCalleeType()->getGenericSignature(); auto witnessThunkSig = witnessFnTy->getGenericSignature(); - SubstitutionMap origSubs = AI.getSubstitutionMap(); + SubstitutionMap origSubs = applySite.getSubstitutionMap(); - auto *mod = Module.getSwiftModule(); + auto *mod = module.getSwiftModule(); bool isSelfAbstract = witnessFnTy->getSelfInstanceType()->is(); auto *classWitness = witnessFnTy->getWitnessMethodClass(); - return ::getWitnessMethodSubstitutions(mod, CRef, requirementSig, + return ::getWitnessMethodSubstitutions(mod, cRef, requirementSig, witnessThunkSig, origSubs, isSelfAbstract, classWitness); } @@ -969,97 +956,99 @@ swift::getWitnessMethodSubstitutions(SILModule &Module, ApplySite AI, /// Generate a new apply of a function_ref to replace an apply of a /// witness_method when we've determined the actual function we'll end /// up calling. -static ApplySite -devirtualizeWitnessMethod(ApplySite AI, SILFunction *F, - ProtocolConformanceRef C, OptRemark::Emitter *ORE) { +static ApplySite devirtualizeWitnessMethod(ApplySite applySite, SILFunction *f, + ProtocolConformanceRef cRef, + OptRemark::Emitter *ore) { // We know the witness thunk and the corresponding set of substitutions // required to invoke the protocol method at this point. - auto &Module = AI.getModule(); + auto &module = applySite.getModule(); // Collect all the required substitutions. // // The complete set of substitutions may be different, e.g. because the found - // witness thunk F may have been created by a specialization pass and have + // witness thunk f may have been created by a specialization pass and have // additional generic parameters. - auto SubMap = getWitnessMethodSubstitutions(Module, AI, F, C); + auto subMap = getWitnessMethodSubstitutions(module, applySite, f, cRef); // Figure out the exact bound type of the function to be called by // applying all substitutions. - auto CalleeCanType = F->getLoweredFunctionType(); - auto SubstCalleeCanType = CalleeCanType->substGenericArgs(Module, SubMap); + auto calleeCanType = f->getLoweredFunctionType(); + auto substCalleeCanType = calleeCanType->substGenericArgs(module, subMap); // Collect arguments from the apply instruction. - SmallVector Arguments; - SmallVector BorrowedArgs; + SmallVector arguments; + SmallVector borrowedArgs; // Iterate over the non self arguments and add them to the // new argument list, upcasting when required. - SILBuilderWithScope B(AI.getInstruction()); - SILFunctionConventions substConv(SubstCalleeCanType, Module); - unsigned substArgIdx = AI.getCalleeArgIndexOfFirstAppliedArg(); - for (auto arg : AI.getArguments()) { + SILBuilderWithScope argBuilder(applySite.getInstruction()); + SILFunctionConventions substConv(substCalleeCanType, module); + unsigned substArgIdx = applySite.getCalleeArgIndexOfFirstAppliedArg(); + for (auto arg : applySite.getArguments()) { auto paramInfo = substConv.getSILArgumentConvention(substArgIdx); auto paramType = substConv.getSILArgumentType(substArgIdx++); if (arg->getType() != paramType) { - if (B.hasOwnership() - && AI.getKind() != ApplySiteKind::PartialApplyInst + if (argBuilder.hasOwnership() + && applySite.getKind() != ApplySiteKind::PartialApplyInst && arg->getType().isObject() && arg.getOwnershipKind() == ValueOwnershipKind::Owned && paramInfo.isGuaranteedConvention()) { - SILBuilderWithScope builder(AI.getInstruction(), B); - arg = builder.createBeginBorrow(AI.getLoc(), arg); - BorrowedArgs.push_back(arg); + SILBuilderWithScope borrowBuilder(applySite.getInstruction(), + argBuilder); + arg = borrowBuilder.createBeginBorrow(applySite.getLoc(), arg); + borrowedArgs.push_back(arg); } - arg = castValueToABICompatibleType(&B, AI.getLoc(), arg, + arg = castValueToABICompatibleType(&argBuilder, applySite.getLoc(), arg, arg->getType(), paramType); } - Arguments.push_back(arg); + arguments.push_back(arg); } assert(substArgIdx == substConv.getNumSILArguments()); // Replace old apply instruction by a new apply instruction that invokes // the witness thunk. - SILBuilderWithScope Builder(AI.getInstruction()); - SILLocation Loc = AI.getLoc(); - auto *FRI = Builder.createFunctionRefFor(Loc, F); + SILBuilderWithScope applyBuilder(applySite.getInstruction()); + SILLocation loc = applySite.getLoc(); + auto *fri = applyBuilder.createFunctionRefFor(loc, f); - ApplySite SAI = replaceApplySite(Builder, Loc, AI, FRI, SubMap, Arguments, - substConv, BorrowedArgs); + ApplySite newApplySite = + replaceApplySite(applyBuilder, loc, applySite, fri, subMap, arguments, + substConv, borrowedArgs); - if (ORE) - ORE->emit([&]() { - using namespace OptRemark; - return RemarkPassed("WitnessMethodDevirtualized", *AI.getInstruction()) - << "Devirtualized call to " << NV("Method", F); - }); + if (ore) + ore->emit([&]() { + using namespace OptRemark; + return RemarkPassed("WitnessMethodDevirtualized", + *applySite.getInstruction()) + << "Devirtualized call to " << NV("Method", f); + }); NumWitnessDevirt++; - return SAI; + return newApplySite; } -static bool canDevirtualizeWitnessMethod(ApplySite AI) { - SILFunction *F; - SILWitnessTable *WT; +static bool canDevirtualizeWitnessMethod(ApplySite applySite) { + SILFunction *f; + SILWitnessTable *wt; - auto *WMI = cast(AI.getCallee()); + auto *wmi = cast(applySite.getCallee()); - std::tie(F, WT) = - AI.getModule().lookUpFunctionInWitnessTable(WMI->getConformance(), - WMI->getMember()); + std::tie(f, wt) = applySite.getModule().lookUpFunctionInWitnessTable( + wmi->getConformance(), wmi->getMember()); - if (!F) + if (!f) return false; - if (AI.getFunction()->isSerialized()) { + if (applySite.getFunction()->isSerialized()) { // function_ref inside fragile function cannot reference a private or // hidden symbol. - if (!F->hasValidLinkageForFragileRef()) + if (!f->hasValidLinkageForFragileRef()) return false; } // devirtualizeWitnessMethod below does not support this case. It currently // assumes it can try_apply call the target. - if (!F->getLoweredFunctionType()->hasErrorResult() && - isa(AI.getInstruction())) { + if (!f->getLoweredFunctionType()->hasErrorResult() + && isa(applySite.getInstruction())) { LLVM_DEBUG(llvm::dbgs() << " FAIL: Trying to devirtualize a " "try_apply but wtable entry has no error result.\n"); return false; @@ -1071,21 +1060,20 @@ static bool canDevirtualizeWitnessMethod(ApplySite AI) { /// In the cases where we can statically determine the function that /// we'll call to, replace an apply of a witness_method with an apply /// of a function_ref, returning the new apply. -ApplySite -swift::tryDevirtualizeWitnessMethod(ApplySite AI, OptRemark::Emitter *ORE) { - if (!canDevirtualizeWitnessMethod(AI)) +ApplySite swift::tryDevirtualizeWitnessMethod(ApplySite applySite, + OptRemark::Emitter *ore) { + if (!canDevirtualizeWitnessMethod(applySite)) return ApplySite(); - SILFunction *F; - SILWitnessTable *WT; + SILFunction *f; + SILWitnessTable *wt; - auto *WMI = cast(AI.getCallee()); + auto *wmi = cast(applySite.getCallee()); - std::tie(F, WT) = - AI.getModule().lookUpFunctionInWitnessTable(WMI->getConformance(), - WMI->getMember()); + std::tie(f, wt) = applySite.getModule().lookUpFunctionInWitnessTable( + wmi->getConformance(), wmi->getMember()); - return devirtualizeWitnessMethod(AI, F, WMI->getConformance(), ORE); + return devirtualizeWitnessMethod(applySite, f, wmi->getConformance(), ore); } //===----------------------------------------------------------------------===// @@ -1094,23 +1082,23 @@ swift::tryDevirtualizeWitnessMethod(ApplySite AI, OptRemark::Emitter *ORE) { /// Attempt to devirtualize the given apply if possible, and return a /// new instruction in that case, or nullptr otherwise. -ApplySite swift::tryDevirtualizeApply(ApplySite AI, - ClassHierarchyAnalysis *CHA, - OptRemark::Emitter *ORE) { +ApplySite swift::tryDevirtualizeApply(ApplySite applySite, + ClassHierarchyAnalysis *cha, + OptRemark::Emitter *ore) { LLVM_DEBUG(llvm::dbgs() << " Trying to devirtualize: " - << *AI.getInstruction()); + << *applySite.getInstruction()); // Devirtualize apply instructions that call witness_method instructions: // // %8 = witness_method $Optional, #LogicValue.boolValue!getter.1 // %9 = apply %8(%6#1) : ... // - if (isa(AI.getCallee())) - return tryDevirtualizeWitnessMethod(AI, ORE); + if (isa(applySite.getCallee())) + return tryDevirtualizeWitnessMethod(applySite, ore); // TODO: check if we can also de-virtualize partial applies of class methods. - FullApplySite FAS = FullApplySite::isa(AI.getInstruction()); - if (!FAS) + FullApplySite fas = FullApplySite::isa(applySite.getInstruction()); + if (!fas) return ApplySite(); /// Optimize a class_method and alloc_ref pair into a direct function @@ -1129,48 +1117,49 @@ ApplySite swift::tryDevirtualizeApply(ApplySite AI, /// into /// /// %YY = function_ref @... - if (auto *CMI = dyn_cast(FAS.getCallee())) { - auto Instance = stripUpCasts(CMI->getOperand()); - auto ClassType = getSelfInstanceType(Instance->getType().getASTType()); - auto *CD = ClassType.getClassOrBoundGenericClass(); + if (auto *cmi = dyn_cast(fas.getCallee())) { + auto instance = stripUpCasts(cmi->getOperand()); + auto classType = getSelfInstanceType(instance->getType().getASTType()); + auto *cd = classType.getClassOrBoundGenericClass(); - if (isEffectivelyFinalMethod(FAS, ClassType, CD, CHA)) - return tryDevirtualizeClassMethod(FAS, Instance, CD, ORE, + if (isEffectivelyFinalMethod(fas, classType, cd, cha)) + return tryDevirtualizeClassMethod(fas, instance, cd, ore, true /*isEffectivelyFinalMethod*/); // Try to check if the exact dynamic type of the instance is statically // known. - if (auto Instance = getInstanceWithExactDynamicType(CMI->getOperand(), CHA)) - return tryDevirtualizeClassMethod(FAS, Instance, CD, ORE); + if (auto instance = getInstanceWithExactDynamicType(cmi->getOperand(), cha)) + return tryDevirtualizeClassMethod(fas, instance, cd, ore); - if (auto ExactTy = getExactDynamicType(CMI->getOperand(), CHA)) { - if (ExactTy == CMI->getOperand()->getType()) - return tryDevirtualizeClassMethod(FAS, CMI->getOperand(), CD, ORE); + if (auto exactTy = getExactDynamicType(cmi->getOperand(), cha)) { + if (exactTy == cmi->getOperand()->getType()) + return tryDevirtualizeClassMethod(fas, cmi->getOperand(), cd, ore); } } - if (isa(FAS.getCallee())) { - auto Instance = FAS.getArguments().back(); - auto ClassType = getSelfInstanceType(Instance->getType().getASTType()); - auto *CD = ClassType.getClassOrBoundGenericClass(); + if (isa(fas.getCallee())) { + auto instance = fas.getArguments().back(); + auto classType = getSelfInstanceType(instance->getType().getASTType()); + auto *cd = classType.getClassOrBoundGenericClass(); - return tryDevirtualizeClassMethod(FAS, Instance, CD, ORE); + return tryDevirtualizeClassMethod(fas, instance, cd, ore); } return ApplySite(); } -bool swift::canDevirtualizeApply(FullApplySite AI, ClassHierarchyAnalysis *CHA) { +bool swift::canDevirtualizeApply(FullApplySite applySite, + ClassHierarchyAnalysis *cha) { LLVM_DEBUG(llvm::dbgs() << " Trying to devirtualize: " - << *AI.getInstruction()); + << *applySite.getInstruction()); // Devirtualize apply instructions that call witness_method instructions: // // %8 = witness_method $Optional, #LogicValue.boolValue!getter.1 // %9 = apply %8(%6#1) : ... // - if (isa(AI.getCallee())) - return canDevirtualizeWitnessMethod(AI); + if (isa(applySite.getCallee())) + return canDevirtualizeWitnessMethod(applySite); /// Optimize a class_method and alloc_ref pair into a direct function /// reference: @@ -1188,33 +1177,32 @@ bool swift::canDevirtualizeApply(FullApplySite AI, ClassHierarchyAnalysis *CHA) /// into /// /// %YY = function_ref @... - if (auto *CMI = dyn_cast(AI.getCallee())) { - auto Instance = stripUpCasts(CMI->getOperand()); - auto ClassType = getSelfInstanceType(Instance->getType().getASTType()); - auto *CD = ClassType.getClassOrBoundGenericClass(); + if (auto *cmi = dyn_cast(applySite.getCallee())) { + auto instance = stripUpCasts(cmi->getOperand()); + auto classType = getSelfInstanceType(instance->getType().getASTType()); + auto *cd = classType.getClassOrBoundGenericClass(); - if (isEffectivelyFinalMethod(AI, ClassType, CD, CHA)) - return canDevirtualizeClassMethod(AI, CD, - nullptr /*ORE*/, + if (isEffectivelyFinalMethod(applySite, classType, cd, cha)) + return canDevirtualizeClassMethod(applySite, cd, nullptr /*ore*/, true /*isEffectivelyFinalMethod*/); // Try to check if the exact dynamic type of the instance is statically // known. - if (auto Instance = getInstanceWithExactDynamicType(CMI->getOperand(), CHA)) - return canDevirtualizeClassMethod(AI, CD); + if (auto instance = getInstanceWithExactDynamicType(cmi->getOperand(), cha)) + return canDevirtualizeClassMethod(applySite, cd); - if (auto ExactTy = getExactDynamicType(CMI->getOperand(), CHA)) { - if (ExactTy == CMI->getOperand()->getType()) - return canDevirtualizeClassMethod(AI, CD); + if (auto exactTy = getExactDynamicType(cmi->getOperand(), cha)) { + if (exactTy == cmi->getOperand()->getType()) + return canDevirtualizeClassMethod(applySite, cd); } } - if (isa(AI.getCallee())) { - auto Instance = AI.getArguments().back(); - auto ClassType = getSelfInstanceType(Instance->getType().getASTType()); - auto *CD = ClassType.getClassOrBoundGenericClass(); + if (isa(applySite.getCallee())) { + auto instance = applySite.getArguments().back(); + auto classType = getSelfInstanceType(instance->getType().getASTType()); + auto *cd = classType.getClassOrBoundGenericClass(); - return canDevirtualizeClassMethod(AI, CD); + return canDevirtualizeClassMethod(applySite, cd); } return false; diff --git a/lib/SILOptimizer/Utils/Existential.cpp b/lib/SILOptimizer/Utils/Existential.cpp index 04d10a6990b..07a78d27479 100644 --- a/lib/SILOptimizer/Utils/Existential.cpp +++ b/lib/SILOptimizer/Utils/Existential.cpp @@ -15,8 +15,8 @@ #include "swift/AST/ProtocolConformance.h" #include "swift/SIL/BasicBlockUtils.h" #include "swift/SIL/InstructionUtils.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/SmallPtrSet.h" using namespace swift; diff --git a/lib/SILOptimizer/Utils/GenericCloner.cpp b/lib/SILOptimizer/Utils/GenericCloner.cpp index ccee64e9647..f41e67384b1 100644 --- a/lib/SILOptimizer/Utils/GenericCloner.cpp +++ b/lib/SILOptimizer/Utils/GenericCloner.cpp @@ -15,11 +15,11 @@ #include "swift/AST/Type.h" #include "swift/SIL/SILBasicBlock.h" #include "swift/SIL/SILFunction.h" -#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILValue.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" diff --git a/lib/SILOptimizer/Utils/InstOptUtils.cpp b/lib/SILOptimizer/Utils/InstOptUtils.cpp new file mode 100644 index 00000000000..7d6e490078d --- /dev/null +++ b/lib/SILOptimizer/Utils/InstOptUtils.cpp @@ -0,0 +1,1577 @@ +//===--- InstOptUtils.cpp - SILOptimizer instruction utilities ------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 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 +// +//===----------------------------------------------------------------------===// + +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/AST/GenericSignature.h" +#include "swift/AST/SubstitutionMap.h" +#include "swift/SIL/BasicBlockUtils.h" +#include "swift/SIL/DebugUtils.h" +#include "swift/SIL/DynamicCasts.h" +#include "swift/SIL/InstructionUtils.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILBuilder.h" +#include "swift/SIL/SILModule.h" +#include "swift/SIL/SILUndef.h" +#include "swift/SIL/TypeLowering.h" +#include "swift/SILOptimizer/Analysis/ARCAnalysis.h" +#include "swift/SILOptimizer/Analysis/Analysis.h" +#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compiler.h" +#include + +using namespace swift; + +static llvm::cl::opt EnableExpandAll("enable-expand-all", + llvm::cl::init(false)); + +/// Creates an increment on \p Ptr before insertion point \p InsertPt that +/// creates a strong_retain if \p Ptr has reference semantics itself or a +/// retain_value if \p Ptr is a non-trivial value without reference-semantics. +NullablePtr +swift::createIncrementBefore(SILValue ptr, SILInstruction *insertPt) { + // Set up the builder we use to insert at our insertion point. + SILBuilder builder(insertPt); + auto loc = RegularLocation::getAutoGeneratedLocation(); + + // If we have a trivial type, just bail, there is no work to do. + if (ptr->getType().isTrivial(builder.getFunction())) + return nullptr; + + // If Ptr is refcounted itself, create the strong_retain and + // return. + if (ptr->getType().isReferenceCounted(builder.getModule())) { + if (ptr->getType().is()) + return builder.createUnownedRetain(loc, ptr, + builder.getDefaultAtomicity()); + else + return builder.createStrongRetain(loc, ptr, + builder.getDefaultAtomicity()); + } + + // Otherwise, create the retain_value. + return builder.createRetainValue(loc, ptr, builder.getDefaultAtomicity()); +} + +/// Creates a decrement on \p ptr before insertion point \p InsertPt that +/// creates a strong_release if \p ptr has reference semantics itself or +/// a release_value if \p ptr is a non-trivial value without +/// reference-semantics. +NullablePtr +swift::createDecrementBefore(SILValue ptr, SILInstruction *insertPt) { + // Setup the builder we will use to insert at our insertion point. + SILBuilder builder(insertPt); + auto loc = RegularLocation::getAutoGeneratedLocation(); + + if (ptr->getType().isTrivial(builder.getFunction())) + return nullptr; + + // If ptr has reference semantics itself, create a strong_release. + if (ptr->getType().isReferenceCounted(builder.getModule())) { + if (ptr->getType().is()) + return builder.createUnownedRelease(loc, ptr, + builder.getDefaultAtomicity()); + else + return builder.createStrongRelease(loc, ptr, + builder.getDefaultAtomicity()); + } + + // Otherwise create a release value. + return builder.createReleaseValue(loc, ptr, builder.getDefaultAtomicity()); +} + +/// 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 *inst) { + // At Onone, consider all uses, including the debug_info. + // This way, debug_info is preserved at Onone. + if (inst->hasUsesOfAnyResult() + && inst->getFunction()->getEffectiveOptimizationMode() + <= OptimizationMode::NoOptimization) + return false; + + if (!onlyHaveDebugUsesOfAllResults(inst) || isa(inst)) + return false; + + if (auto *bi = dyn_cast(inst)) { + // Although the onFastPath builtin has no side-effects we don't want to + // remove it. + if (bi->getBuiltinInfo().ID == BuiltinValueKind::OnFastPath) + return false; + return !bi->mayHaveSideEffects(); + } + + // condfail instructions that obviously can't fail are dead. + if (auto *cfi = dyn_cast(inst)) + if (auto *ili = dyn_cast(cfi->getOperand())) + if (!ili->getValue()) + return true; + + // mark_uninitialized is never dead. + if (isa(inst)) + return false; + + if (isa(inst) || isa(inst)) + return false; + + // These invalidate enums so "write" memory, but that is not an essential + // operation so we can remove these if they are trivially dead. + if (isa(inst)) + return true; + + if (!inst->mayHaveSideEffects()) + return true; + + return false; +} + +/// Return true if this is a release instruction and the released value +/// is a part of a guaranteed parameter. +bool swift::isIntermediateRelease(SILInstruction *inst, + EpilogueARCFunctionInfo *eafi) { + // Check whether this is a release instruction. + if (!isa(inst) && !isa(inst)) + return false; + + // OK. we have a release instruction. + // Check whether this is a release on part of a guaranteed function argument. + SILValue Op = stripValueProjections(inst->getOperand(0)); + auto *arg = dyn_cast(Op); + if (!arg) + return false; + + // This is a release on a guaranteed parameter. Its not the final release. + if (arg->hasConvention(SILArgumentConvention::Direct_Guaranteed)) + return true; + + // This is a release on an owned parameter and its not the epilogue release. + // Its not the final release. + auto rel = eafi->computeEpilogueARCInstructions( + EpilogueARCContext::EpilogueARCKind::Release, arg); + if (rel.size() && !rel.count(inst)) + return true; + + // Failed to prove anything. + return false; +} + +namespace { +using CallbackTy = llvm::function_ref; +} // end anonymous namespace + +void swift::recursivelyDeleteTriviallyDeadInstructions( + ArrayRef ia, bool force, CallbackTy callback) { + // Delete these instruction and others that become dead after it's deleted. + llvm::SmallPtrSet deadInsts; + for (auto *inst : ia) { + // If the instruction is not dead and force is false, do nothing. + if (force || isInstructionTriviallyDead(inst)) + deadInsts.insert(inst); + } + llvm::SmallPtrSet nextInsts; + while (!deadInsts.empty()) { + for (auto inst : deadInsts) { + // Call the callback before we mutate the to be deleted instruction in any + // way. + callback(inst); + + // Check if any of the operands will become dead as well. + MutableArrayRef operands = inst->getAllOperands(); + for (Operand &operand : operands) { + SILValue operandVal = operand.get(); + if (!operandVal) + continue; + + // Remove the reference from the instruction being deleted to this + // operand. + operand.drop(); + + // If the operand is an instruction that is only used by the instruction + // being deleted, delete it. + if (auto *operandValInst = operandVal->getDefiningInstruction()) + if (!deadInsts.count(operandValInst) + && isInstructionTriviallyDead(operandValInst)) + nextInsts.insert(operandValInst); + } + + // If we have a function ref inst, we need to especially drop its function + // argument so that it gets a proper ref decrement. + auto *fri = dyn_cast(inst); + if (fri && fri->getInitiallyReferencedFunction()) + fri->dropReferencedFunction(); + + auto *dfri = dyn_cast(inst); + if (dfri && dfri->getInitiallyReferencedFunction()) + dfri->dropReferencedFunction(); + + auto *pfri = dyn_cast(inst); + if (pfri && pfri->getInitiallyReferencedFunction()) + pfri->dropReferencedFunction(); + } + + for (auto inst : deadInsts) { + // This will remove this instruction and all its uses. + eraseFromParentWithDebugInsts(inst, callback); + } + + nextInsts.swap(deadInsts); + nextInsts.clear(); + } +} + +/// If the given instruction is dead, delete it along with its dead +/// operands. +/// +/// \param inst 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. +void swift::recursivelyDeleteTriviallyDeadInstructions(SILInstruction *inst, + bool force, + CallbackTy callback) { + ArrayRef ai = ArrayRef(inst); + recursivelyDeleteTriviallyDeadInstructions(ai, force, callback); +} + +void swift::eraseUsesOfInstruction(SILInstruction *inst, CallbackTy callback) { + for (auto result : inst->getResults()) { + while (!result->use_empty()) { + auto ui = result->use_begin(); + auto *user = ui->getUser(); + assert(user && "User should never be NULL!"); + + // If the instruction itself has any uses, recursively zap them so that + // nothing uses this instruction. + eraseUsesOfInstruction(user, callback); + + // Walk through the operand list and delete any random instructions that + // will become trivially dead when this instruction is removed. + + for (auto &operand : user->getAllOperands()) { + if (auto *operandI = operand.get()->getDefiningInstruction()) { + // Don't recursively delete the instruction we're working on. + // FIXME: what if we're being recursively invoked? + if (operandI != inst) { + operand.drop(); + recursivelyDeleteTriviallyDeadInstructions(operandI, false, + callback); + } + } + } + callback(user); + user->eraseFromParent(); + } + } +} + +void swift::collectUsesOfValue(SILValue v, + llvm::SmallPtrSetImpl &insts) { + for (auto ui = v->use_begin(), E = v->use_end(); ui != E; ui++) { + auto *user = ui->getUser(); + // Instruction has been processed. + if (!insts.insert(user).second) + continue; + + // Collect the users of this instruction. + for (auto result : user->getResults()) + collectUsesOfValue(result, insts); + } +} + +void swift::eraseUsesOfValue(SILValue v) { + llvm::SmallPtrSet insts; + // Collect the uses. + collectUsesOfValue(v, insts); + // Erase the uses, we can have instructions that become dead because + // of the removal of these instructions, leave to DCE to cleanup. + // Its not safe to do recursively delete here as some of the SILInstruction + // maybe tracked by this set. + for (auto inst : insts) { + inst->replaceAllUsesOfAllResultsWithUndef(); + inst->eraseFromParent(); + } +} + +// Devirtualization of functions with covariant return types produces +// a result that is not an apply, but takes an apply as an +// argument. Attempt to dig the apply out from this result. +FullApplySite swift::findApplyFromDevirtualizedResult(SILValue v) { + if (auto Apply = FullApplySite::isa(v)) + return Apply; + + if (isa(v) || isa(v) || isa(v)) + return findApplyFromDevirtualizedResult( + cast(v)->getOperand(0)); + + return FullApplySite(); +} + +bool swift::mayBindDynamicSelf(SILFunction *F) { + if (!F->hasSelfMetadataParam()) + return false; + + SILValue mdArg = F->getSelfMetadataArgument(); + + for (Operand *mdUse : F->getSelfMetadataArgument()->getUses()) { + SILInstruction *mdUser = mdUse->getUser(); + for (Operand &typeDepOp : mdUser->getTypeDependentOperands()) { + if (typeDepOp.get() == mdArg) + return true; + } + } + return false; +} + +static SILValue skipAddrProjections(SILValue v) { + for (;;) { + switch (v->getKind()) { + case ValueKind::IndexAddrInst: + case ValueKind::IndexRawPointerInst: + case ValueKind::StructElementAddrInst: + case ValueKind::TupleElementAddrInst: + v = cast(v)->getOperand(0); + break; + default: + return v; + } + } + llvm_unreachable("there is no escape from an infinite loop"); +} + +/// Check whether the \p addr is an address of a tail-allocated array element. +bool swift::isAddressOfArrayElement(SILValue addr) { + addr = stripAddressProjections(addr); + if (auto *md = dyn_cast(addr)) + addr = stripAddressProjections(md->getValue()); + + // High-level SIL: check for an get_element_address array semantics call. + if (auto *ptrToAddr = dyn_cast(addr)) + if (auto *sei = dyn_cast(ptrToAddr->getOperand())) { + ArraySemanticsCall call(sei->getOperand()); + if (call && call.getKind() == ArrayCallKind::kGetElementAddress) + return true; + } + + // Check for an tail-address (of an array buffer object). + if (isa(skipAddrProjections(addr))) + return true; + + return false; +} + +/// Find a new position for an ApplyInst's FuncRef so that it dominates its +/// use. Not that FunctionRefInsts may be shared by multiple ApplyInsts. +void swift::placeFuncRef(ApplyInst *ai, DominanceInfo *domInfo) { + FunctionRefInst *funcRef = cast(ai->getCallee()); + SILBasicBlock *domBB = domInfo->findNearestCommonDominator( + ai->getParent(), funcRef->getParent()); + if (domBB == ai->getParent() && domBB != funcRef->getParent()) + // Prefer to place the FuncRef immediately before the call. Since we're + // moving FuncRef up, this must be the only call to it in the block. + funcRef->moveBefore(ai); + else + // Otherwise, conservatively stick it at the beginning of the block. + funcRef->moveBefore(&*domBB->begin()); +} + +/// 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 *swift::addArgumentToBranch(SILValue val, SILBasicBlock *dest, + TermInst *branch) { + SILBuilderWithScope builder(branch); + + if (auto *cbi = dyn_cast(branch)) { + SmallVector trueArgs; + SmallVector falseArgs; + + for (auto arg : cbi->getTrueArgs()) + trueArgs.push_back(arg); + + for (auto arg : cbi->getFalseArgs()) + falseArgs.push_back(arg); + + if (dest == cbi->getTrueBB()) { + trueArgs.push_back(val); + assert(trueArgs.size() == dest->getNumArguments()); + } else { + falseArgs.push_back(val); + assert(falseArgs.size() == dest->getNumArguments()); + } + + return builder.createCondBranch( + cbi->getLoc(), cbi->getCondition(), cbi->getTrueBB(), trueArgs, + cbi->getFalseBB(), falseArgs, cbi->getTrueBBCount(), + cbi->getFalseBBCount()); + } + + if (auto *bi = dyn_cast(branch)) { + SmallVector args; + + for (auto arg : bi->getArgs()) + args.push_back(arg); + + args.push_back(val); + assert(args.size() == dest->getNumArguments()); + return builder.createBranch(bi->getLoc(), bi->getDestBB(), args); + } + + llvm_unreachable("unsupported terminator"); +} + +SILLinkage swift::getSpecializedLinkage(SILFunction *f, SILLinkage linkage) { + if (hasPrivateVisibility(linkage) && !f->isSerialized()) { + // Specializations of private symbols should remain so, unless + // they were serialized, which can only happen when specializing + // definitions from a standard library built with -sil-serialize-all. + return SILLinkage::Private; + } + + return SILLinkage::Shared; +} + +/// 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. +/// +/// If CheckOnly flag is set, then this function only checks if the +/// required casting is possible. If it is not possible, then None +/// is returned. +/// +/// If CheckOnly is not set, then a casting code is generated and the final +/// casted value is returned. +/// +/// NOTE: We intentionally combine the checking of the cast's handling +/// possibility and the transformation performing the cast in the same function, +/// to avoid any divergence between the check and the implementation in the +/// future. +/// +/// NOTE: The implementation of this function is very closely related to the +/// rules checked by SILVerifier::requireABICompatibleFunctionTypes. +SILValue swift::castValueToABICompatibleType(SILBuilder *builder, + SILLocation loc, SILValue value, + SILType srcTy, SILType destTy) { + + // No cast is required if types are the same. + if (srcTy == destTy) + return value; + + assert(srcTy.isAddress() == destTy.isAddress() + && "Addresses aren't compatible with values"); + + if (srcTy.isAddress() && destTy.isAddress()) { + // Cast between two addresses and that's it. + return builder->createUncheckedAddrCast(loc, value, destTy); + } + + // If both types are classes and dest is the superclass of src, + // simply perform an upcast. + if (destTy.isExactSuperclassOf(srcTy)) { + return builder->createUpcast(loc, value, destTy); + } + + if (srcTy.isHeapObjectReferenceType() && destTy.isHeapObjectReferenceType()) { + return builder->createUncheckedRefCast(loc, value, destTy); + } + + if (auto mt1 = srcTy.getAs()) { + if (auto mt2 = destTy.getAs()) { + if (mt1->getRepresentation() == mt2->getRepresentation()) { + // If builder.Type needs to be casted to A.Type and + // A is a superclass of builder, then it can be done by means + // of a simple upcast. + if (mt2.getInstanceType()->isExactSuperclassOf(mt1.getInstanceType())) { + return builder->createUpcast(loc, value, destTy); + } + + // Cast between two metatypes and that's it. + return builder->createUncheckedBitCast(loc, value, destTy); + } + } + } + + // Check if src and dest types are optional. + auto optionalSrcTy = srcTy.getOptionalObjectType(); + auto optionalDestTy = destTy.getOptionalObjectType(); + + // Both types are optional. + if (optionalDestTy && optionalSrcTy) { + // If both wrapped types are classes and dest is the superclass of src, + // simply perform an upcast. + if (optionalDestTy.isExactSuperclassOf(optionalSrcTy)) { + // Insert upcast. + return builder->createUpcast(loc, value, destTy); + } + + // Unwrap the original optional value. + auto *someDecl = builder->getASTContext().getOptionalSomeDecl(); + auto *noneBB = builder->getFunction().createBasicBlock(); + auto *someBB = builder->getFunction().createBasicBlock(); + auto *curBB = builder->getInsertionPoint()->getParent(); + + auto *contBB = curBB->split(builder->getInsertionPoint()); + contBB->createPhiArgument(destTy, ValueOwnershipKind::Owned); + + SmallVector, 1> caseBBs; + caseBBs.push_back(std::make_pair(someDecl, someBB)); + builder->setInsertionPoint(curBB); + builder->createSwitchEnum(loc, value, noneBB, caseBBs); + + // Handle the Some case. + builder->setInsertionPoint(someBB); + SILValue unwrappedValue = + builder->createUncheckedEnumData(loc, value, someDecl); + // Cast the unwrapped value. + auto castedUnwrappedValue = castValueToABICompatibleType( + builder, loc, unwrappedValue, optionalSrcTy, optionalDestTy); + // Wrap into optional. + auto castedValue = + builder->createOptionalSome(loc, castedUnwrappedValue, destTy); + builder->createBranch(loc, contBB, {castedValue}); + + // Handle the None case. + builder->setInsertionPoint(noneBB); + castedValue = builder->createOptionalNone(loc, destTy); + builder->createBranch(loc, contBB, {castedValue}); + builder->setInsertionPoint(contBB->begin()); + + return contBB->getArgument(0); + } + + // Src is not optional, but dest is optional. + if (!optionalSrcTy && optionalDestTy) { + auto optionalSrcCanTy = + OptionalType::get(srcTy.getASTType())->getCanonicalType(); + auto loweredOptionalSrcType = + SILType::getPrimitiveObjectType(optionalSrcCanTy); + + // Wrap the source value into an optional first. + SILValue wrappedValue = + builder->createOptionalSome(loc, value, loweredOptionalSrcType); + // Cast the wrapped value. + return castValueToABICompatibleType(builder, loc, wrappedValue, + wrappedValue->getType(), destTy); + } + + // Handle tuple types. + // Extract elements, cast each of them, create a new tuple. + if (auto srcTupleTy = srcTy.getAs()) { + SmallVector expectedTuple; + for (unsigned i = 0, e = srcTupleTy->getNumElements(); i < e; i++) { + SILValue element = builder->createTupleExtract(loc, value, i); + // Cast the value if necessary. + element = castValueToABICompatibleType(builder, loc, element, + srcTy.getTupleElementType(i), + destTy.getTupleElementType(i)); + expectedTuple.push_back(element); + } + + return builder->createTuple(loc, destTy, expectedTuple); + } + + // Function types are interchangeable if they're also ABI-compatible. + if (srcTy.is()) { + if (destTy.is()) { + assert(srcTy.getAs()->isNoEscape() + == destTy.getAs()->isNoEscape() + || srcTy.getAs()->getRepresentation() + != SILFunctionType::Representation::Thick + && "Swift thick functions that differ in escapeness are " + "not ABI " + "compatible"); + // Insert convert_function. + return builder->createConvertFunction(loc, value, destTy, + /*WithoutActuallyEscaping=*/false); + } + } + + llvm::errs() << "Source type: " << srcTy << "\n"; + llvm::errs() << "Destination type: " << destTy << "\n"; + llvm_unreachable("Unknown combination of types for casting"); +} + +ProjectBoxInst *swift::getOrCreateProjectBox(AllocBoxInst *abi, + unsigned index) { + SILBasicBlock::iterator iter(abi); + iter++; + assert(iter != abi->getParent()->end() + && "alloc_box cannot be the last instruction of a block"); + SILInstruction *nextInst = &*iter; + if (auto *pbi = dyn_cast(nextInst)) { + if (pbi->getOperand() == abi && pbi->getFieldIndex() == index) + return pbi; + } + + SILBuilder builder(nextInst); + return builder.createProjectBox(abi->getLoc(), abi, index); +} + +// Peek through trivial Enum initialization, typically for pointless +// Optionals. +// +// Given an UncheckedTakeEnumDataAddrInst, check that there are no +// other uses of the Enum value and return the address used to initialized the +// enum's payload: +// +// %stack_adr = alloc_stack +// %data_adr = init_enum_data_addr %stk_adr +// %enum_adr = inject_enum_addr %stack_adr +// %copy_src = unchecked_take_enum_data_addr %enum_adr +// dealloc_stack %stack_adr +// (No other uses of %stack_adr.) +InitEnumDataAddrInst * +swift::findInitAddressForTrivialEnum(UncheckedTakeEnumDataAddrInst *utedai) { + auto *asi = dyn_cast(utedai->getOperand()); + if (!asi) + return nullptr; + + SILInstruction *singleUser = nullptr; + for (auto use : asi->getUses()) { + auto *user = use->getUser(); + if (user == utedai) + continue; + + // As long as there's only one UncheckedTakeEnumDataAddrInst and one + // InitEnumDataAddrInst, we don't care how many InjectEnumAddr and + // DeallocStack users there are. + if (isa(user) || isa(user)) + continue; + + if (singleUser) + return nullptr; + + singleUser = user; + } + if (!singleUser) + return nullptr; + + // Assume, without checking, that the returned InitEnumDataAddr dominates the + // given UncheckedTakeEnumDataAddrInst, because that's how SIL is defined. I + // don't know where this is actually verified. + return dyn_cast(singleUser); +} + +//===----------------------------------------------------------------------===// +// String Concatenation Optimizer +//===----------------------------------------------------------------------===// + +namespace { +/// This is a helper class that performs optimization of string literals +/// concatenation. +class StringConcatenationOptimizer { + /// Apply instruction being optimized. + ApplyInst *ai; + /// Builder to be used for creation of new instructions. + SILBuilder &builder; + /// Left string literal operand of a string concatenation. + StringLiteralInst *sliLeft = nullptr; + /// Right string literal operand of a string concatenation. + StringLiteralInst *sliRight = nullptr; + /// Function used to construct the left string literal. + FunctionRefInst *friLeft = nullptr; + /// Function used to construct the right string literal. + FunctionRefInst *friRight = nullptr; + /// Apply instructions used to construct left string literal. + ApplyInst *aiLeft = nullptr; + /// Apply instructions used to construct right string literal. + ApplyInst *aiRight = nullptr; + /// String literal conversion function to be used. + FunctionRefInst *friConvertFromBuiltin = nullptr; + /// Result type of a function producing the concatenated string literal. + SILValue funcResultType; + + /// Internal helper methods + bool extractStringConcatOperands(); + void adjustEncodings(); + APInt getConcatenatedLength(); + bool isAscii() const; + +public: + StringConcatenationOptimizer(ApplyInst *ai, SILBuilder &builder) + : ai(ai), builder(builder) {} + + /// Tries to optimize a given apply instruction if it is a + /// concatenation of string literals. + /// + /// Returns a new instruction if optimization was possible. + SingleValueInstruction *optimize(); +}; + +} // end anonymous namespace + +/// Checks operands of a string concatenation operation to see if +/// optimization is applicable. +/// +/// Returns false if optimization is not possible. +/// Returns true and initializes internal fields if optimization is possible. +bool StringConcatenationOptimizer::extractStringConcatOperands() { + auto *Fn = ai->getReferencedFunctionOrNull(); + if (!Fn) + return false; + + if (ai->getNumArguments() != 3 || !Fn->hasSemanticsAttr("string.concat")) + return false; + + // Left and right operands of a string concatenation operation. + aiLeft = dyn_cast(ai->getOperand(1)); + aiRight = dyn_cast(ai->getOperand(2)); + + if (!aiLeft || !aiRight) + return false; + + friLeft = dyn_cast(aiLeft->getCallee()); + friRight = dyn_cast(aiRight->getCallee()); + + if (!friLeft || !friRight) + return false; + + auto *friLeftFun = friLeft->getReferencedFunctionOrNull(); + auto *friRightFun = friRight->getReferencedFunctionOrNull(); + + if (friLeftFun->getEffectsKind() >= EffectsKind::ReleaseNone + || friRightFun->getEffectsKind() >= EffectsKind::ReleaseNone) + return false; + + if (!friLeftFun->hasSemanticsAttrs() || !friRightFun->hasSemanticsAttrs()) + return false; + + auto aiLeftOperandsNum = aiLeft->getNumOperands(); + auto aiRightOperandsNum = aiRight->getNumOperands(); + + // makeUTF8 should have following parameters: + // (start: RawPointer, utf8CodeUnitCount: Word, isASCII: Int1) + if (!((friLeftFun->hasSemanticsAttr("string.makeUTF8") + && aiLeftOperandsNum == 5) + || (friRightFun->hasSemanticsAttr("string.makeUTF8") + && aiRightOperandsNum == 5))) + return false; + + sliLeft = dyn_cast(aiLeft->getOperand(1)); + sliRight = dyn_cast(aiRight->getOperand(1)); + + if (!sliLeft || !sliRight) + return false; + + // Only UTF-8 and UTF-16 encoded string literals are supported by this + // optimization. + if (sliLeft->getEncoding() != StringLiteralInst::Encoding::UTF8 + && sliLeft->getEncoding() != StringLiteralInst::Encoding::UTF16) + return false; + + if (sliRight->getEncoding() != StringLiteralInst::Encoding::UTF8 + && sliRight->getEncoding() != StringLiteralInst::Encoding::UTF16) + return false; + + return true; +} + +/// Ensures that both string literals to be concatenated use the same +/// UTF encoding. Converts UTF-8 into UTF-16 if required. +void StringConcatenationOptimizer::adjustEncodings() { + if (sliLeft->getEncoding() == sliRight->getEncoding()) { + friConvertFromBuiltin = friLeft; + if (sliLeft->getEncoding() == StringLiteralInst::Encoding::UTF8) { + funcResultType = aiLeft->getOperand(4); + } else { + funcResultType = aiLeft->getOperand(3); + } + return; + } + + builder.setCurrentDebugScope(ai->getDebugScope()); + + // If one of the string literals is UTF8 and another one is UTF16, + // convert the UTF8-encoded string literal into UTF16-encoding first. + if (sliLeft->getEncoding() == StringLiteralInst::Encoding::UTF8 + && sliRight->getEncoding() == StringLiteralInst::Encoding::UTF16) { + funcResultType = aiRight->getOperand(3); + friConvertFromBuiltin = friRight; + // Convert UTF8 representation into UTF16. + sliLeft = builder.createStringLiteral(ai->getLoc(), sliLeft->getValue(), + StringLiteralInst::Encoding::UTF16); + } + + if (sliRight->getEncoding() == StringLiteralInst::Encoding::UTF8 + && sliLeft->getEncoding() == StringLiteralInst::Encoding::UTF16) { + funcResultType = aiLeft->getOperand(3); + friConvertFromBuiltin = friLeft; + // Convert UTF8 representation into UTF16. + sliRight = builder.createStringLiteral(ai->getLoc(), sliRight->getValue(), + StringLiteralInst::Encoding::UTF16); + } + + // It should be impossible to have two operands with different + // encodings at this point. + assert( + sliLeft->getEncoding() == sliRight->getEncoding() + && "Both operands of string concatenation should have the same encoding"); +} + +/// Computes the length of a concatenated string literal. +APInt StringConcatenationOptimizer::getConcatenatedLength() { + // Real length of string literals computed based on its contents. + // Length is in code units. + auto sliLenLeft = sliLeft->getCodeUnitCount(); + (void)sliLenLeft; + auto sliLenRight = sliRight->getCodeUnitCount(); + (void)sliLenRight; + + // Length of string literals as reported by string.make functions. + auto *lenLeft = dyn_cast(aiLeft->getOperand(2)); + auto *lenRight = dyn_cast(aiRight->getOperand(2)); + + // Real and reported length should be the same. + assert(sliLenLeft == lenLeft->getValue() + && "Size of string literal in @_semantics(string.make) is wrong"); + + assert(sliLenRight == lenRight->getValue() + && "Size of string literal in @_semantics(string.make) is wrong"); + + // Compute length of the concatenated literal. + return lenLeft->getValue() + lenRight->getValue(); +} + +/// Computes the isAscii flag of a concatenated UTF8-encoded string literal. +bool StringConcatenationOptimizer::isAscii() const { + // Add the isASCII argument in case of UTF8. + // IsASCII is true only if IsASCII of both literals is true. + auto *asciiLeft = dyn_cast(aiLeft->getOperand(3)); + auto *asciiRight = dyn_cast(aiRight->getOperand(3)); + auto isAsciiLeft = asciiLeft->getValue() == 1; + auto isAsciiRight = asciiRight->getValue() == 1; + return isAsciiLeft && isAsciiRight; +} + +SingleValueInstruction *StringConcatenationOptimizer::optimize() { + // Bail out if string literals concatenation optimization is + // not possible. + if (!extractStringConcatOperands()) + return nullptr; + + // Perform string literal encodings adjustments if needed. + adjustEncodings(); + + // Arguments of the new StringLiteralInst to be created. + SmallVector arguments; + + // Encoding to be used for the concatenated string literal. + auto encoding = sliLeft->getEncoding(); + + // Create a concatenated string literal. + builder.setCurrentDebugScope(ai->getDebugScope()); + auto lv = sliLeft->getValue(); + auto rv = sliRight->getValue(); + auto *newSLI = + builder.createStringLiteral(ai->getLoc(), lv + Twine(rv), encoding); + arguments.push_back(newSLI); + + // Length of the concatenated literal according to its encoding. + auto *len = builder.createIntegerLiteral( + ai->getLoc(), aiLeft->getOperand(2)->getType(), getConcatenatedLength()); + arguments.push_back(len); + + // isAscii flag for UTF8-encoded string literals. + if (encoding == StringLiteralInst::Encoding::UTF8) { + bool ascii = isAscii(); + auto ilType = aiLeft->getOperand(3)->getType(); + auto *asciiLiteral = + builder.createIntegerLiteral(ai->getLoc(), ilType, intmax_t(ascii)); + arguments.push_back(asciiLiteral); + } + + // Type. + arguments.push_back(funcResultType); + + return builder.createApply(ai->getLoc(), friConvertFromBuiltin, + SubstitutionMap(), arguments); +} + +/// Top level entry point +SingleValueInstruction *swift::tryToConcatenateStrings(ApplyInst *ai, + SILBuilder &builder) { + return StringConcatenationOptimizer(ai, builder).optimize(); +} + +//===----------------------------------------------------------------------===// +// Closure Deletion +//===----------------------------------------------------------------------===// + +/// NOTE: Instructions with transitive ownership kind are assumed to not keep +/// the underlying closure alive as well. This is meant for instructions only +/// with non-transitive users. +static bool useDoesNotKeepClosureAlive(const SILInstruction *inst) { + switch (inst->getKind()) { + case SILInstructionKind::StrongRetainInst: + case SILInstructionKind::StrongReleaseInst: + case SILInstructionKind::DestroyValueInst: + case SILInstructionKind::RetainValueInst: + case SILInstructionKind::ReleaseValueInst: + case SILInstructionKind::DebugValueInst: + case SILInstructionKind::EndBorrowInst: + return true; + default: + return false; + } +} + +static bool useHasTransitiveOwnership(const SILInstruction *inst) { + // convert_escape_to_noescape is used to convert to a @noescape function type. + // It does not change ownership of the function value. + if (isa(inst)) + return true; + + // Look through copy_value, begin_borrow. They are inert for our purposes, but + // we need to look through it. + return isa(inst) || isa(inst); +} + +static SILValue createLifetimeExtendedAllocStack( + SILBuilder &builder, SILLocation loc, SILValue arg, + ArrayRef exitingBlocks, InstModCallbacks callbacks) { + AllocStackInst *asi = nullptr; + { + // Save our insert point and create a new alloc_stack in the initial BB and + // dealloc_stack in all exit blocks. + auto *oldInsertPt = &*builder.getInsertionPoint(); + builder.setInsertionPoint(builder.getFunction().begin()->begin()); + asi = builder.createAllocStack(loc, arg->getType()); + callbacks.createdNewInst(asi); + + for (auto *BB : exitingBlocks) { + builder.setInsertionPoint(BB->getTerminator()); + callbacks.createdNewInst(builder.createDeallocStack(loc, asi)); + } + builder.setInsertionPoint(oldInsertPt); + } + assert(asi != nullptr); + + // Then perform a copy_addr [take] [init] right after the partial_apply from + // the original address argument to the new alloc_stack that we have + // created. + callbacks.createdNewInst( + builder.createCopyAddr(loc, arg, asi, IsTake, IsInitialization)); + + // Return the new alloc_stack inst that has the appropriate live range to + // destroy said values. + return asi; +} + +static bool shouldDestroyPartialApplyCapturedArg(SILValue arg, + SILParameterInfo paramInfo, + const SILFunction &F) { + // If we have a non-trivial type and the argument is passed in @inout, we do + // not need to destroy it here. This is something that is implicit in the + // partial_apply design that will be revisited when partial_apply is + // redesigned. + if (paramInfo.isIndirectMutating()) + return false; + + // If we have a trivial type, we do not need to put in any extra releases. + if (arg->getType().isTrivial(F)) + return false; + + // We handle all other cases. + return true; +} + +// *HEY YOU, YES YOU, PLEASE READ*. Even though a textual partial apply is +// printed with the convention of the closed over function upon it, all +// non-inout arguments to a partial_apply are passed at +1. This includes +// arguments that will eventually be passed as guaranteed or in_guaranteed to +// the closed over function. This is because the partial apply is building up a +// boxed aggregate to send off to the closed over function. Of course when you +// call the function, the proper conventions will be used. +void swift::releasePartialApplyCapturedArg(SILBuilder &builder, SILLocation loc, + SILValue arg, + SILParameterInfo paramInfo, + InstModCallbacks callbacks) { + if (!shouldDestroyPartialApplyCapturedArg(arg, paramInfo, + builder.getFunction())) + return; + + // Otherwise, we need to destroy the argument. If we have an address, we + // insert a destroy_addr and return. Any live range issues must have been + // dealt with by our caller. + if (arg->getType().isAddress()) { + // Then emit the destroy_addr for this arg + SILInstruction *newInst = builder.emitDestroyAddrAndFold(loc, arg); + callbacks.createdNewInst(newInst); + return; + } + + // Otherwise, we have an object. We emit the most optimized form of release + // possible for that value. + + // If we have qualified ownership, we should just emit a destroy value. + if (arg->getFunction()->hasOwnership()) { + callbacks.createdNewInst(builder.createDestroyValue(loc, arg)); + return; + } + + if (arg->getType().hasReferenceSemantics()) { + auto u = builder.emitStrongRelease(loc, arg); + if (u.isNull()) + return; + + if (auto *SRI = u.dyn_cast()) { + callbacks.deleteInst(SRI); + return; + } + + callbacks.createdNewInst(u.get()); + return; + } + + auto u = builder.emitReleaseValue(loc, arg); + if (u.isNull()) + return; + + if (auto *rvi = u.dyn_cast()) { + callbacks.deleteInst(rvi); + return; + } + + callbacks.createdNewInst(u.get()); +} + +/// For each captured argument of pai, decrement the ref count of the captured +/// argument as appropriate at each of the post dominated release locations +/// found by tracker. +static bool releaseCapturedArgsOfDeadPartialApply(PartialApplyInst *pai, + ReleaseTracker &tracker, + InstModCallbacks callbacks) { + SILBuilderWithScope builder(pai); + SILLocation loc = pai->getLoc(); + CanSILFunctionType paiTy = + pai->getCallee()->getType().getAs(); + + ArrayRef params = paiTy->getParameters(); + llvm::SmallVector args; + for (SILValue v : pai->getArguments()) { + // If any of our arguments contain open existentials, bail. We do not + // support this for now so that we can avoid having to re-order stack + // locations (a larger change). + if (v->getType().hasOpenedExistential()) + return false; + args.emplace_back(v); + } + unsigned delta = params.size() - args.size(); + assert(delta <= params.size() + && "Error, more args to partial apply than " + "params in its interface."); + params = params.drop_front(delta); + + llvm::SmallVector exitingBlocks; + pai->getFunction()->findExitingBlocks(exitingBlocks); + + // Go through our argument list and create new alloc_stacks for each + // non-trivial address value. This ensures that the memory location that we + // are cleaning up has the same live range as the partial_apply. Otherwise, we + // may be inserting destroy_addr of alloc_stack that have already been passed + // to a dealloc_stack. + for (unsigned i : reversed(indices(args))) { + SILValue arg = args[i]; + SILParameterInfo paramInfo = params[i]; + + // If we are not going to destroy this partial_apply, continue. + if (!shouldDestroyPartialApplyCapturedArg(arg, paramInfo, + builder.getFunction())) + continue; + + // If we have an object, we will not have live range issues, just continue. + if (arg->getType().isObject()) + continue; + + // Now that we know that we have a non-argument address, perform a take-init + // of arg into a lifetime extended alloc_stack + args[i] = createLifetimeExtendedAllocStack(builder, loc, arg, exitingBlocks, + callbacks); + } + + // Emit a destroy for each captured closure argument at each final release + // point. + for (auto *finalRelease : tracker.getFinalReleases()) { + builder.setInsertionPoint(finalRelease); + builder.setCurrentDebugScope(finalRelease->getDebugScope()); + for (unsigned i : indices(args)) { + SILValue arg = args[i]; + SILParameterInfo param = params[i]; + + releasePartialApplyCapturedArg(builder, loc, arg, param, callbacks); + } + } + + return true; +} + +static bool +deadMarkDependenceUser(SILInstruction *inst, + SmallVectorImpl &deleteInsts) { + if (!isa(inst)) + return false; + deleteInsts.push_back(inst); + for (auto *use : cast(inst)->getUses()) { + if (!deadMarkDependenceUser(use->getUser(), deleteInsts)) + return false; + } + return true; +} + +/// TODO: Generalize this to general objects. +bool swift::tryDeleteDeadClosure(SingleValueInstruction *closure, + InstModCallbacks callbacks) { + auto *pa = dyn_cast(closure); + + // We currently only handle locally identified values that do not escape. We + // also assume that the partial apply does not capture any addresses. + if (!pa && !isa(closure)) + return false; + + // A stack allocated partial apply does not have any release users. Delete it + // if the only users are the dealloc_stack and mark_dependence instructions. + if (pa && pa->isOnStack()) { + SmallVector deleteInsts; + for (auto *use : pa->getUses()) { + if (isa(use->getUser()) + || isa(use->getUser())) + deleteInsts.push_back(use->getUser()); + else if (!deadMarkDependenceUser(use->getUser(), deleteInsts)) + return false; + } + for (auto *inst : reverse(deleteInsts)) + callbacks.deleteInst(inst); + callbacks.deleteInst(pa); + + // Note: the lifetime of the captured arguments is managed outside of the + // trivial closure value i.e: there will already be releases for the + // captured arguments. Releasing captured arguments is not necessary. + return true; + } + + // We only accept a user if it is an ARC object that can be removed if the + // object is dead. This should be expanded in the future. This also ensures + // that we are locally identified and non-escaping since we only allow for + // specific ARC users. + ReleaseTracker tracker(useDoesNotKeepClosureAlive, useHasTransitiveOwnership); + + // Find the ARC users and the final retain, release. + if (!getFinalReleasesForValue(SILValue(closure), tracker)) + return false; + + // If we have a partial_apply, release each captured argument at each one of + // the final release locations of the partial apply. + if (auto *pai = dyn_cast(closure)) { + // If we can not decrement the ref counts of the dead partial apply for any + // reason, bail. + if (!releaseCapturedArgsOfDeadPartialApply(pai, tracker, callbacks)) + return false; + } + + // Then delete all user instructions in reverse so that leaf uses are deleted + // first. + for (auto *user : reverse(tracker.getTrackedUsers())) { + assert(user->getResults().empty() + || useHasTransitiveOwnership(user) + && "We expect only ARC operations without " + "results or a cast from escape to noescape without users"); + callbacks.deleteInst(user); + } + + // Finally delete the closure. + callbacks.deleteInst(closure); + + return true; +} + +bool swift::simplifyUsers(SingleValueInstruction *inst) { + bool changed = false; + + for (auto ui = inst->use_begin(), ue = inst->use_end(); ui != ue;) { + SILInstruction *user = ui->getUser(); + ++ui; + + auto svi = dyn_cast(user); + if (!svi) + continue; + + SILValue S = simplifyInstruction(svi); + if (!S) + continue; + + replaceAllSimplifiedUsesAndErase(svi, S); + changed = true; + } + + return changed; +} + +/// True if a type can be expanded without a significant increase to code size. +bool swift::shouldExpand(SILModule &module, SILType ty) { + // FIXME: Expansion + auto expansion = ResilienceExpansion::Minimal; + + if (module.Types.getTypeLowering(ty, expansion).isAddressOnly()) { + return false; + } + if (EnableExpandAll) { + return true; + } + + unsigned numFields = module.Types.countNumberOfFields(ty, expansion); + return (numFields <= 6); +} + +/// Some support functions for the global-opt and let-properties-opts + +// Encapsulate the state used for recursive analysis of a static +// initializer. Discover all the instruction in a use-def graph and return them +// in topological order. +// +// TODO: We should have a DFS utility for this sort of thing so it isn't +// recursive. +class StaticInitializerAnalysis { + SmallVectorImpl &postOrderInstructions; + llvm::SmallDenseSet visited; + int recursionLevel = 0; + +public: + StaticInitializerAnalysis( + SmallVectorImpl &postOrderInstructions) + : postOrderInstructions(postOrderInstructions) {} + + // Perform a recursive DFS on on the use-def graph rooted at `V`. Insert + // values in the `visited` set in preorder. Insert values in + // `postOrderInstructions` in postorder so that the instructions are + // topologically def-use ordered (in execution order). + bool analyze(SILValue rootValue) { + return recursivelyAnalyzeOperand(rootValue); + } + +protected: + bool recursivelyAnalyzeOperand(SILValue v) { + if (!visited.insert(v).second) + return true; + + if (++recursionLevel > 50) + return false; + + // TODO: For multi-result instructions, we could simply insert all result + // values in the visited set here. + auto *inst = dyn_cast(v); + if (!inst) + return false; + + if (!recursivelyAnalyzeInstruction(inst)) + return false; + + postOrderInstructions.push_back(inst); + --recursionLevel; + return true; + } + + bool recursivelyAnalyzeInstruction(SILInstruction *inst) { + if (auto *si = dyn_cast(inst)) { + // If it is not a struct which is a simple type, bail. + if (!si->getType().isTrivial(*si->getFunction())) + return false; + + return llvm::all_of(si->getAllOperands(), [&](Operand &operand) -> bool { + return recursivelyAnalyzeOperand(operand.get()); + }); + } + if (auto *ti = dyn_cast(inst)) { + // If it is not a tuple which is a simple type, bail. + if (!ti->getType().isTrivial(*ti->getFunction())) + return false; + + return llvm::all_of(ti->getAllOperands(), [&](Operand &operand) -> bool { + return recursivelyAnalyzeOperand(operand.get()); + }); + } + if (auto *bi = dyn_cast(inst)) { + switch (bi->getBuiltinInfo().ID) { + case BuiltinValueKind::FPTrunc: + if (auto *li = dyn_cast(bi->getArguments()[0])) { + return recursivelyAnalyzeOperand(li); + } + return false; + default: + return false; + } + } + return isa(inst) || isa(inst) + || isa(inst); + } +}; + +/// Check if the value of v is computed by means of a simple initialization. +/// Populate `forwardInstructions` with references to all the instructions +/// that participate in the use-def graph required to compute `V`. The +/// instructions will be in def-use topological order. +bool swift::analyzeStaticInitializer( + SILValue v, SmallVectorImpl &forwardInstructions) { + return StaticInitializerAnalysis(forwardInstructions).analyze(v); +} + +/// FIXME: This must be kept in sync with replaceLoadSequence() +/// below. What a horrible design. +bool swift::canReplaceLoadSequence(SILInstruction *inst) { + if (auto *cai = dyn_cast(inst)) + return true; + + if (auto *li = dyn_cast(inst)) + return true; + + if (auto *seai = dyn_cast(inst)) { + for (auto seaiUse : seai->getUses()) { + if (!canReplaceLoadSequence(seaiUse->getUser())) + return false; + } + return true; + } + + if (auto *teai = dyn_cast(inst)) { + for (auto teaiUse : teai->getUses()) { + if (!canReplaceLoadSequence(teaiUse->getUser())) + return false; + } + return true; + } + + if (auto *ba = dyn_cast(inst)) { + for (auto use : ba->getUses()) { + if (!canReplaceLoadSequence(use->getUser())) + return false; + } + return true; + } + + // Incidental uses of an address are meaningless with regard to the loaded + // value. + if (isIncidentalUse(inst) || isa(inst)) + return true; + + return false; +} + +/// 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 +/// Move into utils. +/// +/// FIXME: this utility does not make sense as an API. How can the caller +/// guarantee that the only uses of `I` are struct_element_addr and +/// tuple_element_addr? +void swift::replaceLoadSequence(SILInstruction *inst, SILValue value) { + if (auto *cai = dyn_cast(inst)) { + SILBuilder builder(cai); + builder.createStore(cai->getLoc(), value, cai->getDest(), + StoreOwnershipQualifier::Unqualified); + return; + } + + if (auto *li = dyn_cast(inst)) { + li->replaceAllUsesWith(value); + return; + } + + if (auto *seai = dyn_cast(inst)) { + SILBuilder builder(seai); + auto *sei = + builder.createStructExtract(seai->getLoc(), value, seai->getField()); + for (auto seaiUse : seai->getUses()) { + replaceLoadSequence(seaiUse->getUser(), sei); + } + return; + } + + if (auto *teai = dyn_cast(inst)) { + SILBuilder builder(teai); + auto *tei = + builder.createTupleExtract(teai->getLoc(), value, teai->getFieldNo()); + for (auto teaiUse : teai->getUses()) { + replaceLoadSequence(teaiUse->getUser(), tei); + } + return; + } + + if (auto *ba = dyn_cast(inst)) { + for (auto use : ba->getUses()) { + replaceLoadSequence(use->getUser(), value); + } + return; + } + + // Incidental uses of an addres are meaningless with regard to the loaded + // value. + if (isIncidentalUse(inst) || isa(inst)) + return; + + llvm_unreachable("Unknown instruction sequence for reading from a global"); +} + +/// Are the callees that could be called through Decl statically +/// knowable based on the Decl and the compilation mode? +bool swift::calleesAreStaticallyKnowable(SILModule &module, SILDeclRef decl) { + if (decl.isForeign) + return false; + + const DeclContext *assocDC = module.getAssociatedContext(); + if (!assocDC) + return false; + + auto *afd = decl.getAbstractFunctionDecl(); + assert(afd && "Expected abstract function decl!"); + + // Only handle members defined within the SILModule's associated context. + if (!afd->isChildContextOf(assocDC)) + return false; + + if (afd->isDynamic()) { + return false; + } + + if (!afd->hasAccess()) + return false; + + // Only consider 'private' members, unless we are in whole-module compilation. + switch (afd->getEffectiveAccess()) { + case AccessLevel::Open: + return false; + case AccessLevel::Public: + if (isa(afd)) { + // Constructors are special: a derived class in another module can + // "override" a constructor if its class is "open", although the + // constructor itself is not open. + auto *nd = afd->getDeclContext()->getSelfNominalTypeDecl(); + if (nd->getEffectiveAccess() == AccessLevel::Open) + return false; + } + LLVM_FALLTHROUGH; + case AccessLevel::Internal: + return module.isWholeModule(); + case AccessLevel::FilePrivate: + case AccessLevel::Private: + return true; + } + + llvm_unreachable("Unhandled access level in switch."); +} + +Optional +swift::findLocalApplySites(FunctionRefBaseInst *fri) { + SmallVector worklist(fri->use_begin(), fri->use_end()); + + Optional f; + f.emplace(); + + // Optimistically state that we have no escapes before our def-use dataflow. + f->escapes = false; + + while (!worklist.empty()) { + auto *op = worklist.pop_back_val(); + auto *user = op->getUser(); + + // If we have a full apply site as our user. + if (auto apply = FullApplySite::isa(user)) { + if (apply.getCallee() == op->get()) { + f->fullApplySites.push_back(apply); + continue; + } + } + + // If we have a partial apply as a user, start tracking it, but also look at + // its users. + if (auto *pai = dyn_cast(user)) { + if (pai->getCallee() == op->get()) { + // Track the partial apply that we saw so we can potentially eliminate + // dead closure arguments. + f->partialApplySites.push_back(pai); + // Look to see if we can find a full application of this partial apply + // as well. + llvm::copy(pai->getUses(), std::back_inserter(worklist)); + continue; + } + } + + // Otherwise, see if we have any function casts to look through... + switch (user->getKind()) { + case SILInstructionKind::ThinToThickFunctionInst: + case SILInstructionKind::ConvertFunctionInst: + case SILInstructionKind::ConvertEscapeToNoEscapeInst: + llvm::copy(cast(user)->getUses(), + std::back_inserter(worklist)); + continue; + + // A partial_apply [stack] marks its captured arguments with + // mark_dependence. + case SILInstructionKind::MarkDependenceInst: + llvm::copy(cast(user)->getUses(), + std::back_inserter(worklist)); + continue; + + // Look through any reference count instructions since these are not + // escapes: + case SILInstructionKind::CopyValueInst: + llvm::copy(cast(user)->getUses(), + std::back_inserter(worklist)); + continue; + case SILInstructionKind::StrongRetainInst: + case SILInstructionKind::StrongReleaseInst: + case SILInstructionKind::RetainValueInst: + case SILInstructionKind::ReleaseValueInst: + case SILInstructionKind::DestroyValueInst: + // A partial_apply [stack] is deallocated with a dealloc_stack. + case SILInstructionKind::DeallocStackInst: + continue; + default: + break; + } + + // But everything else is considered an escape. + f->escapes = true; + } + + // If we did escape and didn't find any apply sites, then we have no + // information for our users that is interesting. + if (f->escapes && f->partialApplySites.empty() && f->fullApplySites.empty()) + return None; + return f; +} + +/// Insert destroys of captured arguments of partial_apply [stack]. +void swift::insertDestroyOfCapturedArguments( + PartialApplyInst *pai, SILBuilder &builder, + llvm::function_ref shouldInsertDestroy) { + assert(pai->isOnStack()); + + ApplySite site(pai); + SILFunctionConventions calleeConv(site.getSubstCalleeType(), + pai->getModule()); + auto loc = RegularLocation::getAutoGeneratedLocation(); + for (auto &arg : pai->getArgumentOperands()) { + if (!shouldInsertDestroy(arg.get())) + continue; + unsigned calleeArgumentIndex = site.getCalleeArgIndex(arg); + assert(calleeArgumentIndex >= calleeConv.getSILArgIndexOfFirstParam()); + auto paramInfo = calleeConv.getParamInfoForSILArg(calleeArgumentIndex); + releasePartialApplyCapturedArg(builder, loc, arg.get(), paramInfo); + } +} diff --git a/lib/SILOptimizer/Utils/LoadStoreOptUtils.cpp b/lib/SILOptimizer/Utils/LoadStoreOptUtils.cpp index a16be4bc5df..93dcad0c477 100644 --- a/lib/SILOptimizer/Utils/LoadStoreOptUtils.cpp +++ b/lib/SILOptimizer/Utils/LoadStoreOptUtils.cpp @@ -13,7 +13,7 @@ #define DEBUG_TYPE "sil-lsbase" #include "swift/SILOptimizer/Utils/LoadStoreOptUtils.h" #include "swift/SIL/InstructionUtils.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/Utils/Local.cpp b/lib/SILOptimizer/Utils/Local.cpp deleted file mode 100644 index 55852170192..00000000000 --- a/lib/SILOptimizer/Utils/Local.cpp +++ /dev/null @@ -1,1889 +0,0 @@ -//===--- Local.cpp - Functions that perform local SIL transformations. ----===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Analysis/Analysis.h" -#include "swift/SILOptimizer/Analysis/ARCAnalysis.h" -#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" -#include "swift/AST/GenericSignature.h" -#include "swift/AST/SubstitutionMap.h" -#include "swift/SIL/DynamicCasts.h" -#include "swift/SIL/SILArgument.h" -#include "swift/SIL/SILBuilder.h" -#include "swift/SIL/SILModule.h" -#include "swift/SIL/SILUndef.h" -#include "swift/SIL/TypeLowering.h" -#include "swift/SIL/DebugUtils.h" -#include "swift/SIL/InstructionUtils.h" -#include "swift/SIL/BasicBlockUtils.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/IR/Intrinsics.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Compiler.h" -#include - -using namespace swift; - -static llvm::cl::opt EnableExpandAll("enable-expand-all", - llvm::cl::init(false)); - -/// Creates an increment on \p Ptr before insertion point \p InsertPt that -/// creates a strong_retain if \p Ptr has reference semantics itself or a -/// retain_value if \p Ptr is a non-trivial value without reference-semantics. -NullablePtr -swift::createIncrementBefore(SILValue Ptr, SILInstruction *InsertPt) { - // Set up the builder we use to insert at our insertion point. - SILBuilder B(InsertPt); - auto Loc = RegularLocation::getAutoGeneratedLocation(); - - // If we have a trivial type, just bail, there is no work to do. - if (Ptr->getType().isTrivial(B.getFunction())) - return nullptr; - - // If Ptr is refcounted itself, create the strong_retain and - // return. - if (Ptr->getType().isReferenceCounted(B.getModule())) { - if (Ptr->getType().is()) - return B.createUnownedRetain(Loc, Ptr, B.getDefaultAtomicity()); - else - return B.createStrongRetain(Loc, Ptr, B.getDefaultAtomicity()); - } - - // Otherwise, create the retain_value. - return B.createRetainValue(Loc, Ptr, B.getDefaultAtomicity()); -} - -/// Creates a decrement on \p Ptr before insertion point \p InsertPt that -/// creates a strong_release if \p Ptr has reference semantics itself or -/// a release_value if \p Ptr is a non-trivial value without reference-semantics. -NullablePtr -swift::createDecrementBefore(SILValue Ptr, SILInstruction *InsertPt) { - // Setup the builder we will use to insert at our insertion point. - SILBuilder B(InsertPt); - auto Loc = RegularLocation::getAutoGeneratedLocation(); - - if (Ptr->getType().isTrivial(B.getFunction())) - return nullptr; - - // If Ptr has reference semantics itself, create a strong_release. - if (Ptr->getType().isReferenceCounted(B.getModule())) { - if (Ptr->getType().is()) - return B.createUnownedRelease(Loc, Ptr, B.getDefaultAtomicity()); - else - return B.createStrongRelease(Loc, Ptr, B.getDefaultAtomicity()); - } - - // Otherwise create a release value. - return B.createReleaseValue(Loc, Ptr, B.getDefaultAtomicity()); -} - -/// 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) { - // At Onone, consider all uses, including the debug_info. - // This way, debug_info is preserved at Onone. - if (I->hasUsesOfAnyResult() && - I->getFunction()->getEffectiveOptimizationMode() <= - OptimizationMode::NoOptimization) - return false; - - if (!onlyHaveDebugUsesOfAllResults(I) || isa(I)) - return false; - - if (auto *BI = dyn_cast(I)) { - // Although the onFastPath builtin has no side-effects we don't want to - // remove it. - if (BI->getBuiltinInfo().ID == BuiltinValueKind::OnFastPath) - return false; - return !BI->mayHaveSideEffects(); - } - - // condfail instructions that obviously can't fail are dead. - if (auto *CFI = dyn_cast(I)) - if (auto *ILI = dyn_cast(CFI->getOperand())) - if (!ILI->getValue()) - return true; - - // mark_uninitialized is never dead. - if (isa(I)) - return false; - - if (isa(I) || isa(I)) - return false; - - // These invalidate enums so "write" memory, but that is not an essential - // operation so we can remove these if they are trivially dead. - if (isa(I)) - return true; - - if (!I->mayHaveSideEffects()) - return true; - - return false; -} - -/// Return true if this is a release instruction and the released value -/// is a part of a guaranteed parameter. -bool swift::isIntermediateRelease(SILInstruction *I, - EpilogueARCFunctionInfo *EAFI) { - // Check whether this is a release instruction. - if (!isa(I) && !isa(I)) - return false; - - // OK. we have a release instruction. - // Check whether this is a release on part of a guaranteed function argument. - SILValue Op = stripValueProjections(I->getOperand(0)); - auto *Arg = dyn_cast(Op); - if (!Arg) - return false; - - // This is a release on a guaranteed parameter. Its not the final release. - if (Arg->hasConvention(SILArgumentConvention::Direct_Guaranteed)) - return true; - - // This is a release on an owned parameter and its not the epilogue release. - // Its not the final release. - auto Rel = EAFI->computeEpilogueARCInstructions( - EpilogueARCContext::EpilogueARCKind::Release, Arg); - if (Rel.size() && !Rel.count(I)) - return true; - - // Failed to prove anything. - return false; -} - -namespace { - using CallbackTy = llvm::function_ref; -} // end anonymous namespace - -void swift::recursivelyDeleteTriviallyDeadInstructions( - ArrayRef IA, bool Force, CallbackTy Callback) { - // Delete these instruction and others that become dead after it's deleted. - llvm::SmallPtrSet DeadInsts; - for (auto I : IA) { - // If the instruction is not dead and force is false, do nothing. - if (Force || isInstructionTriviallyDead(I)) - DeadInsts.insert(I); - } - llvm::SmallPtrSet NextInsts; - while (!DeadInsts.empty()) { - for (auto I : DeadInsts) { - // Call the callback before we mutate the to be deleted instruction in any - // way. - Callback(I); - - // Check if any of the operands will become dead as well. - MutableArrayRef 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 (auto *OpValInst = OpVal->getDefiningInstruction()) - if (!DeadInsts.count(OpValInst) && - isInstructionTriviallyDead(OpValInst)) - NextInsts.insert(OpValInst); - } - - // If we have a function ref inst, we need to especially drop its function - // argument so that it gets a proper ref decrement. - auto *FRI = dyn_cast(I); - if (FRI && FRI->getInitiallyReferencedFunction()) - FRI->dropReferencedFunction(); - - auto *DFRI = dyn_cast(I); - if (DFRI && DFRI->getInitiallyReferencedFunction()) - DFRI->dropReferencedFunction(); - - auto *PFRI = dyn_cast(I); - if (PFRI && PFRI->getInitiallyReferencedFunction()) - PFRI->dropReferencedFunction(); - } - - for (auto I : DeadInsts) { - // This will remove this instruction and all its uses. - eraseFromParentWithDebugInsts(I, Callback); - } - - NextInsts.swap(DeadInsts); - NextInsts.clear(); - } -} - -/// 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. -void swift::recursivelyDeleteTriviallyDeadInstructions(SILInstruction *I, - bool Force, - CallbackTy Callback) { - ArrayRef AI = ArrayRef(I); - recursivelyDeleteTriviallyDeadInstructions(AI, Force, Callback); -} - -void swift::eraseUsesOfInstruction(SILInstruction *Inst, - CallbackTy Callback) { - for (auto result : Inst->getResults()) { - while (!result->use_empty()) { - auto UI = result->use_begin(); - auto *User = UI->getUser(); - assert(User && "User should never be NULL!"); - - // If the instruction itself has any uses, recursively zap them so that - // nothing uses this instruction. - eraseUsesOfInstruction(User, Callback); - - // 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 = Op.get()->getDefiningInstruction()) { - // Don't recursively delete the instruction we're working on. - // FIXME: what if we're being recursively invoked? - if (OpI != Inst) { - Op.drop(); - recursivelyDeleteTriviallyDeadInstructions(OpI, false, Callback); - } - } - } - Callback(User); - User->eraseFromParent(); - } - } -} - -void swift:: -collectUsesOfValue(SILValue V, llvm::SmallPtrSetImpl &Insts) { - for (auto UI = V->use_begin(), E = V->use_end(); UI != E; UI++) { - auto *User = UI->getUser(); - // Instruction has been processed. - if (!Insts.insert(User).second) - continue; - - // Collect the users of this instruction. - for (auto result : User->getResults()) - collectUsesOfValue(result, Insts); - } -} - -void swift::eraseUsesOfValue(SILValue V) { - llvm::SmallPtrSet Insts; - // Collect the uses. - collectUsesOfValue(V, Insts); - // Erase the uses, we can have instructions that become dead because - // of the removal of these instructions, leave to DCE to cleanup. - // Its not safe to do recursively delete here as some of the SILInstruction - // maybe tracked by this set. - for (auto I : Insts) { - I->replaceAllUsesOfAllResultsWithUndef(); - I->eraseFromParent(); - } -} - -// Devirtualization of functions with covariant return types produces -// a result that is not an apply, but takes an apply as an -// argument. Attempt to dig the apply out from this result. -FullApplySite swift::findApplyFromDevirtualizedResult(SILValue V) { - if (auto Apply = FullApplySite::isa(V)) - return Apply; - - if (isa(V) || isa(V) || isa(V)) - return findApplyFromDevirtualizedResult( - cast(V)->getOperand(0)); - - return FullApplySite(); -} - -bool swift::mayBindDynamicSelf(SILFunction *F) { - if (!F->hasSelfMetadataParam()) - return false; - - SILValue MDArg = F->getSelfMetadataArgument(); - - for (Operand *MDUse : F->getSelfMetadataArgument()->getUses()) { - SILInstruction *MDUser = MDUse->getUser(); - for (Operand &TypeDepOp : MDUser->getTypeDependentOperands()) { - if (TypeDepOp.get() == MDArg) - return true; - } - } - return false; -} - -static SILValue skipAddrProjections(SILValue V) { - for (;;) { - switch (V->getKind()) { - case ValueKind::IndexAddrInst: - case ValueKind::IndexRawPointerInst: - case ValueKind::StructElementAddrInst: - case ValueKind::TupleElementAddrInst: - V = cast(V)->getOperand(0); - break; - default: - return V; - } - } - llvm_unreachable("there is no escape from an infinite loop"); -} - -/// Check whether the \p addr is an address of a tail-allocated array element. -bool swift::isAddressOfArrayElement(SILValue addr) { - addr = stripAddressProjections(addr); - if (auto *MD = dyn_cast(addr)) - addr = stripAddressProjections(MD->getValue()); - - // High-level SIL: check for an get_element_address array semantics call. - if (auto *PtrToAddr = dyn_cast(addr)) - if (auto *SEI = dyn_cast(PtrToAddr->getOperand())) { - ArraySemanticsCall Call(SEI->getOperand()); - if (Call && Call.getKind() == ArrayCallKind::kGetElementAddress) - return true; - } - - // Check for an tail-address (of an array buffer object). - if (isa(skipAddrProjections(addr))) - return true; - - return false; -} - -/// Find a new position for an ApplyInst's FuncRef so that it dominates its -/// use. Not that FunctionRefInsts may be shared by multiple ApplyInsts. -void swift::placeFuncRef(ApplyInst *AI, DominanceInfo *DT) { - FunctionRefInst *FuncRef = cast(AI->getCallee()); - SILBasicBlock *DomBB = - DT->findNearestCommonDominator(AI->getParent(), FuncRef->getParent()); - if (DomBB == AI->getParent() && DomBB != FuncRef->getParent()) - // Prefer to place the FuncRef immediately before the call. Since we're - // moving FuncRef up, this must be the only call to it in the block. - FuncRef->moveBefore(AI); - else - // Otherwise, conservatively stick it at the beginning of the block. - FuncRef->moveBefore(&*DomBB->begin()); -} - -/// 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 *swift::addArgumentToBranch(SILValue Val, SILBasicBlock *Dest, - TermInst *Branch) { - SILBuilderWithScope Builder(Branch); - - if (auto *CBI = dyn_cast(Branch)) { - SmallVector TrueArgs; - SmallVector FalseArgs; - - for (auto A : CBI->getTrueArgs()) - TrueArgs.push_back(A); - - for (auto A : CBI->getFalseArgs()) - FalseArgs.push_back(A); - - if (Dest == CBI->getTrueBB()) { - TrueArgs.push_back(Val); - assert(TrueArgs.size() == Dest->getNumArguments()); - } else { - FalseArgs.push_back(Val); - assert(FalseArgs.size() == Dest->getNumArguments()); - } - - return Builder.createCondBranch(CBI->getLoc(), CBI->getCondition(), CBI->getTrueBB(), TrueArgs, CBI->getFalseBB(), FalseArgs, CBI->getTrueBBCount(), CBI->getFalseBBCount()); - } - - if (auto *BI = dyn_cast(Branch)) { - SmallVector Args; - - for (auto A : BI->getArgs()) - Args.push_back(A); - - Args.push_back(Val); - assert(Args.size() == Dest->getNumArguments()); - return Builder.createBranch(BI->getLoc(), BI->getDestBB(), Args); - } - - llvm_unreachable("unsupported terminator"); -} - -SILLinkage swift::getSpecializedLinkage(SILFunction *F, SILLinkage L) { - if (hasPrivateVisibility(L) && - !F->isSerialized()) { - // Specializations of private symbols should remain so, unless - // they were serialized, which can only happen when specializing - // definitions from a standard library built with -sil-serialize-all. - return SILLinkage::Private; - } - - return SILLinkage::Shared; -} - -/// Remove all instructions in the body of \p BB in safe manner by using -/// undef. -void swift::clearBlockBody(SILBasicBlock *BB) { - // Instructions in the dead block may be used by other dead blocks. Replace - // any uses of them with undef values. - while (!BB->empty()) { - // Grab the last instruction in the BB. - auto *Inst = &BB->back(); - - // Replace any still-remaining uses with undef values and erase. - Inst->replaceAllUsesOfAllResultsWithUndef(); - Inst->eraseFromParent(); - } -} - -// Handle the mechanical aspects of removing an unreachable block. -void swift::removeDeadBlock(SILBasicBlock *BB) { - // Clear the body of BB. - clearBlockBody(BB); - - // Now that the BB is empty, eliminate it. - BB->eraseFromParent(); -} - -/// 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. -/// -/// If CheckOnly flag is set, then this function only checks if the -/// required casting is possible. If it is not possible, then None -/// is returned. -/// -/// If CheckOnly is not set, then a casting code is generated and the final -/// casted value is returned. -/// -/// NOTE: We intentionally combine the checking of the cast's handling possibility -/// and the transformation performing the cast in the same function, to avoid -/// any divergence between the check and the implementation in the future. -/// -/// NOTE: The implementation of this function is very closely related to the -/// rules checked by SILVerifier::requireABICompatibleFunctionTypes. -SILValue swift::castValueToABICompatibleType(SILBuilder *B, SILLocation Loc, - SILValue Value, - SILType SrcTy, SILType DestTy) { - - // No cast is required if types are the same. - if (SrcTy == DestTy) - return Value; - - assert(SrcTy.isAddress() == DestTy.isAddress() && - "Addresses aren't compatible with values"); - - if (SrcTy.isAddress() && DestTy.isAddress()) { - // Cast between two addresses and that's it. - return B->createUncheckedAddrCast(Loc, Value, DestTy); - } - - // If both types are classes and dest is the superclass of src, - // simply perform an upcast. - if (DestTy.isExactSuperclassOf(SrcTy)) { - return B->createUpcast(Loc, Value, DestTy); - } - - if (SrcTy.isHeapObjectReferenceType() && - DestTy.isHeapObjectReferenceType()) { - return B->createUncheckedRefCast(Loc, Value, DestTy); - } - - if (auto mt1 = SrcTy.getAs()) { - if (auto mt2 = DestTy.getAs()) { - if (mt1->getRepresentation() == mt2->getRepresentation()) { - // If B.Type needs to be casted to A.Type and - // A is a superclass of B, then it can be done by means - // of a simple upcast. - if (mt2.getInstanceType()->isExactSuperclassOf( - mt1.getInstanceType())) { - return B->createUpcast(Loc, Value, DestTy); - } - - // Cast between two metatypes and that's it. - return B->createUncheckedBitCast(Loc, Value, DestTy); - } - } - } - - // Check if src and dest types are optional. - auto OptionalSrcTy = SrcTy.getOptionalObjectType(); - auto OptionalDestTy = DestTy.getOptionalObjectType(); - - // Both types are optional. - if (OptionalDestTy && OptionalSrcTy) { - // If both wrapped types are classes and dest is the superclass of src, - // simply perform an upcast. - if (OptionalDestTy.isExactSuperclassOf(OptionalSrcTy)) { - // Insert upcast. - return B->createUpcast(Loc, Value, DestTy); - } - - // Unwrap the original optional value. - auto *SomeDecl = B->getASTContext().getOptionalSomeDecl(); - auto *NoneBB = B->getFunction().createBasicBlock(); - auto *SomeBB = B->getFunction().createBasicBlock(); - auto *CurBB = B->getInsertionPoint()->getParent(); - - auto *ContBB = CurBB->split(B->getInsertionPoint()); - ContBB->createPhiArgument(DestTy, ValueOwnershipKind::Owned); - - SmallVector, 1> CaseBBs; - CaseBBs.push_back(std::make_pair(SomeDecl, SomeBB)); - B->setInsertionPoint(CurBB); - B->createSwitchEnum(Loc, Value, NoneBB, CaseBBs); - - // Handle the Some case. - B->setInsertionPoint(SomeBB); - SILValue UnwrappedValue = B->createUncheckedEnumData(Loc, Value, - SomeDecl); - // Cast the unwrapped value. - auto CastedUnwrappedValue = - castValueToABICompatibleType(B, Loc, UnwrappedValue, - OptionalSrcTy, - OptionalDestTy); - // Wrap into optional. - auto CastedValue = B->createOptionalSome(Loc, CastedUnwrappedValue, DestTy); - B->createBranch(Loc, ContBB, {CastedValue}); - - // Handle the None case. - B->setInsertionPoint(NoneBB); - CastedValue = B->createOptionalNone(Loc, DestTy); - B->createBranch(Loc, ContBB, {CastedValue}); - B->setInsertionPoint(ContBB->begin()); - - return ContBB->getArgument(0); - } - - // Src is not optional, but dest is optional. - if (!OptionalSrcTy && OptionalDestTy) { - auto OptionalSrcCanTy = OptionalType::get(SrcTy.getASTType()) - ->getCanonicalType(); - auto LoweredOptionalSrcType = SILType::getPrimitiveObjectType( - OptionalSrcCanTy); - - // Wrap the source value into an optional first. - SILValue WrappedValue = B->createOptionalSome(Loc, Value, - LoweredOptionalSrcType); - // Cast the wrapped value. - return castValueToABICompatibleType(B, Loc, WrappedValue, - WrappedValue->getType(), - DestTy); - } - - // Handle tuple types. - // Extract elements, cast each of them, create a new tuple. - if (auto SrcTupleTy = SrcTy.getAs()) { - SmallVector ExpectedTuple; - for (unsigned i = 0, e = SrcTupleTy->getNumElements(); i < e; i++) { - SILValue Element = B->createTupleExtract(Loc, Value, i); - // Cast the value if necessary. - Element = castValueToABICompatibleType(B, Loc, Element, - SrcTy.getTupleElementType(i), - DestTy.getTupleElementType(i)); - ExpectedTuple.push_back(Element); - } - - return B->createTuple(Loc, DestTy, ExpectedTuple); - } - - // Function types are interchangeable if they're also ABI-compatible. - if (SrcTy.is()) { - if (DestTy.is()) { - assert(SrcTy.getAs()->isNoEscape() == - DestTy.getAs()->isNoEscape() || - SrcTy.getAs()->getRepresentation() != - SILFunctionType::Representation::Thick && - "Swift thick functions that differ in escapeness are not ABI " - "compatible"); - // Insert convert_function. - return B->createConvertFunction(Loc, Value, DestTy, - /*WithoutActuallyEscaping=*/false); - } - } - - llvm::errs() << "Source type: " << SrcTy << "\n"; - llvm::errs() << "Destination type: " << DestTy << "\n"; - llvm_unreachable("Unknown combination of types for casting"); -} - -ProjectBoxInst *swift::getOrCreateProjectBox(AllocBoxInst *ABI, unsigned Index){ - SILBasicBlock::iterator Iter(ABI); - Iter++; - assert(Iter != ABI->getParent()->end() && - "alloc_box cannot be the last instruction of a block"); - SILInstruction *NextInst = &*Iter; - if (auto *PBI = dyn_cast(NextInst)) { - if (PBI->getOperand() == ABI && PBI->getFieldIndex() == Index) - return PBI; - } - - SILBuilder B(NextInst); - return B.createProjectBox(ABI->getLoc(), ABI, Index); -} - -// Peek through trivial Enum initialization, typically for pointless -// Optionals. -// -// Given an UncheckedTakeEnumDataAddrInst, check that there are no -// other uses of the Enum value and return the address used to initialized the -// enum's payload: -// -// %stack_adr = alloc_stack -// %data_adr = init_enum_data_addr %stk_adr -// %enum_adr = inject_enum_addr %stack_adr -// %copy_src = unchecked_take_enum_data_addr %enum_adr -// dealloc_stack %stack_adr -// (No other uses of %stack_adr.) -InitEnumDataAddrInst * -swift::findInitAddressForTrivialEnum(UncheckedTakeEnumDataAddrInst *UTEDAI) { - auto *ASI = dyn_cast(UTEDAI->getOperand()); - if (!ASI) - return nullptr; - - SILInstruction *singleUser = nullptr; - for (auto use : ASI->getUses()) { - auto *user = use->getUser(); - if (user == UTEDAI) - continue; - - // As long as there's only one UncheckedTakeEnumDataAddrInst and one - // InitEnumDataAddrInst, we don't care how many InjectEnumAddr and - // DeallocStack users there are. - if (isa(user) || isa(user)) - continue; - - if (singleUser) - return nullptr; - - singleUser = user; - } - if (!singleUser) - return nullptr; - - // Assume, without checking, that the returned InitEnumDataAddr dominates the - // given UncheckedTakeEnumDataAddrInst, because that's how SIL is defined. I - // don't know where this is actually verified. - return dyn_cast(singleUser); -} - -//===----------------------------------------------------------------------===// -// String Concatenation Optimizer -//===----------------------------------------------------------------------===// - -namespace { -/// This is a helper class that performs optimization of string literals -/// concatenation. -class StringConcatenationOptimizer { - /// Apply instruction being optimized. - ApplyInst *AI; - /// Builder to be used for creation of new instructions. - SILBuilder &Builder; - /// Left string literal operand of a string concatenation. - StringLiteralInst *SLILeft = nullptr; - /// Right string literal operand of a string concatenation. - StringLiteralInst *SLIRight = nullptr; - /// Function used to construct the left string literal. - FunctionRefInst *FRILeft = nullptr; - /// Function used to construct the right string literal. - FunctionRefInst *FRIRight = nullptr; - /// Apply instructions used to construct left string literal. - ApplyInst *AILeft = nullptr; - /// Apply instructions used to construct right string literal. - ApplyInst *AIRight = nullptr; - /// String literal conversion function to be used. - FunctionRefInst *FRIConvertFromBuiltin = nullptr; - /// Result type of a function producing the concatenated string literal. - SILValue FuncResultType; - - /// Internal helper methods - bool extractStringConcatOperands(); - void adjustEncodings(); - APInt getConcatenatedLength(); - bool isAscii() const; - -public: - StringConcatenationOptimizer(ApplyInst *AI, SILBuilder &Builder) - : AI(AI), Builder(Builder) {} - - /// Tries to optimize a given apply instruction if it is a - /// concatenation of string literals. - /// - /// Returns a new instruction if optimization was possible. - SingleValueInstruction *optimize(); -}; - -} // end anonymous namespace - -/// Checks operands of a string concatenation operation to see if -/// optimization is applicable. -/// -/// Returns false if optimization is not possible. -/// Returns true and initializes internal fields if optimization is possible. -bool StringConcatenationOptimizer::extractStringConcatOperands() { - auto *Fn = AI->getReferencedFunctionOrNull(); - if (!Fn) - return false; - - if (AI->getNumArguments() != 3 || !Fn->hasSemanticsAttr("string.concat")) - return false; - - // Left and right operands of a string concatenation operation. - AILeft = dyn_cast(AI->getOperand(1)); - AIRight = dyn_cast(AI->getOperand(2)); - - if (!AILeft || !AIRight) - return false; - - FRILeft = dyn_cast(AILeft->getCallee()); - FRIRight = dyn_cast(AIRight->getCallee()); - - if (!FRILeft || !FRIRight) - return false; - - auto *FRILeftFun = FRILeft->getReferencedFunctionOrNull(); - auto *FRIRightFun = FRIRight->getReferencedFunctionOrNull(); - - if (FRILeftFun->getEffectsKind() >= EffectsKind::ReleaseNone || - FRIRightFun->getEffectsKind() >= EffectsKind::ReleaseNone) - return false; - - if (!FRILeftFun->hasSemanticsAttrs() || !FRIRightFun->hasSemanticsAttrs()) - return false; - - auto AILeftOperandsNum = AILeft->getNumOperands(); - auto AIRightOperandsNum = AIRight->getNumOperands(); - - // makeUTF8 should have following parameters: - // (start: RawPointer, utf8CodeUnitCount: Word, isASCII: Int1) - if (!((FRILeftFun->hasSemanticsAttr("string.makeUTF8") && - AILeftOperandsNum == 5) || - (FRIRightFun->hasSemanticsAttr("string.makeUTF8") && - AIRightOperandsNum == 5))) - return false; - - SLILeft = dyn_cast(AILeft->getOperand(1)); - SLIRight = dyn_cast(AIRight->getOperand(1)); - - if (!SLILeft || !SLIRight) - return false; - - // Only UTF-8 and UTF-16 encoded string literals are supported by this - // optimization. - if (SLILeft->getEncoding() != StringLiteralInst::Encoding::UTF8 && - SLILeft->getEncoding() != StringLiteralInst::Encoding::UTF16) - return false; - - if (SLIRight->getEncoding() != StringLiteralInst::Encoding::UTF8 && - SLIRight->getEncoding() != StringLiteralInst::Encoding::UTF16) - return false; - - return true; -} - -/// Ensures that both string literals to be concatenated use the same -/// UTF encoding. Converts UTF-8 into UTF-16 if required. -void StringConcatenationOptimizer::adjustEncodings() { - if (SLILeft->getEncoding() == SLIRight->getEncoding()) { - FRIConvertFromBuiltin = FRILeft; - if (SLILeft->getEncoding() == StringLiteralInst::Encoding::UTF8) { - FuncResultType = AILeft->getOperand(4); - } else { - FuncResultType = AILeft->getOperand(3); - } - return; - } - - Builder.setCurrentDebugScope(AI->getDebugScope()); - - // If one of the string literals is UTF8 and another one is UTF16, - // convert the UTF8-encoded string literal into UTF16-encoding first. - if (SLILeft->getEncoding() == StringLiteralInst::Encoding::UTF8 && - SLIRight->getEncoding() == StringLiteralInst::Encoding::UTF16) { - FuncResultType = AIRight->getOperand(3); - FRIConvertFromBuiltin = FRIRight; - // Convert UTF8 representation into UTF16. - SLILeft = Builder.createStringLiteral(AI->getLoc(), SLILeft->getValue(), - StringLiteralInst::Encoding::UTF16); - } - - if (SLIRight->getEncoding() == StringLiteralInst::Encoding::UTF8 && - SLILeft->getEncoding() == StringLiteralInst::Encoding::UTF16) { - FuncResultType = AILeft->getOperand(3); - FRIConvertFromBuiltin = FRILeft; - // Convert UTF8 representation into UTF16. - SLIRight = Builder.createStringLiteral(AI->getLoc(), SLIRight->getValue(), - StringLiteralInst::Encoding::UTF16); - } - - // It should be impossible to have two operands with different - // encodings at this point. - assert(SLILeft->getEncoding() == SLIRight->getEncoding() && - "Both operands of string concatenation should have the same encoding"); -} - -/// Computes the length of a concatenated string literal. -APInt StringConcatenationOptimizer::getConcatenatedLength() { - // Real length of string literals computed based on its contents. - // Length is in code units. - auto SLILenLeft = SLILeft->getCodeUnitCount(); - (void) SLILenLeft; - auto SLILenRight = SLIRight->getCodeUnitCount(); - (void) SLILenRight; - - // Length of string literals as reported by string.make functions. - auto *LenLeft = dyn_cast(AILeft->getOperand(2)); - auto *LenRight = dyn_cast(AIRight->getOperand(2)); - - // Real and reported length should be the same. - assert(SLILenLeft == LenLeft->getValue() && - "Size of string literal in @_semantics(string.make) is wrong"); - - assert(SLILenRight == LenRight->getValue() && - "Size of string literal in @_semantics(string.make) is wrong"); - - - // Compute length of the concatenated literal. - return LenLeft->getValue() + LenRight->getValue(); -} - -/// Computes the isAscii flag of a concatenated UTF8-encoded string literal. -bool StringConcatenationOptimizer::isAscii() const{ - // Add the isASCII argument in case of UTF8. - // IsASCII is true only if IsASCII of both literals is true. - auto *AsciiLeft = dyn_cast(AILeft->getOperand(3)); - auto *AsciiRight = dyn_cast(AIRight->getOperand(3)); - auto IsAsciiLeft = AsciiLeft->getValue() == 1; - auto IsAsciiRight = AsciiRight->getValue() == 1; - return IsAsciiLeft && IsAsciiRight; -} - -SingleValueInstruction *StringConcatenationOptimizer::optimize() { - // Bail out if string literals concatenation optimization is - // not possible. - if (!extractStringConcatOperands()) - return nullptr; - - // Perform string literal encodings adjustments if needed. - adjustEncodings(); - - // Arguments of the new StringLiteralInst to be created. - SmallVector Arguments; - - // Encoding to be used for the concatenated string literal. - auto Encoding = SLILeft->getEncoding(); - - // Create a concatenated string literal. - Builder.setCurrentDebugScope(AI->getDebugScope()); - auto LV = SLILeft->getValue(); - auto RV = SLIRight->getValue(); - auto *NewSLI = - Builder.createStringLiteral(AI->getLoc(), LV + Twine(RV), Encoding); - Arguments.push_back(NewSLI); - - // Length of the concatenated literal according to its encoding. - auto *Len = Builder.createIntegerLiteral( - AI->getLoc(), AILeft->getOperand(2)->getType(), getConcatenatedLength()); - Arguments.push_back(Len); - - // isAscii flag for UTF8-encoded string literals. - if (Encoding == StringLiteralInst::Encoding::UTF8) { - bool IsAscii = isAscii(); - auto ILType = AILeft->getOperand(3)->getType(); - auto *Ascii = - Builder.createIntegerLiteral(AI->getLoc(), ILType, intmax_t(IsAscii)); - Arguments.push_back(Ascii); - } - - // Type. - Arguments.push_back(FuncResultType); - - return Builder.createApply(AI->getLoc(), FRIConvertFromBuiltin, - SubstitutionMap(), Arguments); -} - -/// Top level entry point -SingleValueInstruction * -swift::tryToConcatenateStrings(ApplyInst *AI, SILBuilder &B) { - return StringConcatenationOptimizer(AI, B).optimize(); -} - -//===----------------------------------------------------------------------===// -// Closure Deletion -//===----------------------------------------------------------------------===// - -/// NOTE: Instructions with transitive ownership kind are assumed to not keep -/// the underlying closure alive as well. This is meant for instructions only -/// with non-transitive users. -static bool useDoesNotKeepClosureAlive(const SILInstruction *I) { - switch (I->getKind()) { - case SILInstructionKind::StrongRetainInst: - case SILInstructionKind::StrongReleaseInst: - case SILInstructionKind::DestroyValueInst: - case SILInstructionKind::RetainValueInst: - case SILInstructionKind::ReleaseValueInst: - case SILInstructionKind::DebugValueInst: - case SILInstructionKind::EndBorrowInst: - return true; - default: - return false; - } -} - -static bool useHasTransitiveOwnership(const SILInstruction *I) { - // convert_escape_to_noescape is used to convert to a @noescape function type. - // It does not change ownership of the function value. - if (isa(I)) - return true; - - // Look through copy_value, begin_borrow. They are inert for our purposes, but - // we need to look through it. - return isa(I) || isa(I); -} - -static SILValue createLifetimeExtendedAllocStack( - SILBuilder &Builder, SILLocation Loc, SILValue Arg, - ArrayRef ExitingBlocks, InstModCallbacks Callbacks) { - AllocStackInst *ASI = nullptr; - { - // Save our insert point and create a new alloc_stack in the initial BB and - // dealloc_stack in all exit blocks. - auto *OldInsertPt = &*Builder.getInsertionPoint(); - Builder.setInsertionPoint(Builder.getFunction().begin()->begin()); - ASI = Builder.createAllocStack(Loc, Arg->getType()); - Callbacks.CreatedNewInst(ASI); - - for (auto *BB : ExitingBlocks) { - Builder.setInsertionPoint(BB->getTerminator()); - Callbacks.CreatedNewInst(Builder.createDeallocStack(Loc, ASI)); - } - Builder.setInsertionPoint(OldInsertPt); - } - assert(ASI != nullptr); - - // Then perform a copy_addr [take] [init] right after the partial_apply from - // the original address argument to the new alloc_stack that we have - // created. - Callbacks.CreatedNewInst( - Builder.createCopyAddr(Loc, Arg, ASI, IsTake, IsInitialization)); - - // Return the new alloc_stack inst that has the appropriate live range to - // destroy said values. - return ASI; -} - -static bool shouldDestroyPartialApplyCapturedArg(SILValue Arg, - SILParameterInfo PInfo, - const SILFunction &F) { - // If we have a non-trivial type and the argument is passed in @inout, we do - // not need to destroy it here. This is something that is implicit in the - // partial_apply design that will be revisited when partial_apply is - // redesigned. - if (PInfo.isIndirectMutating()) - return false; - - // If we have a trivial type, we do not need to put in any extra releases. - if (Arg->getType().isTrivial(F)) - return false; - - // We handle all other cases. - return true; -} - -// *HEY YOU, YES YOU, PLEASE READ*. Even though a textual partial apply is -// printed with the convention of the closed over function upon it, all -// non-inout arguments to a partial_apply are passed at +1. This includes -// arguments that will eventually be passed as guaranteed or in_guaranteed to -// the closed over function. This is because the partial apply is building up a -// boxed aggregate to send off to the closed over function. Of course when you -// call the function, the proper conventions will be used. -void swift::releasePartialApplyCapturedArg(SILBuilder &Builder, SILLocation Loc, - SILValue Arg, SILParameterInfo PInfo, - InstModCallbacks Callbacks) { - if (!shouldDestroyPartialApplyCapturedArg(Arg, PInfo, Builder.getFunction())) - return; - - // Otherwise, we need to destroy the argument. If we have an address, we - // insert a destroy_addr and return. Any live range issues must have been - // dealt with by our caller. - if (Arg->getType().isAddress()) { - // Then emit the destroy_addr for this arg - SILInstruction *NewInst = Builder.emitDestroyAddrAndFold(Loc, Arg); - Callbacks.CreatedNewInst(NewInst); - return; - } - - // Otherwise, we have an object. We emit the most optimized form of release - // possible for that value. - - // If we have qualified ownership, we should just emit a destroy value. - if (Arg->getFunction()->hasOwnership()) { - Callbacks.CreatedNewInst(Builder.createDestroyValue(Loc, Arg)); - return; - } - - if (Arg->getType().hasReferenceSemantics()) { - auto U = Builder.emitStrongRelease(Loc, Arg); - if (U.isNull()) - return; - - if (auto *SRI = U.dyn_cast()) { - Callbacks.DeleteInst(SRI); - return; - } - - Callbacks.CreatedNewInst(U.get()); - return; - } - - auto U = Builder.emitReleaseValue(Loc, Arg); - if (U.isNull()) - return; - - if (auto *RVI = U.dyn_cast()) { - Callbacks.DeleteInst(RVI); - return; - } - - Callbacks.CreatedNewInst(U.get()); -} - -/// For each captured argument of PAI, decrement the ref count of the captured -/// argument as appropriate at each of the post dominated release locations -/// found by Tracker. -static bool releaseCapturedArgsOfDeadPartialApply(PartialApplyInst *PAI, - ReleaseTracker &Tracker, - InstModCallbacks Callbacks) { - SILBuilderWithScope Builder(PAI); - SILLocation Loc = PAI->getLoc(); - CanSILFunctionType PAITy = - PAI->getCallee()->getType().getAs(); - - ArrayRef Params = PAITy->getParameters(); - llvm::SmallVector Args; - for (SILValue v : PAI->getArguments()) { - // If any of our arguments contain open existentials, bail. We do not - // support this for now so that we can avoid having to re-order stack - // locations (a larger change). - if (v->getType().hasOpenedExistential()) - return false; - Args.emplace_back(v); - } - unsigned Delta = Params.size() - Args.size(); - assert(Delta <= Params.size() && "Error, more Args to partial apply than " - "params in its interface."); - Params = Params.drop_front(Delta); - - llvm::SmallVector ExitingBlocks; - PAI->getFunction()->findExitingBlocks(ExitingBlocks); - - // Go through our argument list and create new alloc_stacks for each - // non-trivial address value. This ensures that the memory location that we - // are cleaning up has the same live range as the partial_apply. Otherwise, we - // may be inserting destroy_addr of alloc_stack that have already been passed - // to a dealloc_stack. - for (unsigned i : reversed(indices(Args))) { - SILValue Arg = Args[i]; - SILParameterInfo PInfo = Params[i]; - - // If we are not going to destroy this partial_apply, continue. - if (!shouldDestroyPartialApplyCapturedArg(Arg, PInfo, Builder.getFunction())) - continue; - - // If we have an object, we will not have live range issues, just continue. - if (Arg->getType().isObject()) - continue; - - // Now that we know that we have a non-argument address, perform a take-init - // of Arg into a lifetime extended alloc_stack - Args[i] = createLifetimeExtendedAllocStack(Builder, Loc, Arg, ExitingBlocks, - Callbacks); - } - - // Emit a destroy for each captured closure argument at each final release - // point. - for (auto *FinalRelease : Tracker.getFinalReleases()) { - Builder.setInsertionPoint(FinalRelease); - Builder.setCurrentDebugScope(FinalRelease->getDebugScope()); - for (unsigned i : indices(Args)) { - SILValue Arg = Args[i]; - SILParameterInfo Param = Params[i]; - - releasePartialApplyCapturedArg(Builder, Loc, Arg, Param, Callbacks); - } - } - - return true; -} - -static bool -deadMarkDependenceUser(SILInstruction *Inst, - SmallVectorImpl &DeleteInsts) { - if (!isa(Inst)) - return false; - DeleteInsts.push_back(Inst); - for (auto *Use : cast(Inst)->getUses()) { - if (!deadMarkDependenceUser(Use->getUser(), DeleteInsts)) - return false; - } - return true; -} - -/// TODO: Generalize this to general objects. -bool swift::tryDeleteDeadClosure(SingleValueInstruction *Closure, - InstModCallbacks Callbacks) { - auto *PA = dyn_cast(Closure); - - // We currently only handle locally identified values that do not escape. We - // also assume that the partial apply does not capture any addresses. - if (!PA && !isa(Closure)) - return false; - - // A stack allocated partial apply does not have any release users. Delete it - // if the only users are the dealloc_stack and mark_dependence instructions. - if (PA && PA->isOnStack()) { - SmallVector DeleteInsts; - for (auto *Use : PA->getUses()) { - if (isa(Use->getUser()) || - isa(Use->getUser())) - DeleteInsts.push_back(Use->getUser()); - else if (!deadMarkDependenceUser(Use->getUser(), DeleteInsts)) - return false; - } - for (auto *Inst : reverse(DeleteInsts)) - Callbacks.DeleteInst(Inst); - Callbacks.DeleteInst(PA); - - // Note: the lifetime of the captured arguments is managed outside of the - // trivial closure value i.e: there will already be releases for the - // captured arguments. Releasing captured arguments is not necessary. - return true; - } - - // We only accept a user if it is an ARC object that can be removed if the - // object is dead. This should be expanded in the future. This also ensures - // that we are locally identified and non-escaping since we only allow for - // specific ARC users. - ReleaseTracker Tracker(useDoesNotKeepClosureAlive, useHasTransitiveOwnership); - - // Find the ARC Users and the final retain, release. - if (!getFinalReleasesForValue(SILValue(Closure), Tracker)) - return false; - - // If we have a partial_apply, release each captured argument at each one of - // the final release locations of the partial apply. - if (auto *PAI = dyn_cast(Closure)) { - // If we can not decrement the ref counts of the dead partial apply for any - // reason, bail. - if (!releaseCapturedArgsOfDeadPartialApply(PAI, Tracker, Callbacks)) - return false; - } - - // Then delete all user instructions in reverse so that leaf uses are deleted - // first. - for (auto *User : reverse(Tracker.getTrackedUsers())) { - assert(User->getResults().empty() || - useHasTransitiveOwnership(User) && - "We expect only ARC operations without " - "results or a cast from escape to noescape without users"); - Callbacks.DeleteInst(User); - } - - // Finally delete the closure. - Callbacks.DeleteInst(Closure); - - return true; -} - -//===----------------------------------------------------------------------===// -// Value Lifetime -//===----------------------------------------------------------------------===// - -void ValueLifetimeAnalysis::propagateLiveness() { - assert(LiveBlocks.empty() && "frontier computed twice"); - - auto DefBB = DefValue->getParentBlock(); - llvm::SmallVector Worklist; - int NumUsersBeforeDef = 0; - - // Find the initial set of blocks where the value is live, because - // it is used in those blocks. - for (SILInstruction *User : UserSet) { - SILBasicBlock *UserBlock = User->getParent(); - if (LiveBlocks.insert(UserBlock)) - Worklist.push_back(UserBlock); - - // A user in the DefBB could potentially be located before the DefValue. - if (UserBlock == DefBB) - NumUsersBeforeDef++; - } - // Don't count any users in the DefBB which are actually located _after_ - // the DefValue. - auto InstIter = DefValue->getIterator(); - while (NumUsersBeforeDef > 0 && ++InstIter != DefBB->end()) { - if (UserSet.count(&*InstIter)) - NumUsersBeforeDef--; - } - - // Now propagate liveness backwards until we hit the block that defines the - // value. - while (!Worklist.empty()) { - auto *BB = Worklist.pop_back_val(); - - // Don't go beyond the definition. - if (BB == DefBB && NumUsersBeforeDef == 0) - continue; - - for (SILBasicBlock *Pred : BB->getPredecessorBlocks()) { - // If it's already in the set, then we've already queued and/or - // processed the predecessors. - if (LiveBlocks.insert(Pred)) - Worklist.push_back(Pred); - } - } -} - -SILInstruction *ValueLifetimeAnalysis:: findLastUserInBlock(SILBasicBlock *BB) { - // Walk backwards in BB looking for last use of the value. - for (auto II = BB->rbegin(); II != BB->rend(); ++II) { - assert(DefValue != &*II && "Found def before finding use!"); - - if (UserSet.count(&*II)) - return &*II; - } - llvm_unreachable("Expected to find use of value in block!"); -} - -bool ValueLifetimeAnalysis::computeFrontier(Frontier &Fr, Mode mode, - DeadEndBlocks *DEBlocks) { - assert(!isAliveAtBeginOfBlock(DefValue->getFunction()->getEntryBlock()) && - "Can't compute frontier for def which does not dominate all uses"); - - bool NoCriticalEdges = true; - - // Exit-blocks from the lifetime region. The value is live at the end of - // a predecessor block but not in the frontier block itself. - llvm::SmallSetVector FrontierBlocks; - - // Blocks where the value is live at the end of the block and which have - // a frontier block as successor. - llvm::SmallSetVector LiveOutBlocks; - - /// The lifetime ends if we have a live block and a not-live successor. - for (SILBasicBlock *BB : LiveBlocks) { - if (DEBlocks && DEBlocks->isDeadEnd(BB)) - continue; - - bool LiveInSucc = false; - bool DeadInSucc = false; - for (const SILSuccessor &Succ : BB->getSuccessors()) { - if (isAliveAtBeginOfBlock(Succ)) { - LiveInSucc = true; - } else if (!DEBlocks || !DEBlocks->isDeadEnd(Succ)) { - DeadInSucc = true; - } - } - if (!LiveInSucc) { - // The value is not live in any of the successor blocks. This means the - // block contains a last use of the value. The next instruction after - // the last use is part of the frontier. - SILInstruction *LastUser = findLastUserInBlock(BB); - if (!isa(LastUser)) { - Fr.push_back(&*std::next(LastUser->getIterator())); - continue; - } - // In case the last user is a TermInst we add all successor blocks to the - // frontier (see below). - assert(DeadInSucc && "The final using TermInst must have successors"); - } - if (DeadInSucc) { - if (mode == UsersMustPostDomDef) - return false; - - // The value is not live in some of the successor blocks. - LiveOutBlocks.insert(BB); - for (const SILSuccessor &Succ : BB->getSuccessors()) { - if (!isAliveAtBeginOfBlock(Succ)) { - // It's an "exit" edge from the lifetime region. - FrontierBlocks.insert(Succ); - } - } - } - } - // Handle "exit" edges from the lifetime region. - llvm::SmallPtrSet UnhandledFrontierBlocks; - for (SILBasicBlock *FrontierBB: FrontierBlocks) { - assert(mode != UsersMustPostDomDef); - bool needSplit = false; - // If the value is live only in part of the predecessor blocks we have to - // split those predecessor edges. - for (SILBasicBlock *Pred : FrontierBB->getPredecessorBlocks()) { - if (!LiveOutBlocks.count(Pred)) { - needSplit = true; - break; - } - } - if (needSplit) { - if (mode == DontModifyCFG) - return false; - // We need to split the critical edge to create a frontier instruction. - UnhandledFrontierBlocks.insert(FrontierBB); - } else { - // The first instruction of the exit-block is part of the frontier. - Fr.push_back(&*FrontierBB->begin()); - } - } - // Split critical edges from the lifetime region to not yet handled frontier - // blocks. - for (SILBasicBlock *FrontierPred : LiveOutBlocks) { - assert(mode != UsersMustPostDomDef); - auto *T = FrontierPred->getTerminator(); - // Cache the successor blocks because splitting critical edges invalidates - // the successor list iterator of T. - llvm::SmallVector SuccBlocks; - for (const SILSuccessor &Succ : T->getSuccessors()) - SuccBlocks.push_back(Succ); - - for (unsigned i = 0, e = SuccBlocks.size(); i != e; ++i) { - if (UnhandledFrontierBlocks.count(SuccBlocks[i])) { - assert(mode == AllowToModifyCFG); - assert(isCriticalEdge(T, i) && "actually not a critical edge?"); - SILBasicBlock *NewBlock = splitEdge(T, i); - // The single terminator instruction is part of the frontier. - Fr.push_back(&*NewBlock->begin()); - NoCriticalEdges = false; - } - } - } - return NoCriticalEdges; -} - -bool ValueLifetimeAnalysis::isWithinLifetime(SILInstruction *Inst) { - SILBasicBlock *BB = Inst->getParent(); - // Check if the value is not live anywhere in Inst's block. - if (!LiveBlocks.count(BB)) - return false; - for (const SILSuccessor &Succ : BB->getSuccessors()) { - // If the value is live at the beginning of any successor block it is also - // live at the end of BB and therefore Inst is definitely in the lifetime - // region (Note that we don't check in upward direction against the value's - // definition). - if (isAliveAtBeginOfBlock(Succ)) - return true; - } - // The value is live in the block but not at the end of the block. Check if - // Inst is located before (or at) the last use. - for (auto II = BB->rbegin(); II != BB->rend(); ++II) { - if (UserSet.count(&*II)) { - return true; - } - if (Inst == &*II) - return false; - } - llvm_unreachable("Expected to find use of value in block!"); -} - -// Searches \p BB backwards from the instruction before \p FrontierInst -// to the beginning of the list and returns true if we find a dealloc_ref -// /before/ we find \p DefValue (the instruction that defines our target value). -static bool blockContainsDeallocRef(SILBasicBlock *BB, SILInstruction *DefValue, - SILInstruction *FrontierInst) { - SILBasicBlock::reverse_iterator End = BB->rend(); - SILBasicBlock::reverse_iterator Iter = FrontierInst->getReverseIterator(); - for (++Iter; Iter != End; ++Iter) { - SILInstruction *I = &*Iter; - if (isa(I)) - return true; - if (I == DefValue) - return false; - } - return false; -} - -bool ValueLifetimeAnalysis::containsDeallocRef(const Frontier &Frontier) { - SmallPtrSet FrontierBlocks; - // Search in live blocks where the value is not alive until the end of the - // block, i.e. the live range is terminated by a frontier instruction. - for (SILInstruction *FrontierInst : Frontier) { - SILBasicBlock *BB = FrontierInst->getParent(); - if (blockContainsDeallocRef(BB, DefValue, FrontierInst)) - return true; - FrontierBlocks.insert(BB); - } - // Search in all other live blocks where the value is alive until the end of - // the block. - for (SILBasicBlock *BB : LiveBlocks) { - if (FrontierBlocks.count(BB) == 0) { - if (blockContainsDeallocRef(BB, DefValue, BB->getTerminator())) - return true; - } - } - return false; -} - -void ValueLifetimeAnalysis::dump() const { - llvm::errs() << "lifetime of def: " << *DefValue; - for (SILInstruction *Use : UserSet) { - llvm::errs() << " use: " << *Use; - } - llvm::errs() << " live blocks:"; - for (SILBasicBlock *BB : LiveBlocks) { - llvm::errs() << ' ' << BB->getDebugID(); - } - llvm::errs() << '\n'; -} - -// FIXME: Remove this. SILCloner should not create critical edges. -bool BasicBlockCloner::splitCriticalEdges(DominanceInfo *DT, - SILLoopInfo *LI) { - bool changed = false; - // Remove any critical edges that the EdgeThreadingCloner may have - // accidentally created. - for (unsigned succIdx = 0, succEnd = origBB->getSuccessors().size(); - succIdx != succEnd; ++succIdx) { - if (nullptr != splitCriticalEdge(origBB->getTerminator(), succIdx, DT, LI)) - changed |= true; - } - for (unsigned succIdx = 0, succEnd = getNewBB()->getSuccessors().size(); - succIdx != succEnd; ++succIdx) { - auto *newBB = - splitCriticalEdge(getNewBB()->getTerminator(), succIdx, DT, LI); - changed |= (newBB != nullptr); - } - return changed; -} - -bool swift::simplifyUsers(SingleValueInstruction *I) { - bool Changed = false; - - for (auto UI = I->use_begin(), UE = I->use_end(); UI != UE; ) { - SILInstruction *User = UI->getUser(); - ++UI; - - auto SVI = dyn_cast(User); - if (!SVI) continue; - - SILValue S = simplifyInstruction(SVI); - if (!S) - continue; - - replaceAllSimplifiedUsesAndErase(SVI, S); - Changed = true; - } - - return Changed; -} - -/// True if a type can be expanded without a significant increase to code size. -bool swift::shouldExpand(SILModule &Module, SILType Ty) { - // FIXME: Expansion - auto Expansion = ResilienceExpansion::Minimal; - - if (Module.Types.getTypeLowering(Ty, Expansion).isAddressOnly()) { - return false; - } - if (EnableExpandAll) { - return true; - } - - unsigned NumFields = Module.Types.countNumberOfFields(Ty, Expansion); - return (NumFields <= 6); -} - -/// Some support functions for the global-opt and let-properties-opts - -// Encapsulate the state used for recursive analysis of a static -// initializer. Discover all the instruction in a use-def graph and return them -// in topological order. -// -// TODO: We should have a DFS utility for this sort of thing so it isn't -// recursive. -class StaticInitializerAnalysis { - SmallVectorImpl &postOrderInstructions; - llvm::SmallDenseSet visited; - int recursionLevel = 0; - -public: - StaticInitializerAnalysis( - SmallVectorImpl &postOrderInstructions) - : postOrderInstructions(postOrderInstructions) {} - - // Perform a recursive DFS on on the use-def graph rooted at `V`. Insert - // values in the `visited` set in preorder. Insert values in - // `postOrderInstructions` in postorder so that the instructions are - // topologically def-use ordered (in execution order). - bool analyze(SILValue RootValue) { - return recursivelyAnalyzeOperand(RootValue); - } - -protected: - bool recursivelyAnalyzeOperand(SILValue V) { - if (!visited.insert(V).second) - return true; - - if (++recursionLevel > 50) - return false; - - // TODO: For multi-result instructions, we could simply insert all result - // values in the visited set here. - auto *I = dyn_cast(V); - if (!I) - return false; - - if (!recursivelyAnalyzeInstruction(I)) - return false; - - postOrderInstructions.push_back(I); - --recursionLevel; - return true; - } - - bool recursivelyAnalyzeInstruction(SILInstruction *I) { - if (auto *SI = dyn_cast(I)) { - // If it is not a struct which is a simple type, bail. - if (!SI->getType().isTrivial(*SI->getFunction())) - return false; - - return llvm::all_of(SI->getAllOperands(), [&](Operand &Op) -> bool { - return recursivelyAnalyzeOperand(Op.get()); - }); - } - if (auto *TI = dyn_cast(I)) { - // If it is not a tuple which is a simple type, bail. - if (!TI->getType().isTrivial(*TI->getFunction())) - return false; - - return llvm::all_of(TI->getAllOperands(), [&](Operand &Op) -> bool { - return recursivelyAnalyzeOperand(Op.get()); - }); - } - if (auto *bi = dyn_cast(I)) { - switch (bi->getBuiltinInfo().ID) { - case BuiltinValueKind::FPTrunc: - if (auto *LI = dyn_cast(bi->getArguments()[0])) { - return recursivelyAnalyzeOperand(LI); - } - return false; - default: - return false; - } - } - return isa(I) || isa(I) - || isa(I); - } -}; - -/// Check if the value of V is computed by means of a simple initialization. -/// Populate `forwardInstructions` with references to all the instructions -/// that participate in the use-def graph required to compute `V`. The -/// instructions will be in def-use topological order. -bool swift::analyzeStaticInitializer( - SILValue V, SmallVectorImpl &forwardInstructions) { - return StaticInitializerAnalysis(forwardInstructions).analyze(V); -} - -/// FIXME: This must be kept in sync with replaceLoadSequence() -/// below. What a horrible design. -bool swift::canReplaceLoadSequence(SILInstruction *I) { - if (auto *CAI = dyn_cast(I)) - return true; - - if (auto *LI = dyn_cast(I)) - return true; - - if (auto *SEAI = dyn_cast(I)) { - for (auto SEAIUse : SEAI->getUses()) { - if (!canReplaceLoadSequence(SEAIUse->getUser())) - return false; - } - return true; - } - - if (auto *TEAI = dyn_cast(I)) { - for (auto TEAIUse : TEAI->getUses()) { - if (!canReplaceLoadSequence(TEAIUse->getUser())) - return false; - } - return true; - } - - if (auto *BA = dyn_cast(I)) { - for (auto Use : BA->getUses()) { - if (!canReplaceLoadSequence(Use->getUser())) - return false; - } - return true; - } - - // Incidental uses of an address are meaningless with regard to the loaded - // value. - if (isIncidentalUse(I) || isa(I)) - return true; - - return false; -} - -/// 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 -/// Move into utils. -/// -/// FIXME: this utility does not make sense as an API. How can the caller -/// guarantee that the only uses of `I` are struct_element_addr and -/// tuple_element_addr? -void swift::replaceLoadSequence(SILInstruction *I, - SILValue Value) { - if (auto *CAI = dyn_cast(I)) { - SILBuilder B(CAI); - B.createStore(CAI->getLoc(), Value, CAI->getDest(), - StoreOwnershipQualifier::Unqualified); - return; - } - - if (auto *LI = dyn_cast(I)) { - LI->replaceAllUsesWith(Value); - return; - } - - if (auto *SEAI = dyn_cast(I)) { - SILBuilder B(SEAI); - auto *SEI = B.createStructExtract(SEAI->getLoc(), Value, SEAI->getField()); - for (auto SEAIUse : SEAI->getUses()) { - replaceLoadSequence(SEAIUse->getUser(), SEI); - } - return; - } - - if (auto *TEAI = dyn_cast(I)) { - SILBuilder B(TEAI); - auto *TEI = B.createTupleExtract(TEAI->getLoc(), Value, TEAI->getFieldNo()); - for (auto TEAIUse : TEAI->getUses()) { - replaceLoadSequence(TEAIUse->getUser(), TEI); - } - return; - } - - if (auto *BA = dyn_cast(I)) { - for (auto Use : BA->getUses()) { - replaceLoadSequence(Use->getUser(), Value); - } - return; - } - - // Incidental uses of an addres are meaningless with regard to the loaded - // value. - if (isIncidentalUse(I) || isa(I)) - return; - - llvm_unreachable("Unknown instruction sequence for reading from a global"); -} - -/// Are the callees that could be called through Decl statically -/// knowable based on the Decl and the compilation mode? -bool swift::calleesAreStaticallyKnowable(SILModule &M, SILDeclRef Decl) { - if (Decl.isForeign) - return false; - - const DeclContext *AssocDC = M.getAssociatedContext(); - if (!AssocDC) - return false; - - auto *AFD = Decl.getAbstractFunctionDecl(); - assert(AFD && "Expected abstract function decl!"); - - // Only handle members defined within the SILModule's associated context. - if (!AFD->isChildContextOf(AssocDC)) - return false; - - if (AFD->isDynamic()) { - return false; - } - - if (!AFD->hasAccess()) - return false; - - // Only consider 'private' members, unless we are in whole-module compilation. - switch (AFD->getEffectiveAccess()) { - case AccessLevel::Open: - return false; - case AccessLevel::Public: - if (isa(AFD)) { - // Constructors are special: a derived class in another module can - // "override" a constructor if its class is "open", although the - // constructor itself is not open. - auto *ND = AFD->getDeclContext()->getSelfNominalTypeDecl(); - if (ND->getEffectiveAccess() == AccessLevel::Open) - return false; - } - LLVM_FALLTHROUGH; - case AccessLevel::Internal: - return M.isWholeModule(); - case AccessLevel::FilePrivate: - case AccessLevel::Private: - return true; - } - - llvm_unreachable("Unhandled access level in switch."); -} - -void StaticInitCloner::add(SILInstruction *InitVal) { - // Don't schedule an instruction twice for cloning. - if (NumOpsToClone.count(InitVal) != 0) - return; - - ArrayRef Ops = InitVal->getAllOperands(); - NumOpsToClone[InitVal] = Ops.size(); - if (Ops.empty()) { - // It's an instruction without operands, e.g. a literal. It's ready to be - // cloned first. - ReadyToClone.push_back(InitVal); - } else { - // Recursively add all operands. - for (const Operand &Op : Ops) { - add(cast(Op.get())); - } - } -} - -SingleValueInstruction * -StaticInitCloner::clone(SingleValueInstruction *InitVal) { - assert(NumOpsToClone.count(InitVal) != 0 && "InitVal was not added"); - // Find the right order to clone: all operands of an instruction must be - // cloned before the instruction itself. - while (!ReadyToClone.empty()) { - SILInstruction *I = ReadyToClone.pop_back_val(); - - // Clone the instruction into the SILGlobalVariable - visit(I); - - // Check if users of I can now be cloned. - for (SILValue result : I->getResults()) { - for (Operand *Use : result->getUses()) { - SILInstruction *User = Use->getUser(); - if (NumOpsToClone.count(User) != 0 && --NumOpsToClone[User] == 0) - ReadyToClone.push_back(User); - } - } - } - return cast(getMappedValue(InitVal)); -} - -Optional -swift::findLocalApplySites(FunctionRefBaseInst *FRI) { - SmallVector worklist(FRI->use_begin(), FRI->use_end()); - - Optional f; - f.emplace(); - - // Optimistically state that we have no escapes before our def-use dataflow. - f->escapes = false; - - while (!worklist.empty()) { - auto *op = worklist.pop_back_val(); - auto *user = op->getUser(); - - // If we have a full apply site as our user. - if (auto apply = FullApplySite::isa(user)) { - if (apply.getCallee() == op->get()) { - f->fullApplySites.push_back(apply); - continue; - } - } - - // If we have a partial apply as a user, start tracking it, but also look at - // its users. - if (auto *pai = dyn_cast(user)) { - if (pai->getCallee() == op->get()) { - // Track the partial apply that we saw so we can potentially eliminate - // dead closure arguments. - f->partialApplySites.push_back(pai); - // Look to see if we can find a full application of this partial apply - // as well. - llvm::copy(pai->getUses(), std::back_inserter(worklist)); - continue; - } - } - - // Otherwise, see if we have any function casts to look through... - switch (user->getKind()) { - case SILInstructionKind::ThinToThickFunctionInst: - case SILInstructionKind::ConvertFunctionInst: - case SILInstructionKind::ConvertEscapeToNoEscapeInst: - llvm::copy(cast(user)->getUses(), - std::back_inserter(worklist)); - continue; - - // A partial_apply [stack] marks its captured arguments with - // mark_dependence. - case SILInstructionKind::MarkDependenceInst: - llvm::copy(cast(user)->getUses(), - std::back_inserter(worklist)); - continue; - - // Look through any reference count instructions since these are not - // escapes: - case SILInstructionKind::CopyValueInst: - llvm::copy(cast(user)->getUses(), - std::back_inserter(worklist)); - continue; - case SILInstructionKind::StrongRetainInst: - case SILInstructionKind::StrongReleaseInst: - case SILInstructionKind::RetainValueInst: - case SILInstructionKind::ReleaseValueInst: - case SILInstructionKind::DestroyValueInst: - // A partial_apply [stack] is deallocated with a dealloc_stack. - case SILInstructionKind::DeallocStackInst: - continue; - default: - break; - } - - // But everything else is considered an escape. - f->escapes = true; - } - - // If we did escape and didn't find any apply sites, then we have no - // information for our users that is interesting. - if (f->escapes && f->partialApplySites.empty() && f->fullApplySites.empty()) - return None; - return f; -} - -/// Insert destroys of captured arguments of partial_apply [stack]. -void swift::insertDestroyOfCapturedArguments( - PartialApplyInst *PAI, SILBuilder &B, - llvm::function_ref shouldInsertDestroy) { - assert(PAI->isOnStack()); - - ApplySite site(PAI); - SILFunctionConventions calleeConv(site.getSubstCalleeType(), - PAI->getModule()); - auto loc = RegularLocation::getAutoGeneratedLocation(); - for (auto &arg : PAI->getArgumentOperands()) { - if (!shouldInsertDestroy(arg.get())) continue; - unsigned calleeArgumentIndex = site.getCalleeArgIndex(arg); - assert(calleeArgumentIndex >= calleeConv.getSILArgIndexOfFirstParam()); - auto paramInfo = calleeConv.getParamInfoForSILArg(calleeArgumentIndex); - releasePartialApplyCapturedArg(B, loc, arg.get(), paramInfo); - } -} diff --git a/lib/SILOptimizer/Utils/LoopUtils.cpp b/lib/SILOptimizer/Utils/LoopUtils.cpp index 0437d5b6d3d..9f0802b62f5 100644 --- a/lib/SILOptimizer/Utils/LoopUtils.cpp +++ b/lib/SILOptimizer/Utils/LoopUtils.cpp @@ -19,7 +19,7 @@ #include "swift/SIL/SILBasicBlock.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILModule.h" -#include "swift/SILOptimizer/Utils/CFG.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp index 21e08139fe9..0f0f78d9f7e 100644 --- a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp +++ b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp @@ -12,7 +12,7 @@ #include "swift/SILOptimizer/Utils/PerformanceInlinerUtils.h" #include "swift/AST/Module.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" //===----------------------------------------------------------------------===// // ConstantTracker diff --git a/lib/SILOptimizer/Utils/SILInliner.cpp b/lib/SILOptimizer/Utils/SILInliner.cpp index d20ab659b74..8954dcb4f82 100644 --- a/lib/SILOptimizer/Utils/SILInliner.cpp +++ b/lib/SILOptimizer/Utils/SILInliner.cpp @@ -16,7 +16,7 @@ #include "swift/SIL/PrettyStackTrace.h" #include "swift/SIL/SILDebugScope.h" #include "swift/SIL/TypeSubstCloner.h" -#include "swift/SILOptimizer/Utils/CFG.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" diff --git a/lib/SILOptimizer/Utils/SILSSAUpdater.cpp b/lib/SILOptimizer/Utils/SILSSAUpdater.cpp index fb9b17fe7eb..9625114d8fa 100644 --- a/lib/SILOptimizer/Utils/SILSSAUpdater.cpp +++ b/lib/SILOptimizer/Utils/SILSSAUpdater.cpp @@ -10,19 +10,18 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Transforms/Utils/SSAUpdaterImpl.h" +#include "swift/SILOptimizer/Utils/SILSSAUpdater.h" #include "swift/Basic/Malloc.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBasicBlock.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILUndef.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/SILSSAUpdater.h" - +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Utils/SSAUpdaterImpl.h" using namespace swift; diff --git a/lib/SILOptimizer/Utils/ValueLifetime.cpp b/lib/SILOptimizer/Utils/ValueLifetime.cpp new file mode 100644 index 00000000000..8e18a9da9ad --- /dev/null +++ b/lib/SILOptimizer/Utils/ValueLifetime.cpp @@ -0,0 +1,251 @@ +//===--- ValueLifetime.cpp - ValueLifetimeAnalysis ------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 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 +// +//===----------------------------------------------------------------------===// + +#include "swift/SILOptimizer/Utils/ValueLifetime.h" +#include "swift/SIL/BasicBlockUtils.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" + +using namespace swift; + +void ValueLifetimeAnalysis::propagateLiveness() { + assert(liveBlocks.empty() && "frontier computed twice"); + + auto defBB = defValue->getParentBlock(); + llvm::SmallVector worklist; + int numUsersBeforeDef = 0; + + // Find the initial set of blocks where the value is live, because + // it is used in those blocks. + for (SILInstruction *user : userSet) { + SILBasicBlock *userBlock = user->getParent(); + if (liveBlocks.insert(userBlock)) + worklist.push_back(userBlock); + + // A user in the defBB could potentially be located before the defValue. + if (userBlock == defBB) + numUsersBeforeDef++; + } + // Don't count any users in the defBB which are actually located _after_ + // the defValue. + auto instIter = defValue->getIterator(); + while (numUsersBeforeDef > 0 && ++instIter != defBB->end()) { + if (userSet.count(&*instIter)) + numUsersBeforeDef--; + } + + // Now propagate liveness backwards until we hit the block that defines the + // value. + while (!worklist.empty()) { + auto *bb = worklist.pop_back_val(); + + // Don't go beyond the definition. + if (bb == defBB && numUsersBeforeDef == 0) + continue; + + for (SILBasicBlock *Pred : bb->getPredecessorBlocks()) { + // If it's already in the set, then we've already queued and/or + // processed the predecessors. + if (liveBlocks.insert(Pred)) + worklist.push_back(Pred); + } + } +} + +SILInstruction *ValueLifetimeAnalysis::findLastUserInBlock(SILBasicBlock *bb) { + // Walk backwards in bb looking for last use of the value. + for (auto ii = bb->rbegin(); ii != bb->rend(); ++ii) { + assert(defValue != &*ii && "Found def before finding use!"); + + if (userSet.count(&*ii)) + return &*ii; + } + llvm_unreachable("Expected to find use of value in block!"); +} + +bool ValueLifetimeAnalysis::computeFrontier(Frontier &frontier, Mode mode, + DeadEndBlocks *deBlocks) { + assert(!isAliveAtBeginOfBlock(defValue->getFunction()->getEntryBlock()) + && "Can't compute frontier for def which does not dominate all uses"); + + bool noCriticalEdges = true; + + // Exit-blocks from the lifetime region. The value is live at the end of + // a predecessor block but not in the frontier block itself. + llvm::SmallSetVector frontierBlocks; + + // Blocks where the value is live at the end of the block and which have + // a frontier block as successor. + llvm::SmallSetVector liveOutBlocks; + + /// The lifetime ends if we have a live block and a not-live successor. + for (SILBasicBlock *bb : liveBlocks) { + if (deBlocks && deBlocks->isDeadEnd(bb)) + continue; + + bool liveInSucc = false; + bool deadInSucc = false; + for (const SILSuccessor &succ : bb->getSuccessors()) { + if (isAliveAtBeginOfBlock(succ)) { + liveInSucc = true; + } else if (!deBlocks || !deBlocks->isDeadEnd(succ)) { + deadInSucc = true; + } + } + if (!liveInSucc) { + // The value is not live in any of the successor blocks. This means the + // block contains a last use of the value. The next instruction after + // the last use is part of the frontier. + SILInstruction *lastUser = findLastUserInBlock(bb); + if (!isa(lastUser)) { + frontier.push_back(&*std::next(lastUser->getIterator())); + continue; + } + // In case the last user is a TermInst we add all successor blocks to the + // frontier (see below). + assert(deadInSucc && "The final using TermInst must have successors"); + } + if (deadInSucc) { + if (mode == UsersMustPostDomDef) + return false; + + // The value is not live in some of the successor blocks. + liveOutBlocks.insert(bb); + for (const SILSuccessor &succ : bb->getSuccessors()) { + if (!isAliveAtBeginOfBlock(succ)) { + // It's an "exit" edge from the lifetime region. + frontierBlocks.insert(succ); + } + } + } + } + // Handle "exit" edges from the lifetime region. + llvm::SmallPtrSet unhandledFrontierBlocks; + for (SILBasicBlock *frontierBB : frontierBlocks) { + assert(mode != UsersMustPostDomDef); + bool needSplit = false; + // If the value is live only in part of the predecessor blocks we have to + // split those predecessor edges. + for (SILBasicBlock *Pred : frontierBB->getPredecessorBlocks()) { + if (!liveOutBlocks.count(Pred)) { + needSplit = true; + break; + } + } + if (needSplit) { + if (mode == DontModifyCFG) + return false; + // We need to split the critical edge to create a frontier instruction. + unhandledFrontierBlocks.insert(frontierBB); + } else { + // The first instruction of the exit-block is part of the frontier. + frontier.push_back(&*frontierBB->begin()); + } + } + // Split critical edges from the lifetime region to not yet handled frontier + // blocks. + for (SILBasicBlock *frontierPred : liveOutBlocks) { + assert(mode != UsersMustPostDomDef); + auto *term = frontierPred->getTerminator(); + // Cache the successor blocks because splitting critical edges invalidates + // the successor list iterator of T. + llvm::SmallVector succBlocks; + for (const SILSuccessor &succ : term->getSuccessors()) + succBlocks.push_back(succ); + + for (unsigned i = 0, e = succBlocks.size(); i != e; ++i) { + if (unhandledFrontierBlocks.count(succBlocks[i])) { + assert(mode == AllowToModifyCFG); + assert(isCriticalEdge(term, i) && "actually not a critical edge?"); + SILBasicBlock *newBlock = splitEdge(term, i); + // The single terminator instruction is part of the frontier. + frontier.push_back(&*newBlock->begin()); + noCriticalEdges = false; + } + } + } + return noCriticalEdges; +} + +bool ValueLifetimeAnalysis::isWithinLifetime(SILInstruction *inst) { + SILBasicBlock *bb = inst->getParent(); + // Check if the value is not live anywhere in inst's block. + if (!liveBlocks.count(bb)) + return false; + for (const SILSuccessor &succ : bb->getSuccessors()) { + // If the value is live at the beginning of any successor block it is also + // live at the end of bb and therefore inst is definitely in the lifetime + // region (Note that we don't check in upward direction against the value's + // definition). + if (isAliveAtBeginOfBlock(succ)) + return true; + } + // The value is live in the block but not at the end of the block. Check if + // inst is located before (or at) the last use. + for (auto ii = bb->rbegin(); ii != bb->rend(); ++ii) { + if (userSet.count(&*ii)) { + return true; + } + if (inst == &*ii) + return false; + } + llvm_unreachable("Expected to find use of value in block!"); +} + +// Searches \p bb backwards from the instruction before \p frontierInst +// to the beginning of the list and returns true if we find a dealloc_ref +// /before/ we find \p defValue (the instruction that defines our target value). +static bool blockContainsDeallocRef(SILBasicBlock *bb, SILInstruction *defValue, + SILInstruction *frontierInst) { + SILBasicBlock::reverse_iterator End = bb->rend(); + SILBasicBlock::reverse_iterator iter = frontierInst->getReverseIterator(); + for (++iter; iter != End; ++iter) { + SILInstruction *inst = &*iter; + if (isa(inst)) + return true; + if (inst == defValue) + return false; + } + return false; +} + +bool ValueLifetimeAnalysis::containsDeallocRef(const Frontier &frontier) { + SmallPtrSet frontierBlocks; + // Search in live blocks where the value is not alive until the end of the + // block, i.e. the live range is terminated by a frontier instruction. + for (SILInstruction *frontierInst : frontier) { + SILBasicBlock *bb = frontierInst->getParent(); + if (blockContainsDeallocRef(bb, defValue, frontierInst)) + return true; + frontierBlocks.insert(bb); + } + // Search in all other live blocks where the value is alive until the end of + // the block. + for (SILBasicBlock *bb : liveBlocks) { + if (frontierBlocks.count(bb) == 0) { + if (blockContainsDeallocRef(bb, defValue, bb->getTerminator())) + return true; + } + } + return false; +} + +void ValueLifetimeAnalysis::dump() const { + llvm::errs() << "lifetime of def: " << *defValue; + for (SILInstruction *Use : userSet) { + llvm::errs() << " use: " << *Use; + } + llvm::errs() << " live blocks:"; + for (SILBasicBlock *bb : liveBlocks) { + llvm::errs() << ' ' << bb->getDebugID(); + } + llvm::errs() << '\n'; +} diff --git a/test/Sanitizers/tsan-norace-deinit-run-time.swift b/test/Sanitizers/tsan-norace-deinit-run-time.swift index 584448ad319..7fae7a6692e 100644 --- a/test/Sanitizers/tsan-norace-deinit-run-time.swift +++ b/test/Sanitizers/tsan-norace-deinit-run-time.swift @@ -1,6 +1,7 @@ // RUN: %target-swiftc_driver %s -g -sanitize=thread %import-libdispatch -target %sanitizers-target-triple -o %t_tsan-binary // RUN: %target-codesign %t_tsan-binary // RUN: env %env-TSAN_OPTIONS=abort_on_error=0 %target-run %t_tsan-binary 2>&1 | %FileCheck %s --dump-input=fail --implicit-check-not='ThreadSanitizer' +// REQUIRES: rdar55880585 // REQUIRES: executable_test // REQUIRES: tsan_runtime