Home | History | Annotate | Download | only in ObjCARC
      1 //===--- PtrState.h - ARC State for a Ptr -------------------*- C++ -*-----===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 //  This file contains declarations for the ARC state associated with a ptr. It
     11 //  is only used by the ARC Sequence Dataflow computation. By separating this
     12 //  from the actual dataflow, it is easier to consider the mechanics of the ARC
     13 //  optimization separate from the actual predicates being used.
     14 //
     15 //===----------------------------------------------------------------------===//
     16 
     17 #ifndef LLVM_LIB_TRANSFORMS_OBJCARC_PTRSTATE_H
     18 #define LLVM_LIB_TRANSFORMS_OBJCARC_PTRSTATE_H
     19 
     20 #include "llvm/ADT/SmallPtrSet.h"
     21 #include "llvm/Analysis/ObjCARCInstKind.h"
     22 #include "llvm/IR/Instruction.h"
     23 #include "llvm/IR/Value.h"
     24 #include "llvm/Support/raw_ostream.h"
     25 #include "llvm/Support/Debug.h"
     26 
     27 namespace llvm {
     28 namespace objcarc {
     29 
     30 class ARCMDKindCache;
     31 class ProvenanceAnalysis;
     32 
     33 /// \enum Sequence
     34 ///
     35 /// \brief A sequence of states that a pointer may go through in which an
     36 /// objc_retain and objc_release are actually needed.
     37 enum Sequence {
     38   S_None,
     39   S_Retain,        ///< objc_retain(x).
     40   S_CanRelease,    ///< foo(x) -- x could possibly see a ref count decrement.
     41   S_Use,           ///< any use of x.
     42   S_Stop,          ///< like S_Release, but code motion is stopped.
     43   S_Release,       ///< objc_release(x).
     44   S_MovableRelease ///< objc_release(x), !clang.imprecise_release.
     45 };
     46 
     47 raw_ostream &operator<<(raw_ostream &OS,
     48                         const Sequence S) LLVM_ATTRIBUTE_UNUSED;
     49 
     50 /// \brief Unidirectional information about either a
     51 /// retain-decrement-use-release sequence or release-use-decrement-retain
     52 /// reverse sequence.
     53 struct RRInfo {
     54   /// After an objc_retain, the reference count of the referenced
     55   /// object is known to be positive. Similarly, before an objc_release, the
     56   /// reference count of the referenced object is known to be positive. If
     57   /// there are retain-release pairs in code regions where the retain count
     58   /// is known to be positive, they can be eliminated, regardless of any side
     59   /// effects between them.
     60   ///
     61   /// Also, a retain+release pair nested within another retain+release
     62   /// pair all on the known same pointer value can be eliminated, regardless
     63   /// of any intervening side effects.
     64   ///
     65   /// KnownSafe is true when either of these conditions is satisfied.
     66   bool KnownSafe;
     67 
     68   /// True of the objc_release calls are all marked with the "tail" keyword.
     69   bool IsTailCallRelease;
     70 
     71   /// If the Calls are objc_release calls and they all have a
     72   /// clang.imprecise_release tag, this is the metadata tag.
     73   MDNode *ReleaseMetadata;
     74 
     75   /// For a top-down sequence, the set of objc_retains or
     76   /// objc_retainBlocks. For bottom-up, the set of objc_releases.
     77   SmallPtrSet<Instruction *, 2> Calls;
     78 
     79   /// The set of optimal insert positions for moving calls in the opposite
     80   /// sequence.
     81   SmallPtrSet<Instruction *, 2> ReverseInsertPts;
     82 
     83   /// If this is true, we cannot perform code motion but can still remove
     84   /// retain/release pairs.
     85   bool CFGHazardAfflicted;
     86 
     87   RRInfo()
     88       : KnownSafe(false), IsTailCallRelease(false), ReleaseMetadata(nullptr),
     89         CFGHazardAfflicted(false) {}
     90 
     91   void clear();
     92 
     93   /// Conservatively merge the two RRInfo. Returns true if a partial merge has
     94   /// occurred, false otherwise.
     95   bool Merge(const RRInfo &Other);
     96 };
     97 
     98 /// \brief This class summarizes several per-pointer runtime properties which
     99 /// are propagated through the flow graph.
    100 class PtrState {
    101 protected:
    102   /// True if the reference count is known to be incremented.
    103   bool KnownPositiveRefCount;
    104 
    105   /// True if we've seen an opportunity for partial RR elimination, such as
    106   /// pushing calls into a CFG triangle or into one side of a CFG diamond.
    107   bool Partial;
    108 
    109   /// The current position in the sequence.
    110   unsigned char Seq : 8;
    111 
    112   /// Unidirectional information about the current sequence.
    113   RRInfo RRI;
    114 
    115   PtrState() : KnownPositiveRefCount(false), Partial(false), Seq(S_None) {}
    116 
    117 public:
    118   bool IsKnownSafe() const { return RRI.KnownSafe; }
    119 
    120   void SetKnownSafe(const bool NewValue) { RRI.KnownSafe = NewValue; }
    121 
    122   bool IsTailCallRelease() const { return RRI.IsTailCallRelease; }
    123 
    124   void SetTailCallRelease(const bool NewValue) {
    125     RRI.IsTailCallRelease = NewValue;
    126   }
    127 
    128   bool IsTrackingImpreciseReleases() const {
    129     return RRI.ReleaseMetadata != nullptr;
    130   }
    131 
    132   const MDNode *GetReleaseMetadata() const { return RRI.ReleaseMetadata; }
    133 
    134   void SetReleaseMetadata(MDNode *NewValue) { RRI.ReleaseMetadata = NewValue; }
    135 
    136   bool IsCFGHazardAfflicted() const { return RRI.CFGHazardAfflicted; }
    137 
    138   void SetCFGHazardAfflicted(const bool NewValue) {
    139     RRI.CFGHazardAfflicted = NewValue;
    140   }
    141 
    142   void SetKnownPositiveRefCount();
    143   void ClearKnownPositiveRefCount();
    144 
    145   bool HasKnownPositiveRefCount() const { return KnownPositiveRefCount; }
    146 
    147   void SetSeq(Sequence NewSeq);
    148 
    149   Sequence GetSeq() const { return static_cast<Sequence>(Seq); }
    150 
    151   void ClearSequenceProgress() { ResetSequenceProgress(S_None); }
    152 
    153   void ResetSequenceProgress(Sequence NewSeq);
    154   void Merge(const PtrState &Other, bool TopDown);
    155 
    156   void InsertCall(Instruction *I) { RRI.Calls.insert(I); }
    157 
    158   void InsertReverseInsertPt(Instruction *I) { RRI.ReverseInsertPts.insert(I); }
    159 
    160   void ClearReverseInsertPts() { RRI.ReverseInsertPts.clear(); }
    161 
    162   bool HasReverseInsertPts() const { return !RRI.ReverseInsertPts.empty(); }
    163 
    164   const RRInfo &GetRRInfo() const { return RRI; }
    165 };
    166 
    167 struct BottomUpPtrState : PtrState {
    168   BottomUpPtrState() : PtrState() {}
    169 
    170   /// (Re-)Initialize this bottom up pointer returning true if we detected a
    171   /// pointer with nested releases.
    172   bool InitBottomUp(ARCMDKindCache &Cache, Instruction *I);
    173 
    174   /// Return true if this set of releases can be paired with a release. Modifies
    175   /// state appropriately to reflect that the matching occurred if it is
    176   /// successful.
    177   ///
    178   /// It is assumed that one has already checked that the RCIdentity of the
    179   /// retain and the RCIdentity of this ptr state are the same.
    180   bool MatchWithRetain();
    181 
    182   void HandlePotentialUse(BasicBlock *BB, Instruction *Inst, const Value *Ptr,
    183                           ProvenanceAnalysis &PA, ARCInstKind Class);
    184   bool HandlePotentialAlterRefCount(Instruction *Inst, const Value *Ptr,
    185                                     ProvenanceAnalysis &PA, ARCInstKind Class);
    186 };
    187 
    188 struct TopDownPtrState : PtrState {
    189   TopDownPtrState() : PtrState() {}
    190 
    191   /// (Re-)Initialize this bottom up pointer returning true if we detected a
    192   /// pointer with nested releases.
    193   bool InitTopDown(ARCInstKind Kind, Instruction *I);
    194 
    195   /// Return true if this set of retains can be paired with the given
    196   /// release. Modifies state appropriately to reflect that the matching
    197   /// occurred.
    198   bool MatchWithRelease(ARCMDKindCache &Cache, Instruction *Release);
    199 
    200   void HandlePotentialUse(Instruction *Inst, const Value *Ptr,
    201                           ProvenanceAnalysis &PA, ARCInstKind Class);
    202 
    203   bool HandlePotentialAlterRefCount(Instruction *Inst, const Value *Ptr,
    204                                     ProvenanceAnalysis &PA, ARCInstKind Class);
    205 };
    206 
    207 } // end namespace objcarc
    208 } // end namespace llvm
    209 
    210 #endif
    211