|  | //===--- 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 "llvm/ADT/SmallPtrSet.h" | 
|  | #include "llvm/Analysis/ObjCARCInstKind.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 propagated 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 occurred 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 | 
|  | /// occurred. | 
|  | 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 |