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