xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/ObjCARC/PtrState.h (revision fe6060f10f634930ff71b7c50291ddc610da2475)
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