106f32e7eSjoerg //===- PtrState.h - ARC State for a Ptr -------------------------*- C++ -*-===// 206f32e7eSjoerg // 306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information. 506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 606f32e7eSjoerg // 706f32e7eSjoerg //===----------------------------------------------------------------------===// 806f32e7eSjoerg // 906f32e7eSjoerg // This file contains declarations for the ARC state associated with a ptr. It 1006f32e7eSjoerg // is only used by the ARC Sequence Dataflow computation. By separating this 1106f32e7eSjoerg // from the actual dataflow, it is easier to consider the mechanics of the ARC 1206f32e7eSjoerg // optimization separate from the actual predicates being used. 1306f32e7eSjoerg // 1406f32e7eSjoerg //===----------------------------------------------------------------------===// 1506f32e7eSjoerg 1606f32e7eSjoerg #ifndef LLVM_LIB_TRANSFORMS_OBJCARC_PTRSTATE_H 1706f32e7eSjoerg #define LLVM_LIB_TRANSFORMS_OBJCARC_PTRSTATE_H 1806f32e7eSjoerg 1906f32e7eSjoerg #include "llvm/ADT/SmallPtrSet.h" 2006f32e7eSjoerg #include "llvm/Analysis/ObjCARCInstKind.h" 2106f32e7eSjoerg #include "llvm/Support/Compiler.h" 2206f32e7eSjoerg 2306f32e7eSjoerg namespace llvm { 2406f32e7eSjoerg 2506f32e7eSjoerg class BasicBlock; 2606f32e7eSjoerg class Instruction; 2706f32e7eSjoerg class MDNode; 2806f32e7eSjoerg class raw_ostream; 2906f32e7eSjoerg class Value; 3006f32e7eSjoerg 3106f32e7eSjoerg namespace objcarc { 3206f32e7eSjoerg 3306f32e7eSjoerg class ARCMDKindCache; 34*da58b97aSjoerg class BundledRetainClaimRVs; 3506f32e7eSjoerg class ProvenanceAnalysis; 3606f32e7eSjoerg 3706f32e7eSjoerg /// \enum Sequence 3806f32e7eSjoerg /// 3906f32e7eSjoerg /// A sequence of states that a pointer may go through in which an 4006f32e7eSjoerg /// objc_retain and objc_release are actually needed. 4106f32e7eSjoerg enum Sequence { 4206f32e7eSjoerg S_None, 4306f32e7eSjoerg S_Retain, ///< objc_retain(x). 4406f32e7eSjoerg S_CanRelease, ///< foo(x) -- x could possibly see a ref count decrement. 4506f32e7eSjoerg S_Use, ///< any use of x. 46*da58b97aSjoerg S_Stop, ///< code motion is stopped. 4706f32e7eSjoerg S_MovableRelease ///< objc_release(x), !clang.imprecise_release. 4806f32e7eSjoerg }; 4906f32e7eSjoerg 5006f32e7eSjoerg raw_ostream &operator<<(raw_ostream &OS, 5106f32e7eSjoerg const Sequence S) LLVM_ATTRIBUTE_UNUSED; 5206f32e7eSjoerg 5306f32e7eSjoerg /// Unidirectional information about either a 5406f32e7eSjoerg /// retain-decrement-use-release sequence or release-use-decrement-retain 5506f32e7eSjoerg /// reverse sequence. 5606f32e7eSjoerg struct RRInfo { 5706f32e7eSjoerg /// After an objc_retain, the reference count of the referenced 5806f32e7eSjoerg /// object is known to be positive. Similarly, before an objc_release, the 5906f32e7eSjoerg /// reference count of the referenced object is known to be positive. If 6006f32e7eSjoerg /// there are retain-release pairs in code regions where the retain count 6106f32e7eSjoerg /// is known to be positive, they can be eliminated, regardless of any side 6206f32e7eSjoerg /// effects between them. 6306f32e7eSjoerg /// 6406f32e7eSjoerg /// Also, a retain+release pair nested within another retain+release 6506f32e7eSjoerg /// pair all on the known same pointer value can be eliminated, regardless 6606f32e7eSjoerg /// of any intervening side effects. 6706f32e7eSjoerg /// 6806f32e7eSjoerg /// KnownSafe is true when either of these conditions is satisfied. 6906f32e7eSjoerg bool KnownSafe = false; 7006f32e7eSjoerg 7106f32e7eSjoerg /// True of the objc_release calls are all marked with the "tail" keyword. 7206f32e7eSjoerg bool IsTailCallRelease = false; 7306f32e7eSjoerg 7406f32e7eSjoerg /// If the Calls are objc_release calls and they all have a 7506f32e7eSjoerg /// clang.imprecise_release tag, this is the metadata tag. 7606f32e7eSjoerg MDNode *ReleaseMetadata = nullptr; 7706f32e7eSjoerg 7806f32e7eSjoerg /// For a top-down sequence, the set of objc_retains or 7906f32e7eSjoerg /// objc_retainBlocks. For bottom-up, the set of objc_releases. 8006f32e7eSjoerg SmallPtrSet<Instruction *, 2> Calls; 8106f32e7eSjoerg 8206f32e7eSjoerg /// The set of optimal insert positions for moving calls in the opposite 8306f32e7eSjoerg /// sequence. 8406f32e7eSjoerg SmallPtrSet<Instruction *, 2> ReverseInsertPts; 8506f32e7eSjoerg 8606f32e7eSjoerg /// If this is true, we cannot perform code motion but can still remove 8706f32e7eSjoerg /// retain/release pairs. 8806f32e7eSjoerg bool CFGHazardAfflicted = false; 8906f32e7eSjoerg 9006f32e7eSjoerg RRInfo() = default; 9106f32e7eSjoerg 9206f32e7eSjoerg void clear(); 9306f32e7eSjoerg 9406f32e7eSjoerg /// Conservatively merge the two RRInfo. Returns true if a partial merge has 9506f32e7eSjoerg /// occurred, false otherwise. 9606f32e7eSjoerg bool Merge(const RRInfo &Other); 9706f32e7eSjoerg }; 9806f32e7eSjoerg 9906f32e7eSjoerg /// This class summarizes several per-pointer runtime properties which 10006f32e7eSjoerg /// are propagated through the flow graph. 10106f32e7eSjoerg class PtrState { 10206f32e7eSjoerg protected: 10306f32e7eSjoerg /// True if the reference count is known to be incremented. 10406f32e7eSjoerg bool KnownPositiveRefCount = false; 10506f32e7eSjoerg 10606f32e7eSjoerg /// True if we've seen an opportunity for partial RR elimination, such as 10706f32e7eSjoerg /// pushing calls into a CFG triangle or into one side of a CFG diamond. 10806f32e7eSjoerg bool Partial = false; 10906f32e7eSjoerg 11006f32e7eSjoerg /// The current position in the sequence. 11106f32e7eSjoerg unsigned char Seq : 8; 11206f32e7eSjoerg 11306f32e7eSjoerg /// Unidirectional information about the current sequence. 11406f32e7eSjoerg RRInfo RRI; 11506f32e7eSjoerg PtrState()11606f32e7eSjoerg PtrState() : Seq(S_None) {} 11706f32e7eSjoerg 11806f32e7eSjoerg public: IsKnownSafe()11906f32e7eSjoerg bool IsKnownSafe() const { return RRI.KnownSafe; } 12006f32e7eSjoerg SetKnownSafe(const bool NewValue)12106f32e7eSjoerg void SetKnownSafe(const bool NewValue) { RRI.KnownSafe = NewValue; } 12206f32e7eSjoerg IsTailCallRelease()12306f32e7eSjoerg bool IsTailCallRelease() const { return RRI.IsTailCallRelease; } 12406f32e7eSjoerg SetTailCallRelease(const bool NewValue)12506f32e7eSjoerg void SetTailCallRelease(const bool NewValue) { 12606f32e7eSjoerg RRI.IsTailCallRelease = NewValue; 12706f32e7eSjoerg } 12806f32e7eSjoerg IsTrackingImpreciseReleases()12906f32e7eSjoerg bool IsTrackingImpreciseReleases() const { 13006f32e7eSjoerg return RRI.ReleaseMetadata != nullptr; 13106f32e7eSjoerg } 13206f32e7eSjoerg GetReleaseMetadata()13306f32e7eSjoerg const MDNode *GetReleaseMetadata() const { return RRI.ReleaseMetadata; } 13406f32e7eSjoerg SetReleaseMetadata(MDNode * NewValue)13506f32e7eSjoerg void SetReleaseMetadata(MDNode *NewValue) { RRI.ReleaseMetadata = NewValue; } 13606f32e7eSjoerg IsCFGHazardAfflicted()13706f32e7eSjoerg bool IsCFGHazardAfflicted() const { return RRI.CFGHazardAfflicted; } 13806f32e7eSjoerg SetCFGHazardAfflicted(const bool NewValue)13906f32e7eSjoerg void SetCFGHazardAfflicted(const bool NewValue) { 14006f32e7eSjoerg RRI.CFGHazardAfflicted = NewValue; 14106f32e7eSjoerg } 14206f32e7eSjoerg 14306f32e7eSjoerg void SetKnownPositiveRefCount(); 14406f32e7eSjoerg void ClearKnownPositiveRefCount(); 14506f32e7eSjoerg HasKnownPositiveRefCount()14606f32e7eSjoerg bool HasKnownPositiveRefCount() const { return KnownPositiveRefCount; } 14706f32e7eSjoerg 14806f32e7eSjoerg void SetSeq(Sequence NewSeq); 14906f32e7eSjoerg GetSeq()15006f32e7eSjoerg Sequence GetSeq() const { return static_cast<Sequence>(Seq); } 15106f32e7eSjoerg ClearSequenceProgress()15206f32e7eSjoerg void ClearSequenceProgress() { ResetSequenceProgress(S_None); } 15306f32e7eSjoerg 15406f32e7eSjoerg void ResetSequenceProgress(Sequence NewSeq); 15506f32e7eSjoerg void Merge(const PtrState &Other, bool TopDown); 15606f32e7eSjoerg InsertCall(Instruction * I)15706f32e7eSjoerg void InsertCall(Instruction *I) { RRI.Calls.insert(I); } 15806f32e7eSjoerg InsertReverseInsertPt(Instruction * I)15906f32e7eSjoerg void InsertReverseInsertPt(Instruction *I) { RRI.ReverseInsertPts.insert(I); } 16006f32e7eSjoerg ClearReverseInsertPts()16106f32e7eSjoerg void ClearReverseInsertPts() { RRI.ReverseInsertPts.clear(); } 16206f32e7eSjoerg HasReverseInsertPts()16306f32e7eSjoerg bool HasReverseInsertPts() const { return !RRI.ReverseInsertPts.empty(); } 16406f32e7eSjoerg GetRRInfo()16506f32e7eSjoerg const RRInfo &GetRRInfo() const { return RRI; } 16606f32e7eSjoerg }; 16706f32e7eSjoerg 16806f32e7eSjoerg struct BottomUpPtrState : PtrState { 16906f32e7eSjoerg BottomUpPtrState() = default; 17006f32e7eSjoerg 17106f32e7eSjoerg /// (Re-)Initialize this bottom up pointer returning true if we detected a 17206f32e7eSjoerg /// pointer with nested releases. 17306f32e7eSjoerg bool InitBottomUp(ARCMDKindCache &Cache, Instruction *I); 17406f32e7eSjoerg 17506f32e7eSjoerg /// Return true if this set of releases can be paired with a release. Modifies 17606f32e7eSjoerg /// state appropriately to reflect that the matching occurred if it is 17706f32e7eSjoerg /// successful. 17806f32e7eSjoerg /// 17906f32e7eSjoerg /// It is assumed that one has already checked that the RCIdentity of the 18006f32e7eSjoerg /// retain and the RCIdentity of this ptr state are the same. 18106f32e7eSjoerg bool MatchWithRetain(); 18206f32e7eSjoerg 18306f32e7eSjoerg void HandlePotentialUse(BasicBlock *BB, Instruction *Inst, const Value *Ptr, 18406f32e7eSjoerg ProvenanceAnalysis &PA, ARCInstKind Class); 18506f32e7eSjoerg bool HandlePotentialAlterRefCount(Instruction *Inst, const Value *Ptr, 18606f32e7eSjoerg ProvenanceAnalysis &PA, ARCInstKind Class); 18706f32e7eSjoerg }; 18806f32e7eSjoerg 18906f32e7eSjoerg struct TopDownPtrState : PtrState { 19006f32e7eSjoerg TopDownPtrState() = default; 19106f32e7eSjoerg 19206f32e7eSjoerg /// (Re-)Initialize this bottom up pointer returning true if we detected a 19306f32e7eSjoerg /// pointer with nested releases. 19406f32e7eSjoerg bool InitTopDown(ARCInstKind Kind, Instruction *I); 19506f32e7eSjoerg 19606f32e7eSjoerg /// Return true if this set of retains can be paired with the given 19706f32e7eSjoerg /// release. Modifies state appropriately to reflect that the matching 19806f32e7eSjoerg /// occurred. 19906f32e7eSjoerg bool MatchWithRelease(ARCMDKindCache &Cache, Instruction *Release); 20006f32e7eSjoerg 20106f32e7eSjoerg void HandlePotentialUse(Instruction *Inst, const Value *Ptr, 20206f32e7eSjoerg ProvenanceAnalysis &PA, ARCInstKind Class); 20306f32e7eSjoerg 20406f32e7eSjoerg bool HandlePotentialAlterRefCount(Instruction *Inst, const Value *Ptr, 205*da58b97aSjoerg ProvenanceAnalysis &PA, ARCInstKind Class, 206*da58b97aSjoerg const BundledRetainClaimRVs &BundledRVs); 20706f32e7eSjoerg }; 20806f32e7eSjoerg 20906f32e7eSjoerg } // end namespace objcarc 21006f32e7eSjoerg 21106f32e7eSjoerg } // end namespace llvm 21206f32e7eSjoerg 21306f32e7eSjoerg #endif // LLVM_LIB_TRANSFORMS_OBJCARC_PTRSTATE_H 214