1 //===- StratifiedSets.h - Abstract stratified sets implementation. --------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_ADT_STRATIFIEDSETS_H
10 #define LLVM_ADT_STRATIFIEDSETS_H
12 #include "AliasAnalysisSummary.h"
13 #include "llvm/ADT/DenseMap.h"
14 #include "llvm/ADT/Optional.h"
15 #include "llvm/ADT/SmallSet.h"
16 #include "llvm/ADT/SmallVector.h"
20 #include <type_traits>
26 /// An index into Stratified Sets.
27 typedef unsigned StratifiedIndex
;
28 /// NOTE: ^ This can't be a short -- bootstrapping clang has a case where
31 // Container of information related to a value in a StratifiedSet.
32 struct StratifiedInfo
{
33 StratifiedIndex Index
;
34 /// For field sensitivity, etc. we can tack fields on here.
37 /// A "link" between two StratifiedSets.
38 struct StratifiedLink
{
39 /// This is a value used to signify "does not exist" where the
40 /// StratifiedIndex type is used.
42 /// This is used instead of Optional<StratifiedIndex> because
43 /// Optional<StratifiedIndex> would eat up a considerable amount of extra
44 /// memory, after struct padding/alignment is taken into account.
45 static const StratifiedIndex SetSentinel
;
47 /// The index for the set "above" current
48 StratifiedIndex Above
;
50 /// The link for the set "below" current
51 StratifiedIndex Below
;
53 /// Attributes for these StratifiedSets.
56 StratifiedLink() : Above(SetSentinel
), Below(SetSentinel
) {}
58 bool hasBelow() const { return Below
!= SetSentinel
; }
59 bool hasAbove() const { return Above
!= SetSentinel
; }
61 void clearBelow() { Below
= SetSentinel
; }
62 void clearAbove() { Above
= SetSentinel
; }
65 /// These are stratified sets, as described in "Fast algorithms for
66 /// Dyck-CFL-reachability with applications to Alias Analysis" by Zhang Q, Lyu M
67 /// R, Yuan H, and Su Z. -- in short, this is meant to represent different sets
68 /// of Value*s. If two Value*s are in the same set, or if both sets have
69 /// overlapping attributes, then the Value*s are said to alias.
71 /// Sets may be related by position, meaning that one set may be considered as
72 /// above or below another. In CFL Alias Analysis, this gives us an indication
73 /// of how two variables are related; if the set of variable A is below a set
74 /// containing variable B, then at some point, a variable that has interacted
75 /// with B (or B itself) was either used in order to extract the variable A, or
76 /// was used as storage of variable A.
78 /// Sets may also have attributes (as noted above). These attributes are
79 /// generally used for noting whether a variable in the set has interacted with
80 /// a variable whose origins we don't quite know (i.e. globals/arguments), or if
81 /// the variable may have had operations performed on it (modified in a function
82 /// call). All attributes that exist in a set A must exist in all sets marked as
84 template <typename T
> class StratifiedSets
{
86 StratifiedSets() = default;
87 StratifiedSets(StratifiedSets
&&) = default;
88 StratifiedSets
&operator=(StratifiedSets
&&) = default;
90 StratifiedSets(DenseMap
<T
, StratifiedInfo
> Map
,
91 std::vector
<StratifiedLink
> Links
)
92 : Values(std::move(Map
)), Links(std::move(Links
)) {}
94 Optional
<StratifiedInfo
> find(const T
&Elem
) const {
95 auto Iter
= Values
.find(Elem
);
96 if (Iter
== Values
.end())
101 const StratifiedLink
&getLink(StratifiedIndex Index
) const {
102 assert(inbounds(Index
));
107 DenseMap
<T
, StratifiedInfo
> Values
;
108 std::vector
<StratifiedLink
> Links
;
110 bool inbounds(StratifiedIndex Idx
) const { return Idx
< Links
.size(); }
113 /// Generic Builder class that produces StratifiedSets instances.
115 /// The goal of this builder is to efficiently produce correct StratifiedSets
116 /// instances. To this end, we use a few tricks:
117 /// > Set chains (A method for linking sets together)
118 /// > Set remaps (A method for marking a set as an alias [irony?] of another)
120 /// ==== Set chains ====
121 /// This builder has a notion of some value A being above, below, or with some
123 /// > The `A above B` relationship implies that there is a reference edge
124 /// going from A to B. Namely, it notes that A can store anything in B's set.
125 /// > The `A below B` relationship is the opposite of `A above B`. It implies
126 /// that there's a dereference edge going from A to B.
127 /// > The `A with B` relationship states that there's an assignment edge going
128 /// from A to B, and that A and B should be treated as equals.
130 /// As an example, take the following code snippet:
132 /// %a = alloca i32, align 4
133 /// %ap = alloca i32*, align 8
134 /// %app = alloca i32**, align 8
137 /// %aw = getelementptr %ap, i32 0
139 /// Given this, the following relations exist:
140 /// - %a below %ap & %ap above %a
141 /// - %ap below %app & %app above %ap
142 /// - %aw with %ap & %ap with %aw
144 /// These relations produce the following sets:
145 /// [{%a}, {%ap, %aw}, {%app}]
147 /// ...Which state that the only MayAlias relationship in the above program is
148 /// between %ap and %aw.
150 /// Because LLVM allows arbitrary casts, code like the following needs to be
152 /// %ip = alloca i64, align 8
153 /// %ipp = alloca i64*, align 8
154 /// %i = bitcast i64** ipp to i64
155 /// store i64* %ip, i64** %ipp
156 /// store i64 %i, i64* %ip
158 /// Which, because %ipp ends up *both* above and below %ip, is fun.
160 /// This is solved by merging %i and %ipp into a single set (...which is the
161 /// only way to solve this, since their bit patterns are equivalent). Any sets
162 /// that ended up in between %i and %ipp at the time of merging (in this case,
163 /// the set containing %ip) also get conservatively merged into the set of %i
164 /// and %ipp. In short, the resulting StratifiedSet from the above code would be
167 /// ==== Set remaps ====
168 /// More of an implementation detail than anything -- when merging sets, we need
169 /// to update the numbers of all of the elements mapped to those sets. Rather
170 /// than doing this at each merge, we note in the BuilderLink structure that a
171 /// remap has occurred, and use this information so we can defer renumbering set
172 /// elements until build time.
173 template <typename T
> class StratifiedSetsBuilder
{
174 /// Represents a Stratified Set, with information about the Stratified
175 /// Set above it, the set below it, and whether the current set has been
176 /// remapped to another.
178 const StratifiedIndex Number
;
180 BuilderLink(StratifiedIndex N
) : Number(N
) {
181 Remap
= StratifiedLink::SetSentinel
;
184 bool hasAbove() const {
185 assert(!isRemapped());
186 return Link
.hasAbove();
189 bool hasBelow() const {
190 assert(!isRemapped());
191 return Link
.hasBelow();
194 void setBelow(StratifiedIndex I
) {
195 assert(!isRemapped());
199 void setAbove(StratifiedIndex I
) {
200 assert(!isRemapped());
205 assert(!isRemapped());
210 assert(!isRemapped());
214 StratifiedIndex
getBelow() const {
215 assert(!isRemapped());
220 StratifiedIndex
getAbove() const {
221 assert(!isRemapped());
226 AliasAttrs
getAttrs() {
227 assert(!isRemapped());
231 void setAttrs(AliasAttrs Other
) {
232 assert(!isRemapped());
236 bool isRemapped() const { return Remap
!= StratifiedLink::SetSentinel
; }
238 /// For initial remapping to another set
239 void remapTo(StratifiedIndex Other
) {
240 assert(!isRemapped());
244 StratifiedIndex
getRemapIndex() const {
245 assert(isRemapped());
249 /// Should only be called when we're already remapped.
250 void updateRemap(StratifiedIndex Other
) {
251 assert(isRemapped());
255 /// Prefer the above functions to calling things directly on what's returned
256 /// from this -- they guard against unexpected calls when the current
257 /// BuilderLink is remapped.
258 const StratifiedLink
&getLink() const { return Link
; }
262 StratifiedIndex Remap
;
265 /// This function performs all of the set unioning/value renumbering
266 /// that we've been putting off, and generates a vector<StratifiedLink> that
267 /// may be placed in a StratifiedSets instance.
268 void finalizeSets(std::vector
<StratifiedLink
> &StratLinks
) {
269 DenseMap
<StratifiedIndex
, StratifiedIndex
> Remaps
;
270 for (auto &Link
: Links
) {
271 if (Link
.isRemapped())
274 StratifiedIndex Number
= StratLinks
.size();
275 Remaps
.insert(std::make_pair(Link
.Number
, Number
));
276 StratLinks
.push_back(Link
.getLink());
279 for (auto &Link
: StratLinks
) {
280 if (Link
.hasAbove()) {
281 auto &Above
= linksAt(Link
.Above
);
282 auto Iter
= Remaps
.find(Above
.Number
);
283 assert(Iter
!= Remaps
.end());
284 Link
.Above
= Iter
->second
;
287 if (Link
.hasBelow()) {
288 auto &Below
= linksAt(Link
.Below
);
289 auto Iter
= Remaps
.find(Below
.Number
);
290 assert(Iter
!= Remaps
.end());
291 Link
.Below
= Iter
->second
;
295 for (auto &Pair
: Values
) {
296 auto &Info
= Pair
.second
;
297 auto &Link
= linksAt(Info
.Index
);
298 auto Iter
= Remaps
.find(Link
.Number
);
299 assert(Iter
!= Remaps
.end());
300 Info
.Index
= Iter
->second
;
304 /// There's a guarantee in StratifiedLink where all bits set in a
305 /// Link.externals will be set in all Link.externals "below" it.
306 static void propagateAttrs(std::vector
<StratifiedLink
> &Links
) {
307 const auto getHighestParentAbove
= [&Links
](StratifiedIndex Idx
) {
308 const auto *Link
= &Links
[Idx
];
309 while (Link
->hasAbove()) {
316 SmallSet
<StratifiedIndex
, 16> Visited
;
317 for (unsigned I
= 0, E
= Links
.size(); I
< E
; ++I
) {
318 auto CurrentIndex
= getHighestParentAbove(I
);
319 if (!Visited
.insert(CurrentIndex
).second
)
322 while (Links
[CurrentIndex
].hasBelow()) {
323 auto &CurrentBits
= Links
[CurrentIndex
].Attrs
;
324 auto NextIndex
= Links
[CurrentIndex
].Below
;
325 auto &NextBits
= Links
[NextIndex
].Attrs
;
326 NextBits
|= CurrentBits
;
327 CurrentIndex
= NextIndex
;
333 /// Builds a StratifiedSet from the information we've been given since either
334 /// construction or the prior build() call.
335 StratifiedSets
<T
> build() {
336 std::vector
<StratifiedLink
> StratLinks
;
337 finalizeSets(StratLinks
);
338 propagateAttrs(StratLinks
);
340 return StratifiedSets
<T
>(std::move(Values
), std::move(StratLinks
));
343 bool has(const T
&Elem
) const { return get(Elem
).hasValue(); }
345 bool add(const T
&Main
) {
346 if (get(Main
).hasValue())
349 auto NewIndex
= getNewUnlinkedIndex();
350 return addAtMerging(Main
, NewIndex
);
353 /// Restructures the stratified sets as necessary to make "ToAdd" in a
354 /// set above "Main". There are some cases where this is not possible (see
355 /// above), so we merge them such that ToAdd and Main are in the same set.
356 bool addAbove(const T
&Main
, const T
&ToAdd
) {
358 auto Index
= *indexOf(Main
);
359 if (!linksAt(Index
).hasAbove())
362 auto Above
= linksAt(Index
).getAbove();
363 return addAtMerging(ToAdd
, Above
);
366 /// Restructures the stratified sets as necessary to make "ToAdd" in a
367 /// set below "Main". There are some cases where this is not possible (see
368 /// above), so we merge them such that ToAdd and Main are in the same set.
369 bool addBelow(const T
&Main
, const T
&ToAdd
) {
371 auto Index
= *indexOf(Main
);
372 if (!linksAt(Index
).hasBelow())
375 auto Below
= linksAt(Index
).getBelow();
376 return addAtMerging(ToAdd
, Below
);
379 bool addWith(const T
&Main
, const T
&ToAdd
) {
381 auto MainIndex
= *indexOf(Main
);
382 return addAtMerging(ToAdd
, MainIndex
);
385 void noteAttributes(const T
&Main
, AliasAttrs NewAttrs
) {
387 auto *Info
= *get(Main
);
388 auto &Link
= linksAt(Info
->Index
);
389 Link
.setAttrs(NewAttrs
);
393 DenseMap
<T
, StratifiedInfo
> Values
;
394 std::vector
<BuilderLink
> Links
;
396 /// Adds the given element at the given index, merging sets if necessary.
397 bool addAtMerging(const T
&ToAdd
, StratifiedIndex Index
) {
398 StratifiedInfo Info
= {Index
};
399 auto Pair
= Values
.insert(std::make_pair(ToAdd
, Info
));
403 auto &Iter
= Pair
.first
;
404 auto &IterSet
= linksAt(Iter
->second
.Index
);
405 auto &ReqSet
= linksAt(Index
);
407 // Failed to add where we wanted to. Merge the sets.
408 if (&IterSet
!= &ReqSet
)
409 merge(IterSet
.Number
, ReqSet
.Number
);
414 /// Gets the BuilderLink at the given index, taking set remapping into
416 BuilderLink
&linksAt(StratifiedIndex Index
) {
417 auto *Start
= &Links
[Index
];
418 if (!Start
->isRemapped())
421 auto *Current
= Start
;
422 while (Current
->isRemapped())
423 Current
= &Links
[Current
->getRemapIndex()];
425 auto NewRemap
= Current
->Number
;
427 // Run through everything that has yet to be updated, and update them to
430 while (Current
->isRemapped()) {
431 auto *Next
= &Links
[Current
->getRemapIndex()];
432 Current
->updateRemap(NewRemap
);
439 /// Merges two sets into one another. Assumes that these sets are not
440 /// already one in the same.
441 void merge(StratifiedIndex Idx1
, StratifiedIndex Idx2
) {
442 assert(inbounds(Idx1
) && inbounds(Idx2
));
443 assert(&linksAt(Idx1
) != &linksAt(Idx2
) &&
444 "Merging a set into itself is not allowed");
446 // CASE 1: If the set at `Idx1` is above or below `Idx2`, we need to merge
448 // given sets, and all sets between them, into one.
449 if (tryMergeUpwards(Idx1
, Idx2
))
452 if (tryMergeUpwards(Idx2
, Idx1
))
455 // CASE 2: The set at `Idx1` is not in the same chain as the set at `Idx2`.
456 // We therefore need to merge the two chains together.
457 mergeDirect(Idx1
, Idx2
);
460 /// Merges two sets assuming that the set at `Idx1` is unreachable from
461 /// traversing above or below the set at `Idx2`.
462 void mergeDirect(StratifiedIndex Idx1
, StratifiedIndex Idx2
) {
463 assert(inbounds(Idx1
) && inbounds(Idx2
));
465 auto *LinksInto
= &linksAt(Idx1
);
466 auto *LinksFrom
= &linksAt(Idx2
);
467 // Merging everything above LinksInto then proceeding to merge everything
468 // below LinksInto becomes problematic, so we go as far "up" as possible!
469 while (LinksInto
->hasAbove() && LinksFrom
->hasAbove()) {
470 LinksInto
= &linksAt(LinksInto
->getAbove());
471 LinksFrom
= &linksAt(LinksFrom
->getAbove());
474 if (LinksFrom
->hasAbove()) {
475 LinksInto
->setAbove(LinksFrom
->getAbove());
476 auto &NewAbove
= linksAt(LinksInto
->getAbove());
477 NewAbove
.setBelow(LinksInto
->Number
);
481 // > If neither has links below, stop.
482 // > If only `LinksInto` has links below, stop.
483 // > If only `LinksFrom` has links below, reset `LinksInto.Below` to
484 // match `LinksFrom.Below`
485 // > If both have links above, deal with those next.
486 while (LinksInto
->hasBelow() && LinksFrom
->hasBelow()) {
487 auto FromAttrs
= LinksFrom
->getAttrs();
488 LinksInto
->setAttrs(FromAttrs
);
490 // Remap needs to happen after getBelow(), but before
491 // assignment of LinksFrom
492 auto *NewLinksFrom
= &linksAt(LinksFrom
->getBelow());
493 LinksFrom
->remapTo(LinksInto
->Number
);
494 LinksFrom
= NewLinksFrom
;
495 LinksInto
= &linksAt(LinksInto
->getBelow());
498 if (LinksFrom
->hasBelow()) {
499 LinksInto
->setBelow(LinksFrom
->getBelow());
500 auto &NewBelow
= linksAt(LinksInto
->getBelow());
501 NewBelow
.setAbove(LinksInto
->Number
);
504 LinksInto
->setAttrs(LinksFrom
->getAttrs());
505 LinksFrom
->remapTo(LinksInto
->Number
);
508 /// Checks to see if lowerIndex is at a level lower than upperIndex. If so, it
509 /// will merge lowerIndex with upperIndex (and all of the sets between) and
510 /// return true. Otherwise, it will return false.
511 bool tryMergeUpwards(StratifiedIndex LowerIndex
, StratifiedIndex UpperIndex
) {
512 assert(inbounds(LowerIndex
) && inbounds(UpperIndex
));
513 auto *Lower
= &linksAt(LowerIndex
);
514 auto *Upper
= &linksAt(UpperIndex
);
518 SmallVector
<BuilderLink
*, 8> Found
;
519 auto *Current
= Lower
;
520 auto Attrs
= Current
->getAttrs();
521 while (Current
->hasAbove() && Current
!= Upper
) {
522 Found
.push_back(Current
);
523 Attrs
|= Current
->getAttrs();
524 Current
= &linksAt(Current
->getAbove());
527 if (Current
!= Upper
)
530 Upper
->setAttrs(Attrs
);
532 if (Lower
->hasBelow()) {
533 auto NewBelowIndex
= Lower
->getBelow();
534 Upper
->setBelow(NewBelowIndex
);
535 auto &NewBelow
= linksAt(NewBelowIndex
);
536 NewBelow
.setAbove(UpperIndex
);
541 for (const auto &Ptr
: Found
)
542 Ptr
->remapTo(Upper
->Number
);
547 Optional
<const StratifiedInfo
*> get(const T
&Val
) const {
548 auto Result
= Values
.find(Val
);
549 if (Result
== Values
.end())
551 return &Result
->second
;
554 Optional
<StratifiedInfo
*> get(const T
&Val
) {
555 auto Result
= Values
.find(Val
);
556 if (Result
== Values
.end())
558 return &Result
->second
;
561 Optional
<StratifiedIndex
> indexOf(const T
&Val
) {
562 auto MaybeVal
= get(Val
);
563 if (!MaybeVal
.hasValue())
565 auto *Info
= *MaybeVal
;
566 auto &Link
= linksAt(Info
->Index
);
570 StratifiedIndex
addLinkBelow(StratifiedIndex Set
) {
571 auto At
= addLinks();
572 Links
[Set
].setBelow(At
);
573 Links
[At
].setAbove(Set
);
577 StratifiedIndex
addLinkAbove(StratifiedIndex Set
) {
578 auto At
= addLinks();
579 Links
[At
].setBelow(Set
);
580 Links
[Set
].setAbove(At
);
584 StratifiedIndex
getNewUnlinkedIndex() { return addLinks(); }
586 StratifiedIndex
addLinks() {
587 auto Link
= Links
.size();
588 Links
.push_back(BuilderLink(Link
));
592 bool inbounds(StratifiedIndex N
) const { return N
< Links
.size(); }
596 #endif // LLVM_ADT_STRATIFIEDSETS_H