//===--- ARCRegionState.h ---------------------------------------*- 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_PASSMANAGER_ARC_ARCREGIONSTATE_H #define SWIFT_SILOPTIMIZER_PASSMANAGER_ARC_ARCREGIONSTATE_H #include "GlobalLoopARCSequenceDataflow.h" #include "swift/Basic/NullablePtr.h" namespace swift { class LoopRegion; class LoopRegionFunctionInfo; class AliasAnalysis; class RCIdentityFunctionInfo; /// Per-Region state. class ARCRegionState { public: // TODO: These are relatively expensive, find something else to use here. using TopDownMapTy = SmallBlotMapVector; using BottomUpMapTy = SmallBlotMapVector; private: /// The region that this ARCRegionState summarizes information for. /// /// The only time that the pointer is null is during initialization. Using /// NullablePtr is just a convenient way to make sure that we assert if we /// attempt to use Region during initialization before the pointer is set. NullablePtr Region; /// The top-down traversal uses this to record information known about a /// pointer at the bottom of each block. TopDownMapTy PtrToTopDownState; /// The bottom-up traversal uses this to record information known about a /// pointer at the top of each block. BottomUpMapTy PtrToBottomUpState; /// Is this a region from which we can leak ARC values? /// /// If we know that the program has entered a state from which it is /// guaranteed to terminate soon, in our model we allow for all memory to be /// leaked since the operating system will soon reclaim the memory. We take /// advantage of this to ignore control flow. bool AllowsLeaks; /// A list of instructions contained in this region that can either use or /// decrement reference counts. /// /// This is flow insensitive since we just add all of the potential /// users/decrements in subregions without caring if there is only one along a /// path. This is for simplicity in the first iteration. /// /// TODO: This needs a better name. llvm::SmallVector SummarizedInterestingInsts; public: ARCRegionState(LoopRegion *R, bool AllowsLeaks); /// Is this Region from which we can leak memory safely? bool allowsLeaks() const { return AllowsLeaks; } /// Return the region associated with this ARCRegionState. /// /// Even though Region is a NullablePtr, it is only null during /// initialization. This method should not be called then. const LoopRegion *getRegion() const { return Region.get(); } LoopRegion *getRegion() { return Region.get(); } /// Top Down Iterators using topdown_iterator = TopDownMapTy::iterator; using topdown_const_iterator = TopDownMapTy::const_iterator; topdown_iterator topdown_begin() { return PtrToTopDownState.begin(); } topdown_iterator topdown_end() { return PtrToTopDownState.end(); } topdown_const_iterator topdown_begin() const { return PtrToTopDownState.begin(); } topdown_const_iterator topdown_end() const { return PtrToTopDownState.end(); } iterator_range getTopDownStates() { return make_range(topdown_begin(), topdown_end()); } /// Bottom up iteration. using bottomup_iterator = BottomUpMapTy::iterator; using bottomup_const_iterator = BottomUpMapTy::const_iterator; bottomup_iterator bottomup_begin() { return PtrToBottomUpState.begin(); } bottomup_iterator bottomup_end() { return PtrToBottomUpState.end(); } bottomup_const_iterator bottomup_begin() const { return PtrToBottomUpState.begin(); } bottomup_const_iterator bottomup_end() const { return PtrToBottomUpState.end(); } iterator_range getBottomupStates() { return make_range(bottomup_begin(), bottomup_end()); } /// Attempt to find the PtrState object describing the top down state for /// pointer Arg. Return a new initialized PtrState describing the top down /// state for Arg if we do not find one. TopDownRefCountState &getTopDownRefCountState(SILValue Ptr) { return PtrToTopDownState[Ptr]; } /// Attempt to find the PtrState object describing the bottom up state for /// pointer Arg. Return a new initialized PtrState describing the bottom up /// state for Arg if we do not find one. BottomUpRefCountState &getBottomUpRefCountState(SILValue Ptr) { return PtrToBottomUpState[Ptr]; } /// Blot \p Ptr. void clearBottomUpRefCountState(SILValue Ptr) { PtrToBottomUpState.erase(Ptr); } /// Blot \p Ptr. void clearTopDownRefCountState(SILValue Ptr) { PtrToTopDownState.erase(Ptr); } void clearTopDownState() { PtrToTopDownState.clear(); } void clearBottomUpState() { PtrToBottomUpState.clear(); } /// Clear both the bottom up *AND* top down state. void clear() { clearTopDownState(); clearBottomUpState(); } using const_reverse_summarizedinterestinginsts_iterator = decltype(SummarizedInterestingInsts)::const_reverse_iterator; const_reverse_summarizedinterestinginsts_iterator summarizedinterestinginsts_rbegin() const { return SummarizedInterestingInsts.rbegin(); } const_reverse_summarizedinterestinginsts_iterator summarizedinterestinginsts_rend() const { return SummarizedInterestingInsts.rend(); } using const_summarizedinterestinginsts_iterator = decltype(SummarizedInterestingInsts)::const_iterator; const_summarizedinterestinginsts_iterator summarizedinterestinginsts_begin() const { return SummarizedInterestingInsts.begin(); } const_summarizedinterestinginsts_iterator summarizedinterestinginsts_end() const { return SummarizedInterestingInsts.end(); } iterator_range getSummarizedInterestingInsts() const { return {summarizedinterestinginsts_begin(), summarizedinterestinginsts_end()}; } /// Merge in the state of the successor basic block. This is currently a stub. void mergeSuccBottomUp(ARCRegionState &SuccRegion); /// Initialize this Region with the state of the successor basic block. This /// is /// called on a basic block's state and then any other successors states are /// merged in. This is currently a stub. void initSuccBottomUp(ARCRegionState &SuccRegion); /// Merge in the state of the predecessor basic block. This is currently a /// stub. void mergePredTopDown(ARCRegionState &PredRegion); /// Initialize the state for this Region with the state of its predecessor /// Region. Used to create an initial state before we merge in other /// predecessors. This is currently a stub. void initPredTopDown(ARCRegionState &PredRegion); /// If this region is a block, process all instructions top down. Otherwise, /// apply the summarized top down information to the merged top down /// state. Returns true if nested retains were detected while visiting /// instructions. Returns false otherwise. bool processTopDown( AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, LoopRegionFunctionInfo *LRFI, llvm::DenseSet &UnmatchedRefCountInsts, BlotMapVector &DecToIncStateMap, llvm::DenseMap &LoopRegionState, ImmutablePointerSetFactory &SetFactory); /// If this region is a block, process all instructions bottom up. Otherwise, /// apply the summarized bottom up information to the merged bottom up /// state. Returns true if nested releases were detected while visiting /// instructions. Returns false otherwise. bool processBottomUp( AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, EpilogueARCFunctionInfo *EAFI, LoopRegionFunctionInfo *LRFI, bool FreezeOwnedArgEpilogueReleases, llvm::DenseSet &UnmatchedRefCountInsts, BlotMapVector &IncToDecStateMap, llvm::DenseMap &RegionStateInfo, ImmutablePointerSetFactory &SetFactory); void summarizeBlock(SILBasicBlock *BB); void summarize( LoopRegionFunctionInfo *LRFI, llvm::DenseMap &RegionStateInfo); /// Add \p I to the interesting instruction list of this region if it is a /// block. We assume that I is an instruction in the block. void addInterestingInst(SILInstruction *I); /// Remove \p I from the interesting instruction list of this region if it is /// a block. We assume that I is an instruction in the block. void removeInterestingInst(SILInstruction *I); private: bool processBlockBottomUp( const LoopRegion *R, AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, EpilogueARCFunctionInfo *EAFI, LoopRegionFunctionInfo *LRFI, bool FreezeOwnedArgEpilogueReleases, BlotMapVector &IncToDecStateMap, ImmutablePointerSetFactory &SetFactory); bool processLoopBottomUp( const LoopRegion *R, AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI, RCIdentityFunctionInfo *RCIA, llvm::DenseMap &RegionStateInfo, llvm::DenseSet &UnmatchedRefCountInsts); bool processBlockTopDown( SILBasicBlock &BB, AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, BlotMapVector &DecToIncStateMap, ImmutablePointerSetFactory &SetFactory); bool processLoopTopDown( const LoopRegion *R, ARCRegionState *State, AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI, RCIdentityFunctionInfo *RCIA, llvm::DenseSet &UnmatchedRefCountInsts); void summarizeLoop( const LoopRegion *R, LoopRegionFunctionInfo *LRFI, llvm::DenseMap &RegionStateInfo); }; } // end swift namespace #endif