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
27namespace llvm {
28namespace objcarc {
29
30class ARCMDKindCache;
31class 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.
37enum 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
47raw_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.
53struct 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
87  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.
100class PtrState {
101protected:
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
115  PtrState() : KnownPositiveRefCount(false), Partial(false), 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(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(I); }
157
158  void InsertReverseInsertPt(Instruction *I) { RRI.ReverseInsertPts.insert(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() : 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
188struct TopDownPtrState : PtrState {
189  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