blob: 2b647689368e07632c6e5b4d242017c4befa52e1 [file] [log] [blame]
Michael Gottesman68b91db2015-03-05 23:29:03 +00001//===--- 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
Michael Gottesmand45907b2015-03-05 23:57:07 +000010#define DEBUG_TYPE "objc-arc-ptr-state"
11#include "llvm/Support/Debug.h"
Michael Gottesman68b91db2015-03-05 23:29:03 +000012#include "PtrState.h"
13
14using namespace llvm;
15using namespace llvm::objcarc;
16
Michael Gottesmand45907b2015-03-05 23:57:07 +000017raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS, const Sequence S) {
Michael Gottesman68b91db2015-03-05 23:29:03 +000018 switch (S) {
19 case S_None:
20 return OS << "S_None";
21 case S_Retain:
22 return OS << "S_Retain";
23 case S_CanRelease:
24 return OS << "S_CanRelease";
25 case S_Use:
26 return OS << "S_Use";
27 case S_Release:
28 return OS << "S_Release";
29 case S_MovableRelease:
30 return OS << "S_MovableRelease";
31 case S_Stop:
32 return OS << "S_Stop";
33 }
34 llvm_unreachable("Unknown sequence type.");
35}
36
37static Sequence MergeSeqs(Sequence A, Sequence B, bool TopDown) {
38 // The easy cases.
39 if (A == B)
40 return A;
41 if (A == S_None || B == S_None)
42 return S_None;
43
44 if (A > B)
45 std::swap(A, B);
46 if (TopDown) {
47 // Choose the side which is further along in the sequence.
48 if ((A == S_Retain || A == S_CanRelease) &&
49 (B == S_CanRelease || B == S_Use))
50 return B;
51 } else {
52 // Choose the side which is further along in the sequence.
53 if ((A == S_Use || A == S_CanRelease) &&
54 (B == S_Use || B == S_Release || B == S_Stop || B == S_MovableRelease))
55 return A;
56 // If both sides are releases, choose the more conservative one.
57 if (A == S_Stop && (B == S_Release || B == S_MovableRelease))
58 return A;
59 if (A == S_Release && B == S_MovableRelease)
60 return A;
61 }
62
63 return S_None;
64}
65
66void RRInfo::clear() {
67 KnownSafe = false;
68 IsTailCallRelease = false;
69 ReleaseMetadata = nullptr;
70 Calls.clear();
71 ReverseInsertPts.clear();
72 CFGHazardAfflicted = false;
73}
74
75bool RRInfo::Merge(const RRInfo &Other) {
76 // Conservatively merge the ReleaseMetadata information.
77 if (ReleaseMetadata != Other.ReleaseMetadata)
78 ReleaseMetadata = nullptr;
79
80 // Conservatively merge the boolean state.
81 KnownSafe &= Other.KnownSafe;
82 IsTailCallRelease &= Other.IsTailCallRelease;
83 CFGHazardAfflicted |= Other.CFGHazardAfflicted;
84
85 // Merge the call sets.
86 Calls.insert(Other.Calls.begin(), Other.Calls.end());
87
88 // Merge the insert point sets. If there are any differences,
89 // that makes this a partial merge.
90 bool Partial = ReverseInsertPts.size() != Other.ReverseInsertPts.size();
91 for (Instruction *Inst : Other.ReverseInsertPts)
92 Partial |= ReverseInsertPts.insert(Inst).second;
93 return Partial;
94}
95
Michael Gottesmand45907b2015-03-05 23:57:07 +000096void PtrState::SetKnownPositiveRefCount() {
97 DEBUG(dbgs() << "Setting Known Positive.\n");
98 KnownPositiveRefCount = true;
99}
100
101void PtrState::ClearKnownPositiveRefCount() {
102 DEBUG(dbgs() << "Clearing Known Positive.\n");
103 KnownPositiveRefCount = false;
104}
105
106void PtrState::SetSeq(Sequence NewSeq) {
107 DEBUG(dbgs() << "Old: " << Seq << "; New: " << NewSeq << "\n");
108 Seq = NewSeq;
109}
110
111void PtrState::ResetSequenceProgress(Sequence NewSeq) {
112 DEBUG(dbgs() << "Resetting sequence progress.\n");
113 SetSeq(NewSeq);
114 Partial = false;
115 RRI.clear();
116}
117
Michael Gottesman68b91db2015-03-05 23:29:03 +0000118void PtrState::Merge(const PtrState &Other, bool TopDown) {
119 Seq = MergeSeqs(GetSeq(), Other.GetSeq(), TopDown);
120 KnownPositiveRefCount &= Other.KnownPositiveRefCount;
121
122 // If we're not in a sequence (anymore), drop all associated state.
123 if (Seq == S_None) {
124 Partial = false;
125 RRI.clear();
126 } else if (Partial || Other.Partial) {
127 // If we're doing a merge on a path that's previously seen a partial
128 // merge, conservatively drop the sequence, to avoid doing partial
129 // RR elimination. If the branch predicates for the two merge differ,
130 // mixing them is unsafe.
131 ClearSequenceProgress();
132 } else {
133 // Otherwise merge the other PtrState's RRInfo into our RRInfo. At this
134 // point, we know that currently we are not partial. Stash whether or not
135 // the merge operation caused us to undergo a partial merging of reverse
136 // insertion points.
137 Partial = RRI.Merge(Other.RRI);
138 }
139}