//===--- PtrState.h - ARC State for a Ptr -------------------*- C++ -*-----===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains declarations for the ARC state associated with a ptr. It // is only used by the ARC Sequence Dataflow computation. By separating this // from the actual dataflow, it is easier to consider the mechanics of the ARC // optimization separate from the actual predicates being used. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_TRANSFORMS_OBJCARC_PTRSTATE_H #define LLVM_LIB_TRANSFORMS_OBJCARC_PTRSTATE_H #include "ARCInstKind.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Value.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Debug.h" namespace llvm { namespace objcarc { class ARCMDKindCache; class ProvenanceAnalysis; /// \enum Sequence /// /// \brief A sequence of states that a pointer may go through in which an /// objc_retain and objc_release are actually needed. enum Sequence { S_None, S_Retain, ///< objc_retain(x). S_CanRelease, ///< foo(x) -- x could possibly see a ref count decrement. S_Use, ///< any use of x. S_Stop, ///< like S_Release, but code motion is stopped. S_Release, ///< objc_release(x). S_MovableRelease ///< objc_release(x), !clang.imprecise_release. }; raw_ostream &operator<<(raw_ostream &OS, const Sequence S) LLVM_ATTRIBUTE_UNUSED; /// \brief Unidirectional information about either a /// retain-decrement-use-release sequence or release-use-decrement-retain /// reverse sequence. struct RRInfo { /// After an objc_retain, the reference count of the referenced /// object is known to be positive. Similarly, before an objc_release, the /// reference count of the referenced object is known to be positive. If /// there are retain-release pairs in code regions where the retain count /// is known to be positive, they can be eliminated, regardless of any side /// effects between them. /// /// Also, a retain+release pair nested within another retain+release /// pair all on the known same pointer value can be eliminated, regardless /// of any intervening side effects. /// /// KnownSafe is true when either of these conditions is satisfied. bool KnownSafe; /// True of the objc_release calls are all marked with the "tail" keyword. bool IsTailCallRelease; /// If the Calls are objc_release calls and they all have a /// clang.imprecise_release tag, this is the metadata tag. MDNode *ReleaseMetadata; /// For a top-down sequence, the set of objc_retains or /// objc_retainBlocks. For bottom-up, the set of objc_releases. SmallPtrSet<Instruction *, 2> Calls; /// The set of optimal insert positions for moving calls in the opposite /// sequence. SmallPtrSet<Instruction *, 2> ReverseInsertPts; /// If this is true, we cannot perform code motion but can still remove /// retain/release pairs. bool CFGHazardAfflicted; RRInfo() : KnownSafe(false), IsTailCallRelease(false), ReleaseMetadata(nullptr), CFGHazardAfflicted(false) {} void clear(); /// Conservatively merge the two RRInfo. Returns true if a partial merge has /// occurred, false otherwise. bool Merge(const RRInfo &Other); }; /// \brief This class summarizes several per-pointer runtime properties which /// are propogated through the flow graph. class PtrState { protected: /// True if the reference count is known to be incremented. bool KnownPositiveRefCount; /// True if we've seen an opportunity for partial RR elimination, such as /// pushing calls into a CFG triangle or into one side of a CFG diamond. bool Partial; /// The current position in the sequence. unsigned char Seq : 8; /// Unidirectional information about the current sequence. RRInfo RRI; PtrState() : KnownPositiveRefCount(false), Partial(false), Seq(S_None) {} public: bool IsKnownSafe() const { return RRI.KnownSafe; } void SetKnownSafe(const bool NewValue) { RRI.KnownSafe = NewValue; } bool IsTailCallRelease() const { return RRI.IsTailCallRelease; } void SetTailCallRelease(const bool NewValue) { RRI.IsTailCallRelease = NewValue; } bool IsTrackingImpreciseReleases() const { return RRI.ReleaseMetadata != nullptr; } const MDNode *GetReleaseMetadata() const { return RRI.ReleaseMetadata; } void SetReleaseMetadata(MDNode *NewValue) { RRI.ReleaseMetadata = NewValue; } bool IsCFGHazardAfflicted() const { return RRI.CFGHazardAfflicted; } void SetCFGHazardAfflicted(const bool NewValue) { RRI.CFGHazardAfflicted = NewValue; } void SetKnownPositiveRefCount(); void ClearKnownPositiveRefCount(); bool HasKnownPositiveRefCount() const { return KnownPositiveRefCount; } void SetSeq(Sequence NewSeq); Sequence GetSeq() const { return static_cast<Sequence>(Seq); } void ClearSequenceProgress() { ResetSequenceProgress(S_None); } void ResetSequenceProgress(Sequence NewSeq); void Merge(const PtrState &Other, bool TopDown); void InsertCall(Instruction *I) { RRI.Calls.insert(I); } void InsertReverseInsertPt(Instruction *I) { RRI.ReverseInsertPts.insert(I); } void ClearReverseInsertPts() { RRI.ReverseInsertPts.clear(); } bool HasReverseInsertPts() const { return !RRI.ReverseInsertPts.empty(); } const RRInfo &GetRRInfo() const { return RRI; } }; struct BottomUpPtrState : PtrState { BottomUpPtrState() : PtrState() {} /// (Re-)Initialize this bottom up pointer returning true if we detected a /// pointer with nested releases. bool InitBottomUp(ARCMDKindCache &Cache, Instruction *I); /// Return true if this set of releases can be paired with a release. Modifies /// state appropriately to reflect that the matching occured if it is /// successful. /// /// It is assumed that one has already checked that the RCIdentity of the /// retain and the RCIdentity of this ptr state are the same. bool MatchWithRetain(); void HandlePotentialUse(BasicBlock *BB, Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class); bool HandlePotentialAlterRefCount(Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class); }; struct TopDownPtrState : PtrState { TopDownPtrState() : PtrState() {} /// (Re-)Initialize this bottom up pointer returning true if we detected a /// pointer with nested releases. bool InitTopDown(ARCInstKind Kind, Instruction *I); /// Return true if this set of retains can be paired with the given /// release. Modifies state appropriately to reflect that the matching /// occured. bool MatchWithRelease(ARCMDKindCache &Cache, Instruction *Release); void HandlePotentialUse(Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class); bool HandlePotentialAlterRefCount(Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class); }; } // end namespace objcarc } // end namespace llvm #endif