blob: b8b9d2e930eb91ba32bddc88545517e89df13b27 [file] [log] [blame]
//===--- 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;
/// \brief Per-Region state.
class ARCRegionState {
public:
// TODO: These are relatively expensive, find something else to use here.
using TopDownMapTy = SmallBlotMapVector<SILValue, TopDownRefCountState, 4>;
using BottomUpMapTy = SmallBlotMapVector<SILValue, BottomUpRefCountState, 4>;
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<LoopRegion> 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<SILInstruction *, 4> 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<topdown_iterator> 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<bottomup_iterator> 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.blot(Ptr);
}
/// Blot \p Ptr.
void clearTopDownRefCountState(SILValue Ptr) { PtrToTopDownState.blot(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<const_summarizedinterestinginsts_iterator>
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,
BlotMapVector<SILInstruction *, TopDownRefCountState> &DecToIncStateMap,
llvm::DenseMap<const LoopRegion *, ARCRegionState *> &LoopRegionState,
ImmutablePointerSetFactory<SILInstruction> &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,
BlotMapVector<SILInstruction *, BottomUpRefCountState> &IncToDecStateMap,
llvm::DenseMap<const LoopRegion *, ARCRegionState *> &RegionStateInfo,
ImmutablePointerSetFactory<SILInstruction> &SetFactory);
void summarizeBlock(SILBasicBlock *BB);
void summarize(
LoopRegionFunctionInfo *LRFI,
llvm::DenseMap<const LoopRegion *, ARCRegionState *> &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:
void processBlockBottomUpPredTerminators(
const LoopRegion *R, AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI,
ImmutablePointerSetFactory<SILInstruction> &SetFactory);
bool processBlockBottomUp(
const LoopRegion *R, AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA,
EpilogueARCFunctionInfo *EAFI,
LoopRegionFunctionInfo *LRFI, bool FreezeOwnedArgEpilogueReleases,
BlotMapVector<SILInstruction *, BottomUpRefCountState> &IncToDecStateMap,
ImmutablePointerSetFactory<SILInstruction> &SetFactory);
bool processLoopBottomUp(
const LoopRegion *R, AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI,
llvm::DenseMap<const LoopRegion *, ARCRegionState *> &RegionStateInfo,
ImmutablePointerSetFactory<SILInstruction> &SetFactory);
bool processBlockTopDown(
SILBasicBlock &BB, AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA,
BlotMapVector<SILInstruction *, TopDownRefCountState> &DecToIncStateMap,
ImmutablePointerSetFactory<SILInstruction> &SetFactory);
bool
processLoopTopDown(const LoopRegion *R, ARCRegionState *State,
AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI,
ImmutablePointerSetFactory<SILInstruction> &SetFactory);
void summarizeLoop(
const LoopRegion *R, LoopRegionFunctionInfo *LRFI,
llvm::DenseMap<const LoopRegion *, ARCRegionState *> &RegionStateInfo);
};
} // end swift namespace
#endif