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