blob: b06027a1847f667a2f3e8e11129d4131a0e4c823 [file] [log] [blame]
Hal Finkel7529c552014-09-02 21:43:13 +00001//===- StratifiedSets.h - Abstract stratified sets implementation. --------===//
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#ifndef LLVM_ADT_STRATIFIEDSETS_H
11#define LLVM_ADT_STRATIFIEDSETS_H
12
13#include "llvm/ADT/DenseMap.h"
14#include "llvm/ADT/Optional.h"
Hal Finkel7529c552014-09-02 21:43:13 +000015#include "llvm/ADT/SmallSet.h"
16#include "llvm/ADT/SmallVector.h"
17#include <bitset>
18#include <cassert>
19#include <cmath>
Hal Finkel7529c552014-09-02 21:43:13 +000020#include <type_traits>
Hal Finkel8d1590d2014-09-02 22:52:30 +000021#include <utility>
Hal Finkel7529c552014-09-02 21:43:13 +000022#include <vector>
23
24namespace llvm {
George Burgess IV1ca8aff2016-07-06 00:36:12 +000025namespace cflaa {
George Burgess IVcae581d2016-04-13 23:27:37 +000026/// An index into Stratified Sets.
Hal Finkel7529c552014-09-02 21:43:13 +000027typedef unsigned StratifiedIndex;
George Burgess IVcae581d2016-04-13 23:27:37 +000028/// NOTE: ^ This can't be a short -- bootstrapping clang has a case where
29/// ~1M sets exist.
Hal Finkel7529c552014-09-02 21:43:13 +000030
31// \brief Container of information related to a value in a StratifiedSet.
32struct StratifiedInfo {
33 StratifiedIndex Index;
George Burgess IVcae581d2016-04-13 23:27:37 +000034 /// For field sensitivity, etc. we can tack fields on here.
Hal Finkel7529c552014-09-02 21:43:13 +000035};
36
George Burgess IVcae581d2016-04-13 23:27:37 +000037/// The number of attributes that StratifiedAttrs should contain. Attributes are
38/// described below, and 32 was an arbitrary choice because it fits nicely in 32
39/// bits (because we use a bitset for StratifiedAttrs).
Hal Finkel981602a2014-09-02 22:26:06 +000040static const unsigned NumStratifiedAttrs = 32;
Hal Finkel7529c552014-09-02 21:43:13 +000041
George Burgess IVcae581d2016-04-13 23:27:37 +000042/// These are attributes that the users of StratifiedSets/StratifiedSetBuilders
43/// may use for various purposes. These also have the special property of that
44/// they are merged down. So, if set A is above set B, and one decides to set an
45/// attribute in set A, then the attribute will automatically be set in set B.
Hal Finkel7529c552014-09-02 21:43:13 +000046typedef std::bitset<NumStratifiedAttrs> StratifiedAttrs;
47
George Burgess IVcae581d2016-04-13 23:27:37 +000048/// A "link" between two StratifiedSets.
Hal Finkel7529c552014-09-02 21:43:13 +000049struct StratifiedLink {
George Burgess IVcae581d2016-04-13 23:27:37 +000050 /// \brief This is a value used to signify "does not exist" where the
51 /// StratifiedIndex type is used.
52 ///
53 /// This is used instead of Optional<StratifiedIndex> because
54 /// Optional<StratifiedIndex> would eat up a considerable amount of extra
55 /// memory, after struct padding/alignment is taken into account.
Hal Finkel1ae325f2014-09-02 23:50:01 +000056 static const StratifiedIndex SetSentinel;
Hal Finkel7529c552014-09-02 21:43:13 +000057
George Burgess IVcae581d2016-04-13 23:27:37 +000058 /// The index for the set "above" current
Hal Finkel7529c552014-09-02 21:43:13 +000059 StratifiedIndex Above;
60
George Burgess IVcae581d2016-04-13 23:27:37 +000061 /// The link for the set "below" current
Hal Finkel7529c552014-09-02 21:43:13 +000062 StratifiedIndex Below;
63
George Burgess IVcae581d2016-04-13 23:27:37 +000064 /// Attributes for these StratifiedSets.
Hal Finkel7529c552014-09-02 21:43:13 +000065 StratifiedAttrs Attrs;
66
67 StratifiedLink() : Above(SetSentinel), Below(SetSentinel) {}
68
69 bool hasBelow() const { return Below != SetSentinel; }
70 bool hasAbove() const { return Above != SetSentinel; }
71
72 void clearBelow() { Below = SetSentinel; }
73 void clearAbove() { Above = SetSentinel; }
74};
75
George Burgess IVcae581d2016-04-13 23:27:37 +000076/// \brief These are stratified sets, as described in "Fast algorithms for
77/// Dyck-CFL-reachability with applications to Alias Analysis" by Zhang Q, Lyu M
78/// R, Yuan H, and Su Z. -- in short, this is meant to represent different sets
79/// of Value*s. If two Value*s are in the same set, or if both sets have
80/// overlapping attributes, then the Value*s are said to alias.
81///
82/// Sets may be related by position, meaning that one set may be considered as
83/// above or below another. In CFL Alias Analysis, this gives us an indication
84/// of how two variables are related; if the set of variable A is below a set
85/// containing variable B, then at some point, a variable that has interacted
86/// with B (or B itself) was either used in order to extract the variable A, or
87/// was used as storage of variable A.
88///
89/// Sets may also have attributes (as noted above). These attributes are
90/// generally used for noting whether a variable in the set has interacted with
91/// a variable whose origins we don't quite know (i.e. globals/arguments), or if
92/// the variable may have had operations performed on it (modified in a function
93/// call). All attributes that exist in a set A must exist in all sets marked as
94/// below set A.
Hal Finkel7529c552014-09-02 21:43:13 +000095template <typename T> class StratifiedSets {
96public:
George Burgess IV60af2262016-06-07 21:41:18 +000097 StratifiedSets() = default;
George Burgess IVfd4e2f72016-06-08 17:56:35 +000098
99 // TODO: Figure out how to make MSVC not call the copy ctor here, and delete
100 // it.
George Burgess IV785f3912016-06-08 17:27:14 +0000101
102 // Can't default these due to compile errors in MSVC2013
103 StratifiedSets(StratifiedSets &&Other) { *this = std::move(Other); }
104 StratifiedSets &operator=(StratifiedSets &&Other) {
105 Values = std::move(Other.Values);
106 Links = std::move(Other.Links);
107 return *this;
108 }
Hal Finkel7529c552014-09-02 21:43:13 +0000109
110 StratifiedSets(DenseMap<T, StratifiedInfo> Map,
111 std::vector<StratifiedLink> Links)
112 : Values(std::move(Map)), Links(std::move(Links)) {}
113
Hal Finkel7529c552014-09-02 21:43:13 +0000114 Optional<StratifiedInfo> find(const T &Elem) const {
115 auto Iter = Values.find(Elem);
George Burgess IVcae581d2016-04-13 23:27:37 +0000116 if (Iter == Values.end())
117 return None;
Hal Finkel7529c552014-09-02 21:43:13 +0000118 return Iter->second;
119 }
120
121 const StratifiedLink &getLink(StratifiedIndex Index) const {
122 assert(inbounds(Index));
123 return Links[Index];
124 }
125
126private:
127 DenseMap<T, StratifiedInfo> Values;
128 std::vector<StratifiedLink> Links;
129
130 bool inbounds(StratifiedIndex Idx) const { return Idx < Links.size(); }
131};
132
George Burgess IVcae581d2016-04-13 23:27:37 +0000133/// Generic Builder class that produces StratifiedSets instances.
134///
135/// The goal of this builder is to efficiently produce correct StratifiedSets
136/// instances. To this end, we use a few tricks:
137/// > Set chains (A method for linking sets together)
138/// > Set remaps (A method for marking a set as an alias [irony?] of another)
139///
140/// ==== Set chains ====
141/// This builder has a notion of some value A being above, below, or with some
142/// other value B:
143/// > The `A above B` relationship implies that there is a reference edge
144/// going from A to B. Namely, it notes that A can store anything in B's set.
145/// > The `A below B` relationship is the opposite of `A above B`. It implies
146/// that there's a dereference edge going from A to B.
147/// > The `A with B` relationship states that there's an assignment edge going
148/// from A to B, and that A and B should be treated as equals.
149///
150/// As an example, take the following code snippet:
151///
152/// %a = alloca i32, align 4
153/// %ap = alloca i32*, align 8
154/// %app = alloca i32**, align 8
155/// store %a, %ap
156/// store %ap, %app
George Burgess IV60af2262016-06-07 21:41:18 +0000157/// %aw = getelementptr %ap, i32 0
George Burgess IVcae581d2016-04-13 23:27:37 +0000158///
George Burgess IV60af2262016-06-07 21:41:18 +0000159/// Given this, the following relations exist:
George Burgess IVcae581d2016-04-13 23:27:37 +0000160/// - %a below %ap & %ap above %a
161/// - %ap below %app & %app above %ap
162/// - %aw with %ap & %ap with %aw
163///
164/// These relations produce the following sets:
165/// [{%a}, {%ap, %aw}, {%app}]
166///
George Burgess IV60af2262016-06-07 21:41:18 +0000167/// ...Which state that the only MayAlias relationship in the above program is
George Burgess IVcae581d2016-04-13 23:27:37 +0000168/// between %ap and %aw.
169///
George Burgess IV60af2262016-06-07 21:41:18 +0000170/// Because LLVM allows arbitrary casts, code like the following needs to be
171/// supported:
172/// %ip = alloca i64, align 8
173/// %ipp = alloca i64*, align 8
174/// %i = bitcast i64** ipp to i64
175/// store i64* %ip, i64** %ipp
176/// store i64 %i, i64* %ip
George Burgess IVcae581d2016-04-13 23:27:37 +0000177///
George Burgess IV60af2262016-06-07 21:41:18 +0000178/// Which, because %ipp ends up *both* above and below %ip, is fun.
George Burgess IVcae581d2016-04-13 23:27:37 +0000179///
George Burgess IV60af2262016-06-07 21:41:18 +0000180/// This is solved by merging %i and %ipp into a single set (...which is the
181/// only way to solve this, since their bit patterns are equivalent). Any sets
182/// that ended up in between %i and %ipp at the time of merging (in this case,
183/// the set containing %ip) also get conservatively merged into the set of %i
184/// and %ipp. In short, the resulting StratifiedSet from the above code would be
185/// {%ip, %ipp, %i}.
George Burgess IVcae581d2016-04-13 23:27:37 +0000186///
187/// ==== Set remaps ====
188/// More of an implementation detail than anything -- when merging sets, we need
189/// to update the numbers of all of the elements mapped to those sets. Rather
190/// than doing this at each merge, we note in the BuilderLink structure that a
191/// remap has occurred, and use this information so we can defer renumbering set
192/// elements until build time.
Hal Finkel7529c552014-09-02 21:43:13 +0000193template <typename T> class StratifiedSetsBuilder {
George Burgess IVcae581d2016-04-13 23:27:37 +0000194 /// \brief Represents a Stratified Set, with information about the Stratified
195 /// Set above it, the set below it, and whether the current set has been
196 /// remapped to another.
Hal Finkel7529c552014-09-02 21:43:13 +0000197 struct BuilderLink {
198 const StratifiedIndex Number;
199
200 BuilderLink(StratifiedIndex N) : Number(N) {
201 Remap = StratifiedLink::SetSentinel;
202 }
203
204 bool hasAbove() const {
205 assert(!isRemapped());
206 return Link.hasAbove();
207 }
208
209 bool hasBelow() const {
210 assert(!isRemapped());
211 return Link.hasBelow();
212 }
213
214 void setBelow(StratifiedIndex I) {
215 assert(!isRemapped());
216 Link.Below = I;
217 }
218
219 void setAbove(StratifiedIndex I) {
220 assert(!isRemapped());
221 Link.Above = I;
222 }
223
224 void clearBelow() {
225 assert(!isRemapped());
226 Link.clearBelow();
227 }
228
229 void clearAbove() {
230 assert(!isRemapped());
231 Link.clearAbove();
232 }
233
234 StratifiedIndex getBelow() const {
235 assert(!isRemapped());
236 assert(hasBelow());
237 return Link.Below;
238 }
239
240 StratifiedIndex getAbove() const {
241 assert(!isRemapped());
242 assert(hasAbove());
243 return Link.Above;
244 }
245
246 StratifiedAttrs &getAttrs() {
247 assert(!isRemapped());
248 return Link.Attrs;
249 }
250
Hal Finkel7529c552014-09-02 21:43:13 +0000251 void setAttrs(const StratifiedAttrs &other) {
252 assert(!isRemapped());
253 Link.Attrs |= other;
254 }
255
256 bool isRemapped() const { return Remap != StratifiedLink::SetSentinel; }
257
George Burgess IVcae581d2016-04-13 23:27:37 +0000258 /// For initial remapping to another set
Hal Finkel7529c552014-09-02 21:43:13 +0000259 void remapTo(StratifiedIndex Other) {
260 assert(!isRemapped());
261 Remap = Other;
262 }
263
264 StratifiedIndex getRemapIndex() const {
265 assert(isRemapped());
266 return Remap;
267 }
268
George Burgess IVcae581d2016-04-13 23:27:37 +0000269 /// Should only be called when we're already remapped.
Hal Finkel7529c552014-09-02 21:43:13 +0000270 void updateRemap(StratifiedIndex Other) {
271 assert(isRemapped());
272 Remap = Other;
273 }
274
George Burgess IVcae581d2016-04-13 23:27:37 +0000275 /// Prefer the above functions to calling things directly on what's returned
276 /// from this -- they guard against unexpected calls when the current
277 /// BuilderLink is remapped.
Hal Finkel7529c552014-09-02 21:43:13 +0000278 const StratifiedLink &getLink() const { return Link; }
279
280 private:
281 StratifiedLink Link;
282 StratifiedIndex Remap;
283 };
284
George Burgess IVcae581d2016-04-13 23:27:37 +0000285 /// \brief This function performs all of the set unioning/value renumbering
286 /// that we've been putting off, and generates a vector<StratifiedLink> that
287 /// may be placed in a StratifiedSets instance.
Hal Finkel7529c552014-09-02 21:43:13 +0000288 void finalizeSets(std::vector<StratifiedLink> &StratLinks) {
289 DenseMap<StratifiedIndex, StratifiedIndex> Remaps;
290 for (auto &Link : Links) {
George Burgess IVcae581d2016-04-13 23:27:37 +0000291 if (Link.isRemapped())
Hal Finkel7529c552014-09-02 21:43:13 +0000292 continue;
Hal Finkel7529c552014-09-02 21:43:13 +0000293
294 StratifiedIndex Number = StratLinks.size();
Hal Finkel8d1590d2014-09-02 22:52:30 +0000295 Remaps.insert(std::make_pair(Link.Number, Number));
Hal Finkel7529c552014-09-02 21:43:13 +0000296 StratLinks.push_back(Link.getLink());
297 }
298
299 for (auto &Link : StratLinks) {
300 if (Link.hasAbove()) {
301 auto &Above = linksAt(Link.Above);
302 auto Iter = Remaps.find(Above.Number);
303 assert(Iter != Remaps.end());
304 Link.Above = Iter->second;
305 }
306
307 if (Link.hasBelow()) {
308 auto &Below = linksAt(Link.Below);
309 auto Iter = Remaps.find(Below.Number);
310 assert(Iter != Remaps.end());
311 Link.Below = Iter->second;
312 }
313 }
314
315 for (auto &Pair : Values) {
316 auto &Info = Pair.second;
317 auto &Link = linksAt(Info.Index);
318 auto Iter = Remaps.find(Link.Number);
319 assert(Iter != Remaps.end());
320 Info.Index = Iter->second;
321 }
322 }
323
George Burgess IVcae581d2016-04-13 23:27:37 +0000324 /// \brief There's a guarantee in StratifiedLink where all bits set in a
325 /// Link.externals will be set in all Link.externals "below" it.
Hal Finkel7529c552014-09-02 21:43:13 +0000326 static void propagateAttrs(std::vector<StratifiedLink> &Links) {
327 const auto getHighestParentAbove = [&Links](StratifiedIndex Idx) {
328 const auto *Link = &Links[Idx];
329 while (Link->hasAbove()) {
330 Idx = Link->Above;
331 Link = &Links[Idx];
332 }
333 return Idx;
334 };
335
336 SmallSet<StratifiedIndex, 16> Visited;
337 for (unsigned I = 0, E = Links.size(); I < E; ++I) {
338 auto CurrentIndex = getHighestParentAbove(I);
George Burgess IVcae581d2016-04-13 23:27:37 +0000339 if (!Visited.insert(CurrentIndex).second)
Hal Finkel7529c552014-09-02 21:43:13 +0000340 continue;
Hal Finkel7529c552014-09-02 21:43:13 +0000341
342 while (Links[CurrentIndex].hasBelow()) {
343 auto &CurrentBits = Links[CurrentIndex].Attrs;
344 auto NextIndex = Links[CurrentIndex].Below;
345 auto &NextBits = Links[NextIndex].Attrs;
346 NextBits |= CurrentBits;
347 CurrentIndex = NextIndex;
348 }
349 }
350 }
351
352public:
George Burgess IVcae581d2016-04-13 23:27:37 +0000353 /// Builds a StratifiedSet from the information we've been given since either
354 /// construction or the prior build() call.
Hal Finkel7529c552014-09-02 21:43:13 +0000355 StratifiedSets<T> build() {
356 std::vector<StratifiedLink> StratLinks;
357 finalizeSets(StratLinks);
358 propagateAttrs(StratLinks);
359 Links.clear();
360 return StratifiedSets<T>(std::move(Values), std::move(StratLinks));
361 }
362
Hal Finkel7529c552014-09-02 21:43:13 +0000363 bool has(const T &Elem) const { return get(Elem).hasValue(); }
364
365 bool add(const T &Main) {
366 if (get(Main).hasValue())
367 return false;
368
369 auto NewIndex = getNewUnlinkedIndex();
370 return addAtMerging(Main, NewIndex);
371 }
372
George Burgess IVcae581d2016-04-13 23:27:37 +0000373 /// \brief Restructures the stratified sets as necessary to make "ToAdd" in a
374 /// set above "Main". There are some cases where this is not possible (see
375 /// above), so we merge them such that ToAdd and Main are in the same set.
Hal Finkel7529c552014-09-02 21:43:13 +0000376 bool addAbove(const T &Main, const T &ToAdd) {
377 assert(has(Main));
378 auto Index = *indexOf(Main);
379 if (!linksAt(Index).hasAbove())
380 addLinkAbove(Index);
381
382 auto Above = linksAt(Index).getAbove();
383 return addAtMerging(ToAdd, Above);
384 }
385
George Burgess IVcae581d2016-04-13 23:27:37 +0000386 /// \brief Restructures the stratified sets as necessary to make "ToAdd" in a
387 /// set below "Main". There are some cases where this is not possible (see
388 /// above), so we merge them such that ToAdd and Main are in the same set.
Hal Finkel7529c552014-09-02 21:43:13 +0000389 bool addBelow(const T &Main, const T &ToAdd) {
390 assert(has(Main));
391 auto Index = *indexOf(Main);
392 if (!linksAt(Index).hasBelow())
393 addLinkBelow(Index);
394
395 auto Below = linksAt(Index).getBelow();
396 return addAtMerging(ToAdd, Below);
397 }
398
George Burgess IVa3d62be2016-06-24 01:00:03 +0000399 /// \brief Set the StratifiedAttrs of the set "Level"-levels below "Main". If
400 /// there is no set below "Main", create one for it.
401 void addAttributesBelow(const T &Main, unsigned Level, StratifiedAttrs Attr) {
George Burgess IV652ec4f2016-06-09 23:15:04 +0000402 assert(has(Main));
403 auto Index = *indexOf(Main);
George Burgess IVa3d62be2016-06-24 01:00:03 +0000404 auto *Link = &linksAt(Index);
George Burgess IV652ec4f2016-06-09 23:15:04 +0000405
George Burgess IVa3d62be2016-06-24 01:00:03 +0000406 for (unsigned I = 0; I < Level; ++I) {
407 Index = Link->hasBelow() ? Link->getBelow() : addLinkBelow(Index);
408 Link = &linksAt(Index);
409 }
410 Link->setAttrs(Attr);
George Burgess IV652ec4f2016-06-09 23:15:04 +0000411 }
412
Hal Finkel7529c552014-09-02 21:43:13 +0000413 bool addWith(const T &Main, const T &ToAdd) {
414 assert(has(Main));
415 auto MainIndex = *indexOf(Main);
416 return addAtMerging(ToAdd, MainIndex);
417 }
418
George Burgess IV1f99da52016-06-23 18:55:23 +0000419 /// \brief Merge the set "MainBelow"-levels below "Main" and the set
420 /// "ToAddBelow"-levels below "ToAdd".
421 void addBelowWith(const T &Main, unsigned MainBelow, const T &ToAdd,
422 unsigned ToAddBelow) {
423 assert(has(Main));
424 assert(has(ToAdd));
425
George Burgess IVd14d05a2016-06-23 20:59:13 +0000426 auto GetIndexBelow = [&](StratifiedIndex Index, unsigned NumLevel) {
George Burgess IV1f99da52016-06-23 18:55:23 +0000427 for (unsigned I = 0; I < NumLevel; ++I) {
428 auto Link = linksAt(Index);
429 Index = Link.hasBelow() ? Link.getBelow() : addLinkBelow(Index);
430 }
431 return Index;
432 };
433 auto MainIndex = GetIndexBelow(*indexOf(Main), MainBelow);
434 auto ToAddIndex = GetIndexBelow(*indexOf(ToAdd), ToAddBelow);
435 if (&linksAt(MainIndex) != &linksAt(ToAddIndex))
436 merge(MainIndex, ToAddIndex);
437 }
438
Hal Finkel7529c552014-09-02 21:43:13 +0000439 void noteAttributes(const T &Main, const StratifiedAttrs &NewAttrs) {
440 assert(has(Main));
441 auto *Info = *get(Main);
442 auto &Link = linksAt(Info->Index);
443 Link.setAttrs(NewAttrs);
444 }
445
Hal Finkel7529c552014-09-02 21:43:13 +0000446private:
447 DenseMap<T, StratifiedInfo> Values;
448 std::vector<BuilderLink> Links;
449
George Burgess IVcae581d2016-04-13 23:27:37 +0000450 /// Adds the given element at the given index, merging sets if necessary.
Hal Finkel7529c552014-09-02 21:43:13 +0000451 bool addAtMerging(const T &ToAdd, StratifiedIndex Index) {
452 StratifiedInfo Info = {Index};
Hal Finkel8d1590d2014-09-02 22:52:30 +0000453 auto Pair = Values.insert(std::make_pair(ToAdd, Info));
Hal Finkel7529c552014-09-02 21:43:13 +0000454 if (Pair.second)
455 return true;
456
457 auto &Iter = Pair.first;
458 auto &IterSet = linksAt(Iter->second.Index);
459 auto &ReqSet = linksAt(Index);
460
461 // Failed to add where we wanted to. Merge the sets.
462 if (&IterSet != &ReqSet)
463 merge(IterSet.Number, ReqSet.Number);
464
465 return false;
466 }
467
George Burgess IVcae581d2016-04-13 23:27:37 +0000468 /// Gets the BuilderLink at the given index, taking set remapping into
469 /// account.
Hal Finkel7529c552014-09-02 21:43:13 +0000470 BuilderLink &linksAt(StratifiedIndex Index) {
471 auto *Start = &Links[Index];
472 if (!Start->isRemapped())
473 return *Start;
474
475 auto *Current = Start;
476 while (Current->isRemapped())
477 Current = &Links[Current->getRemapIndex()];
478
479 auto NewRemap = Current->Number;
480
481 // Run through everything that has yet to be updated, and update them to
482 // remap to NewRemap
483 Current = Start;
484 while (Current->isRemapped()) {
485 auto *Next = &Links[Current->getRemapIndex()];
486 Current->updateRemap(NewRemap);
487 Current = Next;
488 }
489
490 return *Current;
491 }
492
George Burgess IVcae581d2016-04-13 23:27:37 +0000493 /// \brief Merges two sets into one another. Assumes that these sets are not
494 /// already one in the same.
Hal Finkel7529c552014-09-02 21:43:13 +0000495 void merge(StratifiedIndex Idx1, StratifiedIndex Idx2) {
496 assert(inbounds(Idx1) && inbounds(Idx2));
497 assert(&linksAt(Idx1) != &linksAt(Idx2) &&
498 "Merging a set into itself is not allowed");
499
500 // CASE 1: If the set at `Idx1` is above or below `Idx2`, we need to merge
501 // both the
502 // given sets, and all sets between them, into one.
503 if (tryMergeUpwards(Idx1, Idx2))
504 return;
505
506 if (tryMergeUpwards(Idx2, Idx1))
507 return;
508
509 // CASE 2: The set at `Idx1` is not in the same chain as the set at `Idx2`.
510 // We therefore need to merge the two chains together.
511 mergeDirect(Idx1, Idx2);
512 }
513
George Burgess IVcae581d2016-04-13 23:27:37 +0000514 /// \brief Merges two sets assuming that the set at `Idx1` is unreachable from
515 /// traversing above or below the set at `Idx2`.
Hal Finkel7529c552014-09-02 21:43:13 +0000516 void mergeDirect(StratifiedIndex Idx1, StratifiedIndex Idx2) {
517 assert(inbounds(Idx1) && inbounds(Idx2));
518
519 auto *LinksInto = &linksAt(Idx1);
520 auto *LinksFrom = &linksAt(Idx2);
521 // Merging everything above LinksInto then proceeding to merge everything
522 // below LinksInto becomes problematic, so we go as far "up" as possible!
523 while (LinksInto->hasAbove() && LinksFrom->hasAbove()) {
524 LinksInto = &linksAt(LinksInto->getAbove());
525 LinksFrom = &linksAt(LinksFrom->getAbove());
526 }
527
528 if (LinksFrom->hasAbove()) {
529 LinksInto->setAbove(LinksFrom->getAbove());
530 auto &NewAbove = linksAt(LinksInto->getAbove());
531 NewAbove.setBelow(LinksInto->Number);
532 }
533
534 // Merging strategy:
535 // > If neither has links below, stop.
536 // > If only `LinksInto` has links below, stop.
537 // > If only `LinksFrom` has links below, reset `LinksInto.Below` to
538 // match `LinksFrom.Below`
539 // > If both have links above, deal with those next.
540 while (LinksInto->hasBelow() && LinksFrom->hasBelow()) {
541 auto &FromAttrs = LinksFrom->getAttrs();
542 LinksInto->setAttrs(FromAttrs);
543
544 // Remap needs to happen after getBelow(), but before
545 // assignment of LinksFrom
546 auto *NewLinksFrom = &linksAt(LinksFrom->getBelow());
547 LinksFrom->remapTo(LinksInto->Number);
548 LinksFrom = NewLinksFrom;
549 LinksInto = &linksAt(LinksInto->getBelow());
550 }
551
552 if (LinksFrom->hasBelow()) {
553 LinksInto->setBelow(LinksFrom->getBelow());
554 auto &NewBelow = linksAt(LinksInto->getBelow());
555 NewBelow.setAbove(LinksInto->Number);
556 }
557
558 LinksFrom->remapTo(LinksInto->Number);
559 }
560
George Burgess IVcae581d2016-04-13 23:27:37 +0000561 /// Checks to see if lowerIndex is at a level lower than upperIndex. If so, it
562 /// will merge lowerIndex with upperIndex (and all of the sets between) and
563 /// return true. Otherwise, it will return false.
Hal Finkel7529c552014-09-02 21:43:13 +0000564 bool tryMergeUpwards(StratifiedIndex LowerIndex, StratifiedIndex UpperIndex) {
565 assert(inbounds(LowerIndex) && inbounds(UpperIndex));
566 auto *Lower = &linksAt(LowerIndex);
567 auto *Upper = &linksAt(UpperIndex);
568 if (Lower == Upper)
569 return true;
570
571 SmallVector<BuilderLink *, 8> Found;
572 auto *Current = Lower;
573 auto Attrs = Current->getAttrs();
574 while (Current->hasAbove() && Current != Upper) {
575 Found.push_back(Current);
576 Attrs |= Current->getAttrs();
577 Current = &linksAt(Current->getAbove());
578 }
579
580 if (Current != Upper)
581 return false;
582
583 Upper->setAttrs(Attrs);
584
585 if (Lower->hasBelow()) {
586 auto NewBelowIndex = Lower->getBelow();
587 Upper->setBelow(NewBelowIndex);
588 auto &NewBelow = linksAt(NewBelowIndex);
589 NewBelow.setAbove(UpperIndex);
590 } else {
591 Upper->clearBelow();
592 }
593
594 for (const auto &Ptr : Found)
595 Ptr->remapTo(Upper->Number);
596
597 return true;
598 }
599
600 Optional<const StratifiedInfo *> get(const T &Val) const {
601 auto Result = Values.find(Val);
602 if (Result == Values.end())
George Burgess IVcae581d2016-04-13 23:27:37 +0000603 return None;
Hal Finkel7529c552014-09-02 21:43:13 +0000604 return &Result->second;
605 }
606
607 Optional<StratifiedInfo *> get(const T &Val) {
608 auto Result = Values.find(Val);
609 if (Result == Values.end())
George Burgess IVcae581d2016-04-13 23:27:37 +0000610 return None;
Hal Finkel7529c552014-09-02 21:43:13 +0000611 return &Result->second;
612 }
613
614 Optional<StratifiedIndex> indexOf(const T &Val) {
615 auto MaybeVal = get(Val);
616 if (!MaybeVal.hasValue())
George Burgess IVcae581d2016-04-13 23:27:37 +0000617 return None;
Hal Finkel7529c552014-09-02 21:43:13 +0000618 auto *Info = *MaybeVal;
619 auto &Link = linksAt(Info->Index);
620 return Link.Number;
621 }
622
623 StratifiedIndex addLinkBelow(StratifiedIndex Set) {
624 auto At = addLinks();
625 Links[Set].setBelow(At);
626 Links[At].setAbove(Set);
627 return At;
628 }
629
630 StratifiedIndex addLinkAbove(StratifiedIndex Set) {
631 auto At = addLinks();
632 Links[At].setBelow(Set);
633 Links[Set].setAbove(At);
634 return At;
635 }
636
637 StratifiedIndex getNewUnlinkedIndex() { return addLinks(); }
638
639 StratifiedIndex addLinks() {
640 auto Link = Links.size();
641 Links.push_back(BuilderLink(Link));
642 return Link;
643 }
644
Hal Finkel42b7e012014-09-02 22:36:58 +0000645 bool inbounds(StratifiedIndex N) const { return N < Links.size(); }
Hal Finkel7529c552014-09-02 21:43:13 +0000646};
Alexander Kornienkof00654e2015-06-23 09:49:53 +0000647}
George Burgess IV1ca8aff2016-07-06 00:36:12 +0000648}
George Burgess IVd14d05a2016-06-23 20:59:13 +0000649#endif // LLVM_ADT_STRATIFIEDSETS_H