10b57cec5SDimitry Andric //===- PtrState.h - ARC State for a Ptr -------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file contains declarations for the ARC state associated with a ptr. It 100b57cec5SDimitry Andric // is only used by the ARC Sequence Dataflow computation. By separating this 110b57cec5SDimitry Andric // from the actual dataflow, it is easier to consider the mechanics of the ARC 120b57cec5SDimitry Andric // optimization separate from the actual predicates being used. 130b57cec5SDimitry Andric // 140b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric #ifndef LLVM_LIB_TRANSFORMS_OBJCARC_PTRSTATE_H 170b57cec5SDimitry Andric #define LLVM_LIB_TRANSFORMS_OBJCARC_PTRSTATE_H 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 200b57cec5SDimitry Andric #include "llvm/Analysis/ObjCARCInstKind.h" 210b57cec5SDimitry Andric #include "llvm/Support/Compiler.h" 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric namespace llvm { 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric class BasicBlock; 260b57cec5SDimitry Andric class Instruction; 270b57cec5SDimitry Andric class MDNode; 280b57cec5SDimitry Andric class raw_ostream; 290b57cec5SDimitry Andric class Value; 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric namespace objcarc { 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric class ARCMDKindCache; 34*fe6060f1SDimitry Andric class BundledRetainClaimRVs; 350b57cec5SDimitry Andric class ProvenanceAnalysis; 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric /// \enum Sequence 380b57cec5SDimitry Andric /// 390b57cec5SDimitry Andric /// A sequence of states that a pointer may go through in which an 400b57cec5SDimitry Andric /// objc_retain and objc_release are actually needed. 410b57cec5SDimitry Andric enum Sequence { 420b57cec5SDimitry Andric S_None, 430b57cec5SDimitry Andric S_Retain, ///< objc_retain(x). 440b57cec5SDimitry Andric S_CanRelease, ///< foo(x) -- x could possibly see a ref count decrement. 450b57cec5SDimitry Andric S_Use, ///< any use of x. 46*fe6060f1SDimitry Andric S_Stop, ///< code motion is stopped. 470b57cec5SDimitry Andric S_MovableRelease ///< objc_release(x), !clang.imprecise_release. 480b57cec5SDimitry Andric }; 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric raw_ostream &operator<<(raw_ostream &OS, 510b57cec5SDimitry Andric const Sequence S) LLVM_ATTRIBUTE_UNUSED; 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric /// Unidirectional information about either a 540b57cec5SDimitry Andric /// retain-decrement-use-release sequence or release-use-decrement-retain 550b57cec5SDimitry Andric /// reverse sequence. 560b57cec5SDimitry Andric struct RRInfo { 570b57cec5SDimitry Andric /// After an objc_retain, the reference count of the referenced 580b57cec5SDimitry Andric /// object is known to be positive. Similarly, before an objc_release, the 590b57cec5SDimitry Andric /// reference count of the referenced object is known to be positive. If 600b57cec5SDimitry Andric /// there are retain-release pairs in code regions where the retain count 610b57cec5SDimitry Andric /// is known to be positive, they can be eliminated, regardless of any side 620b57cec5SDimitry Andric /// effects between them. 630b57cec5SDimitry Andric /// 640b57cec5SDimitry Andric /// Also, a retain+release pair nested within another retain+release 650b57cec5SDimitry Andric /// pair all on the known same pointer value can be eliminated, regardless 660b57cec5SDimitry Andric /// of any intervening side effects. 670b57cec5SDimitry Andric /// 680b57cec5SDimitry Andric /// KnownSafe is true when either of these conditions is satisfied. 690b57cec5SDimitry Andric bool KnownSafe = false; 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric /// True of the objc_release calls are all marked with the "tail" keyword. 720b57cec5SDimitry Andric bool IsTailCallRelease = false; 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric /// If the Calls are objc_release calls and they all have a 750b57cec5SDimitry Andric /// clang.imprecise_release tag, this is the metadata tag. 760b57cec5SDimitry Andric MDNode *ReleaseMetadata = nullptr; 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric /// For a top-down sequence, the set of objc_retains or 790b57cec5SDimitry Andric /// objc_retainBlocks. For bottom-up, the set of objc_releases. 800b57cec5SDimitry Andric SmallPtrSet<Instruction *, 2> Calls; 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric /// The set of optimal insert positions for moving calls in the opposite 830b57cec5SDimitry Andric /// sequence. 840b57cec5SDimitry Andric SmallPtrSet<Instruction *, 2> ReverseInsertPts; 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric /// If this is true, we cannot perform code motion but can still remove 870b57cec5SDimitry Andric /// retain/release pairs. 880b57cec5SDimitry Andric bool CFGHazardAfflicted = false; 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric RRInfo() = default; 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric void clear(); 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric /// Conservatively merge the two RRInfo. Returns true if a partial merge has 950b57cec5SDimitry Andric /// occurred, false otherwise. 960b57cec5SDimitry Andric bool Merge(const RRInfo &Other); 970b57cec5SDimitry Andric }; 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric /// This class summarizes several per-pointer runtime properties which 1000b57cec5SDimitry Andric /// are propagated through the flow graph. 1010b57cec5SDimitry Andric class PtrState { 1020b57cec5SDimitry Andric protected: 1030b57cec5SDimitry Andric /// True if the reference count is known to be incremented. 1040b57cec5SDimitry Andric bool KnownPositiveRefCount = false; 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric /// True if we've seen an opportunity for partial RR elimination, such as 1070b57cec5SDimitry Andric /// pushing calls into a CFG triangle or into one side of a CFG diamond. 1080b57cec5SDimitry Andric bool Partial = false; 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric /// The current position in the sequence. 1110b57cec5SDimitry Andric unsigned char Seq : 8; 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric /// Unidirectional information about the current sequence. 1140b57cec5SDimitry Andric RRInfo RRI; 1150b57cec5SDimitry Andric PtrState()1160b57cec5SDimitry Andric PtrState() : Seq(S_None) {} 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric public: IsKnownSafe()1190b57cec5SDimitry Andric bool IsKnownSafe() const { return RRI.KnownSafe; } 1200b57cec5SDimitry Andric SetKnownSafe(const bool NewValue)1210b57cec5SDimitry Andric void SetKnownSafe(const bool NewValue) { RRI.KnownSafe = NewValue; } 1220b57cec5SDimitry Andric IsTailCallRelease()1230b57cec5SDimitry Andric bool IsTailCallRelease() const { return RRI.IsTailCallRelease; } 1240b57cec5SDimitry Andric SetTailCallRelease(const bool NewValue)1250b57cec5SDimitry Andric void SetTailCallRelease(const bool NewValue) { 1260b57cec5SDimitry Andric RRI.IsTailCallRelease = NewValue; 1270b57cec5SDimitry Andric } 1280b57cec5SDimitry Andric IsTrackingImpreciseReleases()1290b57cec5SDimitry Andric bool IsTrackingImpreciseReleases() const { 1300b57cec5SDimitry Andric return RRI.ReleaseMetadata != nullptr; 1310b57cec5SDimitry Andric } 1320b57cec5SDimitry Andric GetReleaseMetadata()1330b57cec5SDimitry Andric const MDNode *GetReleaseMetadata() const { return RRI.ReleaseMetadata; } 1340b57cec5SDimitry Andric SetReleaseMetadata(MDNode * NewValue)1350b57cec5SDimitry Andric void SetReleaseMetadata(MDNode *NewValue) { RRI.ReleaseMetadata = NewValue; } 1360b57cec5SDimitry Andric IsCFGHazardAfflicted()1370b57cec5SDimitry Andric bool IsCFGHazardAfflicted() const { return RRI.CFGHazardAfflicted; } 1380b57cec5SDimitry Andric SetCFGHazardAfflicted(const bool NewValue)1390b57cec5SDimitry Andric void SetCFGHazardAfflicted(const bool NewValue) { 1400b57cec5SDimitry Andric RRI.CFGHazardAfflicted = NewValue; 1410b57cec5SDimitry Andric } 1420b57cec5SDimitry Andric 1430b57cec5SDimitry Andric void SetKnownPositiveRefCount(); 1440b57cec5SDimitry Andric void ClearKnownPositiveRefCount(); 1450b57cec5SDimitry Andric HasKnownPositiveRefCount()1460b57cec5SDimitry Andric bool HasKnownPositiveRefCount() const { return KnownPositiveRefCount; } 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric void SetSeq(Sequence NewSeq); 1490b57cec5SDimitry Andric GetSeq()1500b57cec5SDimitry Andric Sequence GetSeq() const { return static_cast<Sequence>(Seq); } 1510b57cec5SDimitry Andric ClearSequenceProgress()1520b57cec5SDimitry Andric void ClearSequenceProgress() { ResetSequenceProgress(S_None); } 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric void ResetSequenceProgress(Sequence NewSeq); 1550b57cec5SDimitry Andric void Merge(const PtrState &Other, bool TopDown); 1560b57cec5SDimitry Andric InsertCall(Instruction * I)1570b57cec5SDimitry Andric void InsertCall(Instruction *I) { RRI.Calls.insert(I); } 1580b57cec5SDimitry Andric InsertReverseInsertPt(Instruction * I)1590b57cec5SDimitry Andric void InsertReverseInsertPt(Instruction *I) { RRI.ReverseInsertPts.insert(I); } 1600b57cec5SDimitry Andric ClearReverseInsertPts()1610b57cec5SDimitry Andric void ClearReverseInsertPts() { RRI.ReverseInsertPts.clear(); } 1620b57cec5SDimitry Andric HasReverseInsertPts()1630b57cec5SDimitry Andric bool HasReverseInsertPts() const { return !RRI.ReverseInsertPts.empty(); } 1640b57cec5SDimitry Andric GetRRInfo()1650b57cec5SDimitry Andric const RRInfo &GetRRInfo() const { return RRI; } 1660b57cec5SDimitry Andric }; 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric struct BottomUpPtrState : PtrState { 1690b57cec5SDimitry Andric BottomUpPtrState() = default; 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric /// (Re-)Initialize this bottom up pointer returning true if we detected a 1720b57cec5SDimitry Andric /// pointer with nested releases. 1730b57cec5SDimitry Andric bool InitBottomUp(ARCMDKindCache &Cache, Instruction *I); 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric /// Return true if this set of releases can be paired with a release. Modifies 1760b57cec5SDimitry Andric /// state appropriately to reflect that the matching occurred if it is 1770b57cec5SDimitry Andric /// successful. 1780b57cec5SDimitry Andric /// 1790b57cec5SDimitry Andric /// It is assumed that one has already checked that the RCIdentity of the 1800b57cec5SDimitry Andric /// retain and the RCIdentity of this ptr state are the same. 1810b57cec5SDimitry Andric bool MatchWithRetain(); 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric void HandlePotentialUse(BasicBlock *BB, Instruction *Inst, const Value *Ptr, 1840b57cec5SDimitry Andric ProvenanceAnalysis &PA, ARCInstKind Class); 1850b57cec5SDimitry Andric bool HandlePotentialAlterRefCount(Instruction *Inst, const Value *Ptr, 1860b57cec5SDimitry Andric ProvenanceAnalysis &PA, ARCInstKind Class); 1870b57cec5SDimitry Andric }; 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric struct TopDownPtrState : PtrState { 1900b57cec5SDimitry Andric TopDownPtrState() = default; 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric /// (Re-)Initialize this bottom up pointer returning true if we detected a 1930b57cec5SDimitry Andric /// pointer with nested releases. 1940b57cec5SDimitry Andric bool InitTopDown(ARCInstKind Kind, Instruction *I); 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric /// Return true if this set of retains can be paired with the given 1970b57cec5SDimitry Andric /// release. Modifies state appropriately to reflect that the matching 1980b57cec5SDimitry Andric /// occurred. 1990b57cec5SDimitry Andric bool MatchWithRelease(ARCMDKindCache &Cache, Instruction *Release); 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric void HandlePotentialUse(Instruction *Inst, const Value *Ptr, 2020b57cec5SDimitry Andric ProvenanceAnalysis &PA, ARCInstKind Class); 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric bool HandlePotentialAlterRefCount(Instruction *Inst, const Value *Ptr, 205*fe6060f1SDimitry Andric ProvenanceAnalysis &PA, ARCInstKind Class, 206*fe6060f1SDimitry Andric const BundledRetainClaimRVs &BundledRVs); 2070b57cec5SDimitry Andric }; 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric } // end namespace objcarc 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric } // end namespace llvm 2120b57cec5SDimitry Andric 2130b57cec5SDimitry Andric #endif // LLVM_LIB_TRANSFORMS_OBJCARC_PTRSTATE_H 214