213 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file contains declarations for the ARC state associated with a ptr. It10// is only used by the ARC Sequence Dataflow computation. By separating this11// from the actual dataflow, it is easier to consider the mechanics of the ARC12// optimization separate from the actual predicates being used.13//14//===----------------------------------------------------------------------===//15 16#ifndef LLVM_LIB_TRANSFORMS_OBJCARC_PTRSTATE_H17#define LLVM_LIB_TRANSFORMS_OBJCARC_PTRSTATE_H18 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 Sequence38///39/// A sequence of states that a pointer may go through in which an40/// 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 a53/// retain-decrement-use-release sequence or release-use-decrement-retain54/// reverse sequence.55struct RRInfo {56 /// After an objc_retain, the reference count of the referenced57 /// object is known to be positive. Similarly, before an objc_release, the58 /// reference count of the referenced object is known to be positive. If59 /// there are retain-release pairs in code regions where the retain count60 /// is known to be positive, they can be eliminated, regardless of any side61 /// effects between them.62 ///63 /// Also, a retain+release pair nested within another retain+release64 /// pair all on the known same pointer value can be eliminated, regardless65 /// 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 a74 /// 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 or78 /// 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 opposite82 /// sequence.83 SmallPtrSet<Instruction *, 2> ReverseInsertPts;84 85 /// If this is true, we cannot perform code motion but can still remove86 /// 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 has94 /// occurred, false otherwise.95 bool Merge(const RRInfo &Other);96};97 98/// This class summarizes several per-pointer runtime properties which99/// 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 as106 /// 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(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() = default;169 170 /// (Re-)Initialize this bottom up pointer returning true if we detected a171 /// 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. Modifies175 /// state appropriately to reflect that the matching occurred if it is176 /// successful.177 ///178 /// It is assumed that one has already checked that the RCIdentity of the179 /// 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 a192 /// 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 given196 /// release. Modifies state appropriately to reflect that the matching197 /// 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 objcarc209 210} // end namespace llvm211 212#endif // LLVM_LIB_TRANSFORMS_OBJCARC_PTRSTATE_H213