[objc-arc] Extract out state specific to a ref count from the main objc arc sequence...
[oota-llvm.git] / lib / Transforms / ObjCARC / PtrState.cpp
1 //===--- PtrState.cpp -----------------------------------------------------===//
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 #include "PtrState.h"
11
12 using namespace llvm;
13 using namespace llvm::objcarc;
14
15 raw_ostream &operator<<(raw_ostream &OS, const Sequence S) {
16   switch (S) {
17   case S_None:
18     return OS << "S_None";
19   case S_Retain:
20     return OS << "S_Retain";
21   case S_CanRelease:
22     return OS << "S_CanRelease";
23   case S_Use:
24     return OS << "S_Use";
25   case S_Release:
26     return OS << "S_Release";
27   case S_MovableRelease:
28     return OS << "S_MovableRelease";
29   case S_Stop:
30     return OS << "S_Stop";
31   }
32   llvm_unreachable("Unknown sequence type.");
33 }
34
35 static Sequence MergeSeqs(Sequence A, Sequence B, bool TopDown) {
36   // The easy cases.
37   if (A == B)
38     return A;
39   if (A == S_None || B == S_None)
40     return S_None;
41
42   if (A > B)
43     std::swap(A, B);
44   if (TopDown) {
45     // Choose the side which is further along in the sequence.
46     if ((A == S_Retain || A == S_CanRelease) &&
47         (B == S_CanRelease || B == S_Use))
48       return B;
49   } else {
50     // Choose the side which is further along in the sequence.
51     if ((A == S_Use || A == S_CanRelease) &&
52         (B == S_Use || B == S_Release || B == S_Stop || B == S_MovableRelease))
53       return A;
54     // If both sides are releases, choose the more conservative one.
55     if (A == S_Stop && (B == S_Release || B == S_MovableRelease))
56       return A;
57     if (A == S_Release && B == S_MovableRelease)
58       return A;
59   }
60
61   return S_None;
62 }
63
64 void RRInfo::clear() {
65   KnownSafe = false;
66   IsTailCallRelease = false;
67   ReleaseMetadata = nullptr;
68   Calls.clear();
69   ReverseInsertPts.clear();
70   CFGHazardAfflicted = false;
71 }
72
73 bool RRInfo::Merge(const RRInfo &Other) {
74   // Conservatively merge the ReleaseMetadata information.
75   if (ReleaseMetadata != Other.ReleaseMetadata)
76     ReleaseMetadata = nullptr;
77
78   // Conservatively merge the boolean state.
79   KnownSafe &= Other.KnownSafe;
80   IsTailCallRelease &= Other.IsTailCallRelease;
81   CFGHazardAfflicted |= Other.CFGHazardAfflicted;
82
83   // Merge the call sets.
84   Calls.insert(Other.Calls.begin(), Other.Calls.end());
85
86   // Merge the insert point sets. If there are any differences,
87   // that makes this a partial merge.
88   bool Partial = ReverseInsertPts.size() != Other.ReverseInsertPts.size();
89   for (Instruction *Inst : Other.ReverseInsertPts)
90     Partial |= ReverseInsertPts.insert(Inst).second;
91   return Partial;
92 }
93
94 void PtrState::Merge(const PtrState &Other, bool TopDown) {
95   Seq = MergeSeqs(GetSeq(), Other.GetSeq(), TopDown);
96   KnownPositiveRefCount &= Other.KnownPositiveRefCount;
97
98   // If we're not in a sequence (anymore), drop all associated state.
99   if (Seq == S_None) {
100     Partial = false;
101     RRI.clear();
102   } else if (Partial || Other.Partial) {
103     // If we're doing a merge on a path that's previously seen a partial
104     // merge, conservatively drop the sequence, to avoid doing partial
105     // RR elimination. If the branch predicates for the two merge differ,
106     // mixing them is unsafe.
107     ClearSequenceProgress();
108   } else {
109     // Otherwise merge the other PtrState's RRInfo into our RRInfo. At this
110     // point, we know that currently we are not partial. Stash whether or not
111     // the merge operation caused us to undergo a partial merging of reverse
112     // insertion points.
113     Partial = RRI.Merge(Other.RRI);
114   }
115 }