• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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