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
23namespace llvm {
24
25class BasicBlock;
26class Instruction;
27class MDNode;
28class raw_ostream;
29class Value;
30
31namespace objcarc {
32
33class ARCMDKindCache;
34class BundledRetainClaimRVs;
35class 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.
41enum 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, ///< code motion is stopped.
47 S_MovableRelease ///< objc_release(x), !clang.imprecise_release.
48};
49
50[[maybe_unused]] raw_ostream &operator<<(raw_ostream &OS, const Sequence S);
51
52/// Unidirectional information about either a
53/// retain-decrement-use-release sequence or release-use-decrement-retain
54/// reverse sequence.
55struct RRInfo {
56 /// After an objc_retain, the reference count of the referenced
57 /// object is known to be positive. Similarly, before an objc_release, the
58 /// reference count of the referenced object is known to be positive. If
59 /// there are retain-release pairs in code regions where the retain count
60 /// is known to be positive, they can be eliminated, regardless of any side
61 /// effects between them.
62 ///
63 /// Also, a retain+release pair nested within another retain+release
64 /// pair all on the known same pointer value can be eliminated, regardless
65 /// of any intervening side effects.
66 ///
67 /// KnownSafe is true when either of these conditions is satisfied.
68 bool KnownSafe = false;
69
70 /// True of the objc_release calls are all marked with the "tail" keyword.
71 bool IsTailCallRelease = false;
72
73 /// If the Calls are objc_release calls and they all have a
74 /// clang.imprecise_release tag, this is the metadata tag.
75 MDNode *ReleaseMetadata = nullptr;
76
77 /// For a top-down sequence, the set of objc_retains or
78 /// objc_retainBlocks. For bottom-up, the set of objc_releases.
79 SmallPtrSet<Instruction *, 2> Calls;
80
81 /// The set of optimal insert positions for moving calls in the opposite
82 /// sequence.
83 SmallPtrSet<Instruction *, 2> ReverseInsertPts;
84
85 /// If this is true, we cannot perform code motion but can still remove
86 /// retain/release pairs.
87 bool CFGHazardAfflicted = false;
88
89 RRInfo() = default;
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/// This class summarizes several per-pointer runtime properties which
99/// are propagated through the flow graph.
100class PtrState {
101protected:
102 /// True if the reference count is known to be incremented.
103 bool KnownPositiveRefCount = false;
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 = false;
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 PtrState() : Seq(S_None) {}
116
117public:
118 bool IsKnownSafe() const { return RRI.KnownSafe; }
119
120 void SetKnownSafe(const bool NewValue) { RRI.KnownSafe = NewValue; }
121
122 bool IsTailCallRelease() const { return RRI.IsTailCallRelease; }
123
124 void SetTailCallRelease(const bool NewValue) {
125 RRI.IsTailCallRelease = NewValue;
126 }
127
128 bool IsTrackingImpreciseReleases() const {
129 return RRI.ReleaseMetadata != nullptr;
130 }
131
132 const MDNode *GetReleaseMetadata() const { return RRI.ReleaseMetadata; }
133
134 void SetReleaseMetadata(MDNode *NewValue) { RRI.ReleaseMetadata = NewValue; }
135
136 bool IsCFGHazardAfflicted() const { return RRI.CFGHazardAfflicted; }
137
138 void SetCFGHazardAfflicted(const bool NewValue) {
139 RRI.CFGHazardAfflicted = NewValue;
140 }
141
142 void SetKnownPositiveRefCount();
143 void ClearKnownPositiveRefCount();
144
145 bool HasKnownPositiveRefCount() const { return KnownPositiveRefCount; }
146
147 void SetSeq(Sequence NewSeq);
148
149 Sequence GetSeq() const { return static_cast<Sequence>(Seq); }
150
151 void ClearSequenceProgress() { ResetSequenceProgress(NewSeq: S_None); }
152
153 void ResetSequenceProgress(Sequence NewSeq);
154 void Merge(const PtrState &Other, bool TopDown);
155
156 void InsertCall(Instruction *I) { RRI.Calls.insert(Ptr: I); }
157
158 void InsertReverseInsertPt(Instruction *I) { RRI.ReverseInsertPts.insert(Ptr: I); }
159
160 void ClearReverseInsertPts() { RRI.ReverseInsertPts.clear(); }
161
162 bool HasReverseInsertPts() const { return !RRI.ReverseInsertPts.empty(); }
163
164 const RRInfo &GetRRInfo() const { return RRI; }
165};
166
167struct BottomUpPtrState : PtrState {
168 BottomUpPtrState() = default;
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
188struct TopDownPtrState : PtrState {
189 TopDownPtrState() = default;
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 const BundledRetainClaimRVs &BundledRVs);
206};
207
208} // end namespace objcarc
209
210} // end namespace llvm
211
212#endif // LLVM_LIB_TRANSFORMS_OBJCARC_PTRSTATE_H
213