forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			211 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			211 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===--- PtrState.h - ARC State for a Ptr -------------------*- C++ -*-----===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| //  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/IR/Instruction.h"
 | |
| #include "llvm/IR/Value.h"
 | |
| #include "llvm/Support/Debug.h"
 | |
| #include "llvm/Support/raw_ostream.h"
 | |
| 
 | |
| namespace llvm {
 | |
| namespace objcarc {
 | |
| 
 | |
| class ARCMDKindCache;
 | |
| class ProvenanceAnalysis;
 | |
| 
 | |
| /// \enum Sequence
 | |
| ///
 | |
| /// \brief 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,          ///< like S_Release, but code motion is stopped.
 | |
|   S_Release,       ///< objc_release(x).
 | |
|   S_MovableRelease ///< objc_release(x), !clang.imprecise_release.
 | |
| };
 | |
| 
 | |
| raw_ostream &operator<<(raw_ostream &OS,
 | |
|                         const Sequence S) LLVM_ATTRIBUTE_UNUSED;
 | |
| 
 | |
| /// \brief 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;
 | |
| 
 | |
|   /// True of the objc_release calls are all marked with the "tail" keyword.
 | |
|   bool IsTailCallRelease;
 | |
| 
 | |
|   /// If the Calls are objc_release calls and they all have a
 | |
|   /// clang.imprecise_release tag, this is the metadata tag.
 | |
|   MDNode *ReleaseMetadata;
 | |
| 
 | |
|   /// 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;
 | |
| 
 | |
|   RRInfo()
 | |
|       : KnownSafe(false), IsTailCallRelease(false), ReleaseMetadata(nullptr),
 | |
|         CFGHazardAfflicted(false) {}
 | |
| 
 | |
|   void clear();
 | |
| 
 | |
|   /// Conservatively merge the two RRInfo. Returns true if a partial merge has
 | |
|   /// occurred, false otherwise.
 | |
|   bool Merge(const RRInfo &Other);
 | |
| };
 | |
| 
 | |
| /// \brief 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;
 | |
| 
 | |
|   /// 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;
 | |
| 
 | |
|   /// The current position in the sequence.
 | |
|   unsigned char Seq : 8;
 | |
| 
 | |
|   /// Unidirectional information about the current sequence.
 | |
|   RRInfo RRI;
 | |
| 
 | |
|   PtrState() : KnownPositiveRefCount(false), Partial(false), 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() : PtrState() {}
 | |
| 
 | |
|   /// (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() : PtrState() {}
 | |
| 
 | |
|   /// (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);
 | |
| };
 | |
| 
 | |
| } // end namespace objcarc
 | |
| } // end namespace llvm
 | |
| 
 | |
| #endif
 |