1*9880d681SAndroid Build Coastguard Worker //===--- PtrState.h - ARC State for a Ptr -------------------*- C++ -*-----===// 2*9880d681SAndroid Build Coastguard Worker // 3*9880d681SAndroid Build Coastguard Worker // The LLVM Compiler Infrastructure 4*9880d681SAndroid Build Coastguard Worker // 5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source 6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details. 7*9880d681SAndroid Build Coastguard Worker // 8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===// 9*9880d681SAndroid Build Coastguard Worker // 10*9880d681SAndroid Build Coastguard Worker // This file contains declarations for the ARC state associated with a ptr. It 11*9880d681SAndroid Build Coastguard Worker // is only used by the ARC Sequence Dataflow computation. By separating this 12*9880d681SAndroid Build Coastguard Worker // from the actual dataflow, it is easier to consider the mechanics of the ARC 13*9880d681SAndroid Build Coastguard Worker // optimization separate from the actual predicates being used. 14*9880d681SAndroid Build Coastguard Worker // 15*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===// 16*9880d681SAndroid Build Coastguard Worker 17*9880d681SAndroid Build Coastguard Worker #ifndef LLVM_LIB_TRANSFORMS_OBJCARC_PTRSTATE_H 18*9880d681SAndroid Build Coastguard Worker #define LLVM_LIB_TRANSFORMS_OBJCARC_PTRSTATE_H 19*9880d681SAndroid Build Coastguard Worker 20*9880d681SAndroid Build Coastguard Worker #include "llvm/ADT/SmallPtrSet.h" 21*9880d681SAndroid Build Coastguard Worker #include "llvm/Analysis/ObjCARCInstKind.h" 22*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/Instruction.h" 23*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/Value.h" 24*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/raw_ostream.h" 25*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/Debug.h" 26*9880d681SAndroid Build Coastguard Worker 27*9880d681SAndroid Build Coastguard Worker namespace llvm { 28*9880d681SAndroid Build Coastguard Worker namespace objcarc { 29*9880d681SAndroid Build Coastguard Worker 30*9880d681SAndroid Build Coastguard Worker class ARCMDKindCache; 31*9880d681SAndroid Build Coastguard Worker class ProvenanceAnalysis; 32*9880d681SAndroid Build Coastguard Worker 33*9880d681SAndroid Build Coastguard Worker /// \enum Sequence 34*9880d681SAndroid Build Coastguard Worker /// 35*9880d681SAndroid Build Coastguard Worker /// \brief A sequence of states that a pointer may go through in which an 36*9880d681SAndroid Build Coastguard Worker /// objc_retain and objc_release are actually needed. 37*9880d681SAndroid Build Coastguard Worker enum Sequence { 38*9880d681SAndroid Build Coastguard Worker S_None, 39*9880d681SAndroid Build Coastguard Worker S_Retain, ///< objc_retain(x). 40*9880d681SAndroid Build Coastguard Worker S_CanRelease, ///< foo(x) -- x could possibly see a ref count decrement. 41*9880d681SAndroid Build Coastguard Worker S_Use, ///< any use of x. 42*9880d681SAndroid Build Coastguard Worker S_Stop, ///< like S_Release, but code motion is stopped. 43*9880d681SAndroid Build Coastguard Worker S_Release, ///< objc_release(x). 44*9880d681SAndroid Build Coastguard Worker S_MovableRelease ///< objc_release(x), !clang.imprecise_release. 45*9880d681SAndroid Build Coastguard Worker }; 46*9880d681SAndroid Build Coastguard Worker 47*9880d681SAndroid Build Coastguard Worker raw_ostream &operator<<(raw_ostream &OS, 48*9880d681SAndroid Build Coastguard Worker const Sequence S) LLVM_ATTRIBUTE_UNUSED; 49*9880d681SAndroid Build Coastguard Worker 50*9880d681SAndroid Build Coastguard Worker /// \brief Unidirectional information about either a 51*9880d681SAndroid Build Coastguard Worker /// retain-decrement-use-release sequence or release-use-decrement-retain 52*9880d681SAndroid Build Coastguard Worker /// reverse sequence. 53*9880d681SAndroid Build Coastguard Worker struct RRInfo { 54*9880d681SAndroid Build Coastguard Worker /// After an objc_retain, the reference count of the referenced 55*9880d681SAndroid Build Coastguard Worker /// object is known to be positive. Similarly, before an objc_release, the 56*9880d681SAndroid Build Coastguard Worker /// reference count of the referenced object is known to be positive. If 57*9880d681SAndroid Build Coastguard Worker /// there are retain-release pairs in code regions where the retain count 58*9880d681SAndroid Build Coastguard Worker /// is known to be positive, they can be eliminated, regardless of any side 59*9880d681SAndroid Build Coastguard Worker /// effects between them. 60*9880d681SAndroid Build Coastguard Worker /// 61*9880d681SAndroid Build Coastguard Worker /// Also, a retain+release pair nested within another retain+release 62*9880d681SAndroid Build Coastguard Worker /// pair all on the known same pointer value can be eliminated, regardless 63*9880d681SAndroid Build Coastguard Worker /// of any intervening side effects. 64*9880d681SAndroid Build Coastguard Worker /// 65*9880d681SAndroid Build Coastguard Worker /// KnownSafe is true when either of these conditions is satisfied. 66*9880d681SAndroid Build Coastguard Worker bool KnownSafe; 67*9880d681SAndroid Build Coastguard Worker 68*9880d681SAndroid Build Coastguard Worker /// True of the objc_release calls are all marked with the "tail" keyword. 69*9880d681SAndroid Build Coastguard Worker bool IsTailCallRelease; 70*9880d681SAndroid Build Coastguard Worker 71*9880d681SAndroid Build Coastguard Worker /// If the Calls are objc_release calls and they all have a 72*9880d681SAndroid Build Coastguard Worker /// clang.imprecise_release tag, this is the metadata tag. 73*9880d681SAndroid Build Coastguard Worker MDNode *ReleaseMetadata; 74*9880d681SAndroid Build Coastguard Worker 75*9880d681SAndroid Build Coastguard Worker /// For a top-down sequence, the set of objc_retains or 76*9880d681SAndroid Build Coastguard Worker /// objc_retainBlocks. For bottom-up, the set of objc_releases. 77*9880d681SAndroid Build Coastguard Worker SmallPtrSet<Instruction *, 2> Calls; 78*9880d681SAndroid Build Coastguard Worker 79*9880d681SAndroid Build Coastguard Worker /// The set of optimal insert positions for moving calls in the opposite 80*9880d681SAndroid Build Coastguard Worker /// sequence. 81*9880d681SAndroid Build Coastguard Worker SmallPtrSet<Instruction *, 2> ReverseInsertPts; 82*9880d681SAndroid Build Coastguard Worker 83*9880d681SAndroid Build Coastguard Worker /// If this is true, we cannot perform code motion but can still remove 84*9880d681SAndroid Build Coastguard Worker /// retain/release pairs. 85*9880d681SAndroid Build Coastguard Worker bool CFGHazardAfflicted; 86*9880d681SAndroid Build Coastguard Worker RRInfoRRInfo87*9880d681SAndroid Build Coastguard Worker RRInfo() 88*9880d681SAndroid Build Coastguard Worker : KnownSafe(false), IsTailCallRelease(false), ReleaseMetadata(nullptr), 89*9880d681SAndroid Build Coastguard Worker CFGHazardAfflicted(false) {} 90*9880d681SAndroid Build Coastguard Worker 91*9880d681SAndroid Build Coastguard Worker void clear(); 92*9880d681SAndroid Build Coastguard Worker 93*9880d681SAndroid Build Coastguard Worker /// Conservatively merge the two RRInfo. Returns true if a partial merge has 94*9880d681SAndroid Build Coastguard Worker /// occurred, false otherwise. 95*9880d681SAndroid Build Coastguard Worker bool Merge(const RRInfo &Other); 96*9880d681SAndroid Build Coastguard Worker }; 97*9880d681SAndroid Build Coastguard Worker 98*9880d681SAndroid Build Coastguard Worker /// \brief This class summarizes several per-pointer runtime properties which 99*9880d681SAndroid Build Coastguard Worker /// are propagated through the flow graph. 100*9880d681SAndroid Build Coastguard Worker class PtrState { 101*9880d681SAndroid Build Coastguard Worker protected: 102*9880d681SAndroid Build Coastguard Worker /// True if the reference count is known to be incremented. 103*9880d681SAndroid Build Coastguard Worker bool KnownPositiveRefCount; 104*9880d681SAndroid Build Coastguard Worker 105*9880d681SAndroid Build Coastguard Worker /// True if we've seen an opportunity for partial RR elimination, such as 106*9880d681SAndroid Build Coastguard Worker /// pushing calls into a CFG triangle or into one side of a CFG diamond. 107*9880d681SAndroid Build Coastguard Worker bool Partial; 108*9880d681SAndroid Build Coastguard Worker 109*9880d681SAndroid Build Coastguard Worker /// The current position in the sequence. 110*9880d681SAndroid Build Coastguard Worker unsigned char Seq : 8; 111*9880d681SAndroid Build Coastguard Worker 112*9880d681SAndroid Build Coastguard Worker /// Unidirectional information about the current sequence. 113*9880d681SAndroid Build Coastguard Worker RRInfo RRI; 114*9880d681SAndroid Build Coastguard Worker PtrState()115*9880d681SAndroid Build Coastguard Worker PtrState() : KnownPositiveRefCount(false), Partial(false), Seq(S_None) {} 116*9880d681SAndroid Build Coastguard Worker 117*9880d681SAndroid Build Coastguard Worker public: IsKnownSafe()118*9880d681SAndroid Build Coastguard Worker bool IsKnownSafe() const { return RRI.KnownSafe; } 119*9880d681SAndroid Build Coastguard Worker SetKnownSafe(const bool NewValue)120*9880d681SAndroid Build Coastguard Worker void SetKnownSafe(const bool NewValue) { RRI.KnownSafe = NewValue; } 121*9880d681SAndroid Build Coastguard Worker IsTailCallRelease()122*9880d681SAndroid Build Coastguard Worker bool IsTailCallRelease() const { return RRI.IsTailCallRelease; } 123*9880d681SAndroid Build Coastguard Worker SetTailCallRelease(const bool NewValue)124*9880d681SAndroid Build Coastguard Worker void SetTailCallRelease(const bool NewValue) { 125*9880d681SAndroid Build Coastguard Worker RRI.IsTailCallRelease = NewValue; 126*9880d681SAndroid Build Coastguard Worker } 127*9880d681SAndroid Build Coastguard Worker IsTrackingImpreciseReleases()128*9880d681SAndroid Build Coastguard Worker bool IsTrackingImpreciseReleases() const { 129*9880d681SAndroid Build Coastguard Worker return RRI.ReleaseMetadata != nullptr; 130*9880d681SAndroid Build Coastguard Worker } 131*9880d681SAndroid Build Coastguard Worker GetReleaseMetadata()132*9880d681SAndroid Build Coastguard Worker const MDNode *GetReleaseMetadata() const { return RRI.ReleaseMetadata; } 133*9880d681SAndroid Build Coastguard Worker SetReleaseMetadata(MDNode * NewValue)134*9880d681SAndroid Build Coastguard Worker void SetReleaseMetadata(MDNode *NewValue) { RRI.ReleaseMetadata = NewValue; } 135*9880d681SAndroid Build Coastguard Worker IsCFGHazardAfflicted()136*9880d681SAndroid Build Coastguard Worker bool IsCFGHazardAfflicted() const { return RRI.CFGHazardAfflicted; } 137*9880d681SAndroid Build Coastguard Worker SetCFGHazardAfflicted(const bool NewValue)138*9880d681SAndroid Build Coastguard Worker void SetCFGHazardAfflicted(const bool NewValue) { 139*9880d681SAndroid Build Coastguard Worker RRI.CFGHazardAfflicted = NewValue; 140*9880d681SAndroid Build Coastguard Worker } 141*9880d681SAndroid Build Coastguard Worker 142*9880d681SAndroid Build Coastguard Worker void SetKnownPositiveRefCount(); 143*9880d681SAndroid Build Coastguard Worker void ClearKnownPositiveRefCount(); 144*9880d681SAndroid Build Coastguard Worker HasKnownPositiveRefCount()145*9880d681SAndroid Build Coastguard Worker bool HasKnownPositiveRefCount() const { return KnownPositiveRefCount; } 146*9880d681SAndroid Build Coastguard Worker 147*9880d681SAndroid Build Coastguard Worker void SetSeq(Sequence NewSeq); 148*9880d681SAndroid Build Coastguard Worker GetSeq()149*9880d681SAndroid Build Coastguard Worker Sequence GetSeq() const { return static_cast<Sequence>(Seq); } 150*9880d681SAndroid Build Coastguard Worker ClearSequenceProgress()151*9880d681SAndroid Build Coastguard Worker void ClearSequenceProgress() { ResetSequenceProgress(S_None); } 152*9880d681SAndroid Build Coastguard Worker 153*9880d681SAndroid Build Coastguard Worker void ResetSequenceProgress(Sequence NewSeq); 154*9880d681SAndroid Build Coastguard Worker void Merge(const PtrState &Other, bool TopDown); 155*9880d681SAndroid Build Coastguard Worker InsertCall(Instruction * I)156*9880d681SAndroid Build Coastguard Worker void InsertCall(Instruction *I) { RRI.Calls.insert(I); } 157*9880d681SAndroid Build Coastguard Worker InsertReverseInsertPt(Instruction * I)158*9880d681SAndroid Build Coastguard Worker void InsertReverseInsertPt(Instruction *I) { RRI.ReverseInsertPts.insert(I); } 159*9880d681SAndroid Build Coastguard Worker ClearReverseInsertPts()160*9880d681SAndroid Build Coastguard Worker void ClearReverseInsertPts() { RRI.ReverseInsertPts.clear(); } 161*9880d681SAndroid Build Coastguard Worker HasReverseInsertPts()162*9880d681SAndroid Build Coastguard Worker bool HasReverseInsertPts() const { return !RRI.ReverseInsertPts.empty(); } 163*9880d681SAndroid Build Coastguard Worker GetRRInfo()164*9880d681SAndroid Build Coastguard Worker const RRInfo &GetRRInfo() const { return RRI; } 165*9880d681SAndroid Build Coastguard Worker }; 166*9880d681SAndroid Build Coastguard Worker 167*9880d681SAndroid Build Coastguard Worker struct BottomUpPtrState : PtrState { BottomUpPtrStateBottomUpPtrState168*9880d681SAndroid Build Coastguard Worker BottomUpPtrState() : PtrState() {} 169*9880d681SAndroid Build Coastguard Worker 170*9880d681SAndroid Build Coastguard Worker /// (Re-)Initialize this bottom up pointer returning true if we detected a 171*9880d681SAndroid Build Coastguard Worker /// pointer with nested releases. 172*9880d681SAndroid Build Coastguard Worker bool InitBottomUp(ARCMDKindCache &Cache, Instruction *I); 173*9880d681SAndroid Build Coastguard Worker 174*9880d681SAndroid Build Coastguard Worker /// Return true if this set of releases can be paired with a release. Modifies 175*9880d681SAndroid Build Coastguard Worker /// state appropriately to reflect that the matching occurred if it is 176*9880d681SAndroid Build Coastguard Worker /// successful. 177*9880d681SAndroid Build Coastguard Worker /// 178*9880d681SAndroid Build Coastguard Worker /// It is assumed that one has already checked that the RCIdentity of the 179*9880d681SAndroid Build Coastguard Worker /// retain and the RCIdentity of this ptr state are the same. 180*9880d681SAndroid Build Coastguard Worker bool MatchWithRetain(); 181*9880d681SAndroid Build Coastguard Worker 182*9880d681SAndroid Build Coastguard Worker void HandlePotentialUse(BasicBlock *BB, Instruction *Inst, const Value *Ptr, 183*9880d681SAndroid Build Coastguard Worker ProvenanceAnalysis &PA, ARCInstKind Class); 184*9880d681SAndroid Build Coastguard Worker bool HandlePotentialAlterRefCount(Instruction *Inst, const Value *Ptr, 185*9880d681SAndroid Build Coastguard Worker ProvenanceAnalysis &PA, ARCInstKind Class); 186*9880d681SAndroid Build Coastguard Worker }; 187*9880d681SAndroid Build Coastguard Worker 188*9880d681SAndroid Build Coastguard Worker struct TopDownPtrState : PtrState { TopDownPtrStateTopDownPtrState189*9880d681SAndroid Build Coastguard Worker TopDownPtrState() : PtrState() {} 190*9880d681SAndroid Build Coastguard Worker 191*9880d681SAndroid Build Coastguard Worker /// (Re-)Initialize this bottom up pointer returning true if we detected a 192*9880d681SAndroid Build Coastguard Worker /// pointer with nested releases. 193*9880d681SAndroid Build Coastguard Worker bool InitTopDown(ARCInstKind Kind, Instruction *I); 194*9880d681SAndroid Build Coastguard Worker 195*9880d681SAndroid Build Coastguard Worker /// Return true if this set of retains can be paired with the given 196*9880d681SAndroid Build Coastguard Worker /// release. Modifies state appropriately to reflect that the matching 197*9880d681SAndroid Build Coastguard Worker /// occurred. 198*9880d681SAndroid Build Coastguard Worker bool MatchWithRelease(ARCMDKindCache &Cache, Instruction *Release); 199*9880d681SAndroid Build Coastguard Worker 200*9880d681SAndroid Build Coastguard Worker void HandlePotentialUse(Instruction *Inst, const Value *Ptr, 201*9880d681SAndroid Build Coastguard Worker ProvenanceAnalysis &PA, ARCInstKind Class); 202*9880d681SAndroid Build Coastguard Worker 203*9880d681SAndroid Build Coastguard Worker bool HandlePotentialAlterRefCount(Instruction *Inst, const Value *Ptr, 204*9880d681SAndroid Build Coastguard Worker ProvenanceAnalysis &PA, ARCInstKind Class); 205*9880d681SAndroid Build Coastguard Worker }; 206*9880d681SAndroid Build Coastguard Worker 207*9880d681SAndroid Build Coastguard Worker } // end namespace objcarc 208*9880d681SAndroid Build Coastguard Worker } // end namespace llvm 209*9880d681SAndroid Build Coastguard Worker 210*9880d681SAndroid Build Coastguard Worker #endif 211