1 //===- StratifiedSets.h - Abstract stratified sets implementation. --------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #ifndef LLVM_ADT_STRATIFIEDSETS_H
11 #define LLVM_ADT_STRATIFIEDSETS_H
13 #include "AliasAnalysisSummary.h"
14 #include "llvm/ADT/DenseMap.h"
15 #include "llvm/ADT/Optional.h"
16 #include "llvm/ADT/SmallSet.h"
17 #include "llvm/ADT/SmallVector.h"
21 #include <type_traits>
27 /// An index into Stratified Sets.
28 typedef unsigned StratifiedIndex
;
29 /// NOTE: ^ This can't be a short -- bootstrapping clang has a case where
32 // Container of information related to a value in a StratifiedSet.
33 struct StratifiedInfo
{
34 StratifiedIndex Index
;
35 /// For field sensitivity, etc. we can tack fields on here.
38 /// A "link" between two StratifiedSets.
39 struct StratifiedLink
{
40 /// This is a value used to signify "does not exist" where the
41 /// StratifiedIndex type is used.
43 /// This is used instead of Optional<StratifiedIndex> because
44 /// Optional<StratifiedIndex> would eat up a considerable amount of extra
45 /// memory, after struct padding/alignment is taken into account.
46 static const StratifiedIndex SetSentinel
;
48 /// The index for the set "above" current
49 StratifiedIndex Above
;
51 /// The link for the set "below" current
52 StratifiedIndex Below
;
54 /// Attributes for these StratifiedSets.
57 StratifiedLink() : Above(SetSentinel
), Below(SetSentinel
) {}
59 bool hasBelow() const { return Below
!= SetSentinel
; }
60 bool hasAbove() const { return Above
!= SetSentinel
; }
62 void clearBelow() { Below
= SetSentinel
; }
63 void clearAbove() { Above
= SetSentinel
; }
66 /// These are stratified sets, as described in "Fast algorithms for
67 /// Dyck-CFL-reachability with applications to Alias Analysis" by Zhang Q, Lyu M
68 /// R, Yuan H, and Su Z. -- in short, this is meant to represent different sets
69 /// of Value*s. If two Value*s are in the same set, or if both sets have
70 /// overlapping attributes, then the Value*s are said to alias.
72 /// Sets may be related by position, meaning that one set may be considered as
73 /// above or below another. In CFL Alias Analysis, this gives us an indication
74 /// of how two variables are related; if the set of variable A is below a set
75 /// containing variable B, then at some point, a variable that has interacted
76 /// with B (or B itself) was either used in order to extract the variable A, or
77 /// was used as storage of variable A.
79 /// Sets may also have attributes (as noted above). These attributes are
80 /// generally used for noting whether a variable in the set has interacted with
81 /// a variable whose origins we don't quite know (i.e. globals/arguments), or if
82 /// the variable may have had operations performed on it (modified in a function
83 /// call). All attributes that exist in a set A must exist in all sets marked as
85 template <typename T
> class StratifiedSets
{
87 StratifiedSets() = default;
88 StratifiedSets(StratifiedSets
&&) = default;
89 StratifiedSets
&operator=(StratifiedSets
&&) = default;
91 StratifiedSets(DenseMap
<T
, StratifiedInfo
> Map
,
92 std::vector
<StratifiedLink
> Links
)
93 : Values(std::move(Map
)), Links(std::move(Links
)) {}
95 Optional
<StratifiedInfo
> find(const T
&Elem
) const {
96 auto Iter
= Values
.find(Elem
);
97 if (Iter
== Values
.end())
102 const StratifiedLink
&getLink(StratifiedIndex Index
) const {
103 assert(inbounds(Index
));
108 DenseMap
<T
, StratifiedInfo
> Values
;
109 std::vector
<StratifiedLink
> Links
;
111 bool inbounds(StratifiedIndex Idx
) const { return Idx
< Links
.size(); }
114 /// Generic Builder class that produces StratifiedSets instances.
116 /// The goal of this builder is to efficiently produce correct StratifiedSets
117 /// instances. To this end, we use a few tricks:
118 /// > Set chains (A method for linking sets together)
119 /// > Set remaps (A method for marking a set as an alias [irony?] of another)
121 /// ==== Set chains ====
122 /// This builder has a notion of some value A being above, below, or with some
124 /// > The `A above B` relationship implies that there is a reference edge
125 /// going from A to B. Namely, it notes that A can store anything in B's set.
126 /// > The `A below B` relationship is the opposite of `A above B`. It implies
127 /// that there's a dereference edge going from A to B.
128 /// > The `A with B` relationship states that there's an assignment edge going
129 /// from A to B, and that A and B should be treated as equals.
131 /// As an example, take the following code snippet:
133 /// %a = alloca i32, align 4
134 /// %ap = alloca i32*, align 8
135 /// %app = alloca i32**, align 8
138 /// %aw = getelementptr %ap, i32 0
140 /// Given this, the following relations exist:
141 /// - %a below %ap & %ap above %a
142 /// - %ap below %app & %app above %ap
143 /// - %aw with %ap & %ap with %aw
145 /// These relations produce the following sets:
146 /// [{%a}, {%ap, %aw}, {%app}]
148 /// ...Which state that the only MayAlias relationship in the above program is
149 /// between %ap and %aw.
151 /// Because LLVM allows arbitrary casts, code like the following needs to be
153 /// %ip = alloca i64, align 8
154 /// %ipp = alloca i64*, align 8
155 /// %i = bitcast i64** ipp to i64
156 /// store i64* %ip, i64** %ipp
157 /// store i64 %i, i64* %ip
159 /// Which, because %ipp ends up *both* above and below %ip, is fun.
161 /// This is solved by merging %i and %ipp into a single set (...which is the
162 /// only way to solve this, since their bit patterns are equivalent). Any sets
163 /// that ended up in between %i and %ipp at the time of merging (in this case,
164 /// the set containing %ip) also get conservatively merged into the set of %i
165 /// and %ipp. In short, the resulting StratifiedSet from the above code would be
168 /// ==== Set remaps ====
169 /// More of an implementation detail than anything -- when merging sets, we need
170 /// to update the numbers of all of the elements mapped to those sets. Rather
171 /// than doing this at each merge, we note in the BuilderLink structure that a
172 /// remap has occurred, and use this information so we can defer renumbering set
173 /// elements until build time.
174 template <typename T
> class StratifiedSetsBuilder
{
175 /// Represents a Stratified Set, with information about the Stratified
176 /// Set above it, the set below it, and whether the current set has been
177 /// remapped to another.
179 const StratifiedIndex Number
;
181 BuilderLink(StratifiedIndex N
) : Number(N
) {
182 Remap
= StratifiedLink::SetSentinel
;
185 bool hasAbove() const {
186 assert(!isRemapped());
187 return Link
.hasAbove();
190 bool hasBelow() const {
191 assert(!isRemapped());
192 return Link
.hasBelow();
195 void setBelow(StratifiedIndex I
) {
196 assert(!isRemapped());
200 void setAbove(StratifiedIndex I
) {
201 assert(!isRemapped());
206 assert(!isRemapped());
211 assert(!isRemapped());
215 StratifiedIndex
getBelow() const {
216 assert(!isRemapped());
221 StratifiedIndex
getAbove() const {
222 assert(!isRemapped());
227 AliasAttrs
getAttrs() {
228 assert(!isRemapped());
232 void setAttrs(AliasAttrs Other
) {
233 assert(!isRemapped());
237 bool isRemapped() const { return Remap
!= StratifiedLink::SetSentinel
; }
239 /// For initial remapping to another set
240 void remapTo(StratifiedIndex Other
) {
241 assert(!isRemapped());
245 StratifiedIndex
getRemapIndex() const {
246 assert(isRemapped());
250 /// Should only be called when we're already remapped.
251 void updateRemap(StratifiedIndex Other
) {
252 assert(isRemapped());
256 /// Prefer the above functions to calling things directly on what's returned
257 /// from this -- they guard against unexpected calls when the current
258 /// BuilderLink is remapped.
259 const StratifiedLink
&getLink() const { return Link
; }
263 StratifiedIndex Remap
;
266 /// This function performs all of the set unioning/value renumbering
267 /// that we've been putting off, and generates a vector<StratifiedLink> that
268 /// may be placed in a StratifiedSets instance.
269 void finalizeSets(std::vector
<StratifiedLink
> &StratLinks
) {
270 DenseMap
<StratifiedIndex
, StratifiedIndex
> Remaps
;
271 for (auto &Link
: Links
) {
272 if (Link
.isRemapped())
275 StratifiedIndex Number
= StratLinks
.size();
276 Remaps
.insert(std::make_pair(Link
.Number
, Number
));
277 StratLinks
.push_back(Link
.getLink());
280 for (auto &Link
: StratLinks
) {
281 if (Link
.hasAbove()) {
282 auto &Above
= linksAt(Link
.Above
);
283 auto Iter
= Remaps
.find(Above
.Number
);
284 assert(Iter
!= Remaps
.end());
285 Link
.Above
= Iter
->second
;
288 if (Link
.hasBelow()) {
289 auto &Below
= linksAt(Link
.Below
);
290 auto Iter
= Remaps
.find(Below
.Number
);
291 assert(Iter
!= Remaps
.end());
292 Link
.Below
= Iter
->second
;
296 for (auto &Pair
: Values
) {
297 auto &Info
= Pair
.second
;
298 auto &Link
= linksAt(Info
.Index
);
299 auto Iter
= Remaps
.find(Link
.Number
);
300 assert(Iter
!= Remaps
.end());
301 Info
.Index
= Iter
->second
;
305 /// There's a guarantee in StratifiedLink where all bits set in a
306 /// Link.externals will be set in all Link.externals "below" it.
307 static void propagateAttrs(std::vector
<StratifiedLink
> &Links
) {
308 const auto getHighestParentAbove
= [&Links
](StratifiedIndex Idx
) {
309 const auto *Link
= &Links
[Idx
];
310 while (Link
->hasAbove()) {
317 SmallSet
<StratifiedIndex
, 16> Visited
;
318 for (unsigned I
= 0, E
= Links
.size(); I
< E
; ++I
) {
319 auto CurrentIndex
= getHighestParentAbove(I
);
320 if (!Visited
.insert(CurrentIndex
).second
)
323 while (Links
[CurrentIndex
].hasBelow()) {
324 auto &CurrentBits
= Links
[CurrentIndex
].Attrs
;
325 auto NextIndex
= Links
[CurrentIndex
].Below
;
326 auto &NextBits
= Links
[NextIndex
].Attrs
;
327 NextBits
|= CurrentBits
;
328 CurrentIndex
= NextIndex
;
334 /// Builds a StratifiedSet from the information we've been given since either
335 /// construction or the prior build() call.
336 StratifiedSets
<T
> build() {
337 std::vector
<StratifiedLink
> StratLinks
;
338 finalizeSets(StratLinks
);
339 propagateAttrs(StratLinks
);
341 return StratifiedSets
<T
>(std::move(Values
), std::move(StratLinks
));
344 bool has(const T
&Elem
) const { return get(Elem
).hasValue(); }
346 bool add(const T
&Main
) {
347 if (get(Main
).hasValue())
350 auto NewIndex
= getNewUnlinkedIndex();
351 return addAtMerging(Main
, NewIndex
);
354 /// Restructures the stratified sets as necessary to make "ToAdd" in a
355 /// set above "Main". There are some cases where this is not possible (see
356 /// above), so we merge them such that ToAdd and Main are in the same set.
357 bool addAbove(const T
&Main
, const T
&ToAdd
) {
359 auto Index
= *indexOf(Main
);
360 if (!linksAt(Index
).hasAbove())
363 auto Above
= linksAt(Index
).getAbove();
364 return addAtMerging(ToAdd
, Above
);
367 /// Restructures the stratified sets as necessary to make "ToAdd" in a
368 /// set below "Main". There are some cases where this is not possible (see
369 /// above), so we merge them such that ToAdd and Main are in the same set.
370 bool addBelow(const T
&Main
, const T
&ToAdd
) {
372 auto Index
= *indexOf(Main
);
373 if (!linksAt(Index
).hasBelow())
376 auto Below
= linksAt(Index
).getBelow();
377 return addAtMerging(ToAdd
, Below
);
380 bool addWith(const T
&Main
, const T
&ToAdd
) {
382 auto MainIndex
= *indexOf(Main
);
383 return addAtMerging(ToAdd
, MainIndex
);
386 void noteAttributes(const T
&Main
, AliasAttrs NewAttrs
) {
388 auto *Info
= *get(Main
);
389 auto &Link
= linksAt(Info
->Index
);
390 Link
.setAttrs(NewAttrs
);
394 DenseMap
<T
, StratifiedInfo
> Values
;
395 std::vector
<BuilderLink
> Links
;
397 /// Adds the given element at the given index, merging sets if necessary.
398 bool addAtMerging(const T
&ToAdd
, StratifiedIndex Index
) {
399 StratifiedInfo Info
= {Index
};
400 auto Pair
= Values
.insert(std::make_pair(ToAdd
, Info
));
404 auto &Iter
= Pair
.first
;
405 auto &IterSet
= linksAt(Iter
->second
.Index
);
406 auto &ReqSet
= linksAt(Index
);
408 // Failed to add where we wanted to. Merge the sets.
409 if (&IterSet
!= &ReqSet
)
410 merge(IterSet
.Number
, ReqSet
.Number
);
415 /// Gets the BuilderLink at the given index, taking set remapping into
417 BuilderLink
&linksAt(StratifiedIndex Index
) {
418 auto *Start
= &Links
[Index
];
419 if (!Start
->isRemapped())
422 auto *Current
= Start
;
423 while (Current
->isRemapped())
424 Current
= &Links
[Current
->getRemapIndex()];
426 auto NewRemap
= Current
->Number
;
428 // Run through everything that has yet to be updated, and update them to
431 while (Current
->isRemapped()) {
432 auto *Next
= &Links
[Current
->getRemapIndex()];
433 Current
->updateRemap(NewRemap
);
440 /// Merges two sets into one another. Assumes that these sets are not
441 /// already one in the same.
442 void merge(StratifiedIndex Idx1
, StratifiedIndex Idx2
) {
443 assert(inbounds(Idx1
) && inbounds(Idx2
));
444 assert(&linksAt(Idx1
) != &linksAt(Idx2
) &&
445 "Merging a set into itself is not allowed");
447 // CASE 1: If the set at `Idx1` is above or below `Idx2`, we need to merge
449 // given sets, and all sets between them, into one.
450 if (tryMergeUpwards(Idx1
, Idx2
))
453 if (tryMergeUpwards(Idx2
, Idx1
))
456 // CASE 2: The set at `Idx1` is not in the same chain as the set at `Idx2`.
457 // We therefore need to merge the two chains together.
458 mergeDirect(Idx1
, Idx2
);
461 /// Merges two sets assuming that the set at `Idx1` is unreachable from
462 /// traversing above or below the set at `Idx2`.
463 void mergeDirect(StratifiedIndex Idx1
, StratifiedIndex Idx2
) {
464 assert(inbounds(Idx1
) && inbounds(Idx2
));
466 auto *LinksInto
= &linksAt(Idx1
);
467 auto *LinksFrom
= &linksAt(Idx2
);
468 // Merging everything above LinksInto then proceeding to merge everything
469 // below LinksInto becomes problematic, so we go as far "up" as possible!
470 while (LinksInto
->hasAbove() && LinksFrom
->hasAbove()) {
471 LinksInto
= &linksAt(LinksInto
->getAbove());
472 LinksFrom
= &linksAt(LinksFrom
->getAbove());
475 if (LinksFrom
->hasAbove()) {
476 LinksInto
->setAbove(LinksFrom
->getAbove());
477 auto &NewAbove
= linksAt(LinksInto
->getAbove());
478 NewAbove
.setBelow(LinksInto
->Number
);
482 // > If neither has links below, stop.
483 // > If only `LinksInto` has links below, stop.
484 // > If only `LinksFrom` has links below, reset `LinksInto.Below` to
485 // match `LinksFrom.Below`
486 // > If both have links above, deal with those next.
487 while (LinksInto
->hasBelow() && LinksFrom
->hasBelow()) {
488 auto FromAttrs
= LinksFrom
->getAttrs();
489 LinksInto
->setAttrs(FromAttrs
);
491 // Remap needs to happen after getBelow(), but before
492 // assignment of LinksFrom
493 auto *NewLinksFrom
= &linksAt(LinksFrom
->getBelow());
494 LinksFrom
->remapTo(LinksInto
->Number
);
495 LinksFrom
= NewLinksFrom
;
496 LinksInto
= &linksAt(LinksInto
->getBelow());
499 if (LinksFrom
->hasBelow()) {
500 LinksInto
->setBelow(LinksFrom
->getBelow());
501 auto &NewBelow
= linksAt(LinksInto
->getBelow());
502 NewBelow
.setAbove(LinksInto
->Number
);
505 LinksInto
->setAttrs(LinksFrom
->getAttrs());
506 LinksFrom
->remapTo(LinksInto
->Number
);
509 /// Checks to see if lowerIndex is at a level lower than upperIndex. If so, it
510 /// will merge lowerIndex with upperIndex (and all of the sets between) and
511 /// return true. Otherwise, it will return false.
512 bool tryMergeUpwards(StratifiedIndex LowerIndex
, StratifiedIndex UpperIndex
) {
513 assert(inbounds(LowerIndex
) && inbounds(UpperIndex
));
514 auto *Lower
= &linksAt(LowerIndex
);
515 auto *Upper
= &linksAt(UpperIndex
);
519 SmallVector
<BuilderLink
*, 8> Found
;
520 auto *Current
= Lower
;
521 auto Attrs
= Current
->getAttrs();
522 while (Current
->hasAbove() && Current
!= Upper
) {
523 Found
.push_back(Current
);
524 Attrs
|= Current
->getAttrs();
525 Current
= &linksAt(Current
->getAbove());
528 if (Current
!= Upper
)
531 Upper
->setAttrs(Attrs
);
533 if (Lower
->hasBelow()) {
534 auto NewBelowIndex
= Lower
->getBelow();
535 Upper
->setBelow(NewBelowIndex
);
536 auto &NewBelow
= linksAt(NewBelowIndex
);
537 NewBelow
.setAbove(UpperIndex
);
542 for (const auto &Ptr
: Found
)
543 Ptr
->remapTo(Upper
->Number
);
548 Optional
<const StratifiedInfo
*> get(const T
&Val
) const {
549 auto Result
= Values
.find(Val
);
550 if (Result
== Values
.end())
552 return &Result
->second
;
555 Optional
<StratifiedInfo
*> get(const T
&Val
) {
556 auto Result
= Values
.find(Val
);
557 if (Result
== Values
.end())
559 return &Result
->second
;
562 Optional
<StratifiedIndex
> indexOf(const T
&Val
) {
563 auto MaybeVal
= get(Val
);
564 if (!MaybeVal
.hasValue())
566 auto *Info
= *MaybeVal
;
567 auto &Link
= linksAt(Info
->Index
);
571 StratifiedIndex
addLinkBelow(StratifiedIndex Set
) {
572 auto At
= addLinks();
573 Links
[Set
].setBelow(At
);
574 Links
[At
].setAbove(Set
);
578 StratifiedIndex
addLinkAbove(StratifiedIndex Set
) {
579 auto At
= addLinks();
580 Links
[At
].setBelow(Set
);
581 Links
[Set
].setAbove(At
);
585 StratifiedIndex
getNewUnlinkedIndex() { return addLinks(); }
587 StratifiedIndex
addLinks() {
588 auto Link
= Links
.size();
589 Links
.push_back(BuilderLink(Link
));
593 bool inbounds(StratifiedIndex N
) const { return N
< Links
.size(); }
597 #endif // LLVM_ADT_STRATIFIEDSETS_H