| //===- PtrState.h - ARC State for a Ptr -------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // 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/Support/Compiler.h" |
| |
| namespace llvm { |
| |
| class BasicBlock; |
| class Instruction; |
| class MDNode; |
| class raw_ostream; |
| class Value; |
| |
| namespace objcarc { |
| |
| class ARCMDKindCache; |
| class BundledRetainClaimRVs; |
| class ProvenanceAnalysis; |
| |
| /// \enum Sequence |
| /// |
| /// 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, ///< code motion is stopped. |
| S_MovableRelease ///< objc_release(x), !clang.imprecise_release. |
| }; |
| |
| raw_ostream &operator<<(raw_ostream &OS, |
| const Sequence S) LLVM_ATTRIBUTE_UNUSED; |
| |
| /// 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 = false; |
| |
| /// True of the objc_release calls are all marked with the "tail" keyword. |
| bool IsTailCallRelease = false; |
| |
| /// If the Calls are objc_release calls and they all have a |
| /// clang.imprecise_release tag, this is the metadata tag. |
| MDNode *ReleaseMetadata = nullptr; |
| |
| /// 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 = false; |
| |
| RRInfo() = default; |
| |
| void clear(); |
| |
| /// Conservatively merge the two RRInfo. Returns true if a partial merge has |
| /// occurred, false otherwise. |
| bool Merge(const RRInfo &Other); |
| }; |
| |
| /// 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 = false; |
| |
| /// 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 = false; |
| |
| /// The current position in the sequence. |
| unsigned char Seq : 8; |
| |
| /// Unidirectional information about the current sequence. |
| RRInfo RRI; |
| |
| PtrState() : 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() = default; |
| |
| /// (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() = default; |
| |
| /// (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, |
| const BundledRetainClaimRVs &BundledRVs); |
| }; |
| |
| } // end namespace objcarc |
| |
| } // end namespace llvm |
| |
| #endif // LLVM_LIB_TRANSFORMS_OBJCARC_PTRSTATE_H |