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/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 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 
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 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 {
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   /// 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
211