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