blob: 02c58dd3d4afdad4cae5e435e2c1ac5e39ee8215 [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
10#include "PtrState.h"
11
12using namespace llvm;
13using namespace llvm::objcarc;
14
15raw_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
35static 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
64void RRInfo::clear() {
65 KnownSafe = false;
66 IsTailCallRelease = false;
67 ReleaseMetadata = nullptr;
68 Calls.clear();
69 ReverseInsertPts.clear();
70 CFGHazardAfflicted = false;
71}
72
73bool 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
94void 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}