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