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