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