/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/Transforms/ObjCARC/PtrState.h
Line | Count | Source (jump to first uncovered line) |
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/IR/Instruction.h" |
23 | | #include "llvm/IR/Value.h" |
24 | | #include "llvm/Support/Debug.h" |
25 | | #include "llvm/Support/raw_ostream.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 | | |
87 | | RRInfo() |
88 | | : KnownSafe(false), IsTailCallRelease(false), ReleaseMetadata(nullptr), |
89 | 1.57k | 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 propagated 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 | | |
115 | 824 | PtrState() : KnownPositiveRefCount(false), Partial(false), Seq(S_None) {} |
116 | | |
117 | | public: |
118 | 911 | bool IsKnownSafe() const { return RRI.KnownSafe; } |
119 | | |
120 | 597 | void SetKnownSafe(const bool NewValue) { RRI.KnownSafe = NewValue; } |
121 | | |
122 | 0 | bool IsTailCallRelease() const { return RRI.IsTailCallRelease; } |
123 | | |
124 | 489 | void SetTailCallRelease(const bool NewValue) { |
125 | 489 | RRI.IsTailCallRelease = NewValue; |
126 | 489 | } |
127 | | |
128 | 40 | bool IsTrackingImpreciseReleases() const { |
129 | 40 | return RRI.ReleaseMetadata != nullptr; |
130 | 40 | } |
131 | | |
132 | 0 | const MDNode *GetReleaseMetadata() const { return RRI.ReleaseMetadata; } |
133 | | |
134 | 489 | void SetReleaseMetadata(MDNode *NewValue) { RRI.ReleaseMetadata = NewValue; } |
135 | | |
136 | 0 | bool IsCFGHazardAfflicted() const { return RRI.CFGHazardAfflicted; } |
137 | | |
138 | 114 | void SetCFGHazardAfflicted(const bool NewValue) { |
139 | 114 | RRI.CFGHazardAfflicted = NewValue; |
140 | 114 | } |
141 | | |
142 | | void SetKnownPositiveRefCount(); |
143 | | void ClearKnownPositiveRefCount(); |
144 | | |
145 | 597 | bool HasKnownPositiveRefCount() const { return KnownPositiveRefCount; } |
146 | | |
147 | | void SetSeq(Sequence NewSeq); |
148 | | |
149 | 10.9k | Sequence GetSeq() const { return static_cast<Sequence>(Seq); } |
150 | | |
151 | 461 | void ClearSequenceProgress() { ResetSequenceProgress(S_None); } |
152 | | |
153 | | void ResetSequenceProgress(Sequence NewSeq); |
154 | | void Merge(const PtrState &Other, bool TopDown); |
155 | | |
156 | 597 | void InsertCall(Instruction *I) { RRI.Calls.insert(I); } |
157 | | |
158 | 408 | void InsertReverseInsertPt(Instruction *I) { RRI.ReverseInsertPts.insert(I); } |
159 | | |
160 | 129 | void ClearReverseInsertPts() { RRI.ReverseInsertPts.clear(); } |
161 | | |
162 | 0 | bool HasReverseInsertPts() const { return !RRI.ReverseInsertPts.empty(); } |
163 | | |
164 | 372 | const RRInfo &GetRRInfo() const { return RRI; } |
165 | | }; |
166 | | |
167 | | struct BottomUpPtrState : PtrState { |
168 | 517 | 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 occurred 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 { |
189 | 307 | 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 | | /// occurred. |
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 |