003 File Manager
Current Path:
/usr/src/contrib/llvm-project/llvm/lib/Analysis
usr
/
src
/
contrib
/
llvm-project
/
llvm
/
lib
/
Analysis
/
📁
..
📄
AliasAnalysis.cpp
(33.55 KB)
📄
AliasAnalysisEvaluator.cpp
(15.64 KB)
📄
AliasAnalysisSummary.cpp
(3.49 KB)
📄
AliasAnalysisSummary.h
(10.17 KB)
📄
AliasSetTracker.cpp
(25.86 KB)
📄
Analysis.cpp
(5.29 KB)
📄
AssumeBundleQueries.cpp
(7.96 KB)
📄
AssumptionCache.cpp
(10.94 KB)
📄
BasicAliasAnalysis.cpp
(85.81 KB)
📄
BlockFrequencyInfo.cpp
(12.39 KB)
📄
BlockFrequencyInfoImpl.cpp
(28.6 KB)
📄
BranchProbabilityInfo.cpp
(43.48 KB)
📄
CFG.cpp
(9.9 KB)
📄
CFGPrinter.cpp
(11.2 KB)
📄
CFLAndersAliasAnalysis.cpp
(33.01 KB)
📄
CFLGraph.h
(21.23 KB)
📄
CFLSteensAliasAnalysis.cpp
(13.24 KB)
📄
CGSCCPassManager.cpp
(31.2 KB)
📄
CallGraph.cpp
(12.86 KB)
📄
CallGraphSCCPass.cpp
(26.31 KB)
📄
CallPrinter.cpp
(9.48 KB)
📄
CaptureTracking.cpp
(15.38 KB)
📄
CmpInstAnalysis.cpp
(4.63 KB)
📄
CodeMetrics.cpp
(6.99 KB)
📄
ConstantFolding.cpp
(105.15 KB)
📄
CostModel.cpp
(3.87 KB)
📄
DDG.cpp
(11.29 KB)
📄
Delinearization.cpp
(4.49 KB)
📄
DemandedBits.cpp
(16.27 KB)
📄
DependenceAnalysis.cpp
(150.78 KB)
📄
DependenceGraphBuilder.cpp
(19.24 KB)
📄
DivergenceAnalysis.cpp
(15.59 KB)
📄
DomPrinter.cpp
(9.67 KB)
📄
DomTreeUpdater.cpp
(15.21 KB)
📄
DominanceFrontier.cpp
(3.2 KB)
📄
EHPersonalities.cpp
(5.89 KB)
📄
GlobalsModRef.cpp
(41 KB)
📄
GuardUtils.cpp
(3.27 KB)
📄
HeatUtils.cpp
(2.85 KB)
📄
IVDescriptors.cpp
(42.28 KB)
📄
IVUsers.cpp
(16.12 KB)
📄
IndirectCallPromotionAnalysis.cpp
(4.33 KB)
📄
InlineAdvisor.cpp
(15.28 KB)
📄
InlineCost.cpp
(99.47 KB)
📄
InlineFeaturesAnalysis.cpp
(1.59 KB)
📄
InlineSizeEstimatorAnalysis.cpp
(10.95 KB)
📄
InstCount.cpp
(2.45 KB)
📄
InstructionPrecedenceTracking.cpp
(4.8 KB)
📄
InstructionSimplify.cpp
(216.91 KB)
📄
Interval.cpp
(1.78 KB)
📄
IntervalPartition.cpp
(4.5 KB)
📄
LazyBlockFrequencyInfo.cpp
(2.81 KB)
📄
LazyBranchProbabilityInfo.cpp
(2.96 KB)
📄
LazyCallGraph.cpp
(67.33 KB)
📄
LazyValueInfo.cpp
(76.38 KB)
📄
LegacyDivergenceAnalysis.cpp
(14.82 KB)
📄
Lint.cpp
(29.07 KB)
📄
Loads.cpp
(20.6 KB)
📄
LoopAccessAnalysis.cpp
(88.02 KB)
📄
LoopAnalysisManager.cpp
(6.6 KB)
📄
LoopCacheAnalysis.cpp
(23.53 KB)
📄
LoopInfo.cpp
(37.15 KB)
📄
LoopNestAnalysis.cpp
(10.62 KB)
📄
LoopPass.cpp
(12.89 KB)
📄
LoopUnrollAnalyzer.cpp
(7.26 KB)
📄
MLInlineAdvisor.cpp
(11.36 KB)
📄
MemDepPrinter.cpp
(5.13 KB)
📄
MemDerefPrinter.cpp
(2.53 KB)
📄
MemoryBuiltins.cpp
(41.14 KB)
📄
MemoryDependenceAnalysis.cpp
(69.89 KB)
📄
MemoryLocation.cpp
(7.92 KB)
📄
MemorySSA.cpp
(90.16 KB)
📄
MemorySSAUpdater.cpp
(57.9 KB)
📄
ModuleDebugInfoPrinter.cpp
(4.02 KB)
📄
ModuleSummaryAnalysis.cpp
(38.13 KB)
📄
MustExecute.cpp
(31.18 KB)
📄
ObjCARCAliasAnalysis.cpp
(5.81 KB)
📄
ObjCARCAnalysisUtils.cpp
(1.07 KB)
📄
ObjCARCInstKind.cpp
(23.15 KB)
📄
OptimizationRemarkEmitter.cpp
(4.23 KB)
📄
PHITransAddr.cpp
(16.05 KB)
📄
PhiValues.cpp
(8.4 KB)
📄
PostDominators.cpp
(3.59 KB)
📄
ProfileSummaryInfo.cpp
(18.07 KB)
📄
PtrUseVisitor.cpp
(1.28 KB)
📄
RegionInfo.cpp
(6.5 KB)
📄
RegionPass.cpp
(9.23 KB)
📄
RegionPrinter.cpp
(8.61 KB)
📄
ReleaseModeModelRunner.cpp
(2.83 KB)
📄
ScalarEvolution.cpp
(475.26 KB)
📄
ScalarEvolutionAliasAnalysis.cpp
(5.96 KB)
📄
ScalarEvolutionDivision.cpp
(7.51 KB)
📄
ScalarEvolutionNormalization.cpp
(4.59 KB)
📄
ScopedNoAliasAA.cpp
(7.38 KB)
📄
StackLifetime.cpp
(12.22 KB)
📄
StackSafetyAnalysis.cpp
(31.81 KB)
📄
StratifiedSets.h
(18.67 KB)
📄
SyncDependenceAnalysis.cpp
(12.97 KB)
📄
SyntheticCountsUtils.cpp
(3.81 KB)
📄
TFUtils.cpp
(8.99 KB)
📄
TargetLibraryInfo.cpp
(58.98 KB)
📄
TargetTransformInfo.cpp
(48.15 KB)
📄
Trace.cpp
(1.8 KB)
📄
TypeBasedAliasAnalysis.cpp
(26.04 KB)
📄
TypeMetadataUtils.cpp
(5.93 KB)
📄
VFABIDemangling.cpp
(16.46 KB)
📄
ValueLattice.cpp
(1.19 KB)
📄
ValueLatticeUtils.cpp
(1.53 KB)
📄
ValueTracking.cpp
(243.08 KB)
📄
VectorUtils.cpp
(48.57 KB)
📁
models
Editing: StratifiedSets.h
//===- StratifiedSets.h - Abstract stratified sets implementation. --------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_ADT_STRATIFIEDSETS_H #define LLVM_ADT_STRATIFIEDSETS_H #include "AliasAnalysisSummary.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include <bitset> #include <cassert> #include <cmath> #include <type_traits> #include <utility> #include <vector> namespace llvm { namespace cflaa { /// An index into Stratified Sets. typedef unsigned StratifiedIndex; /// NOTE: ^ This can't be a short -- bootstrapping clang has a case where /// ~1M sets exist. // Container of information related to a value in a StratifiedSet. struct StratifiedInfo { StratifiedIndex Index; /// For field sensitivity, etc. we can tack fields on here. }; /// A "link" between two StratifiedSets. struct StratifiedLink { /// This is a value used to signify "does not exist" where the /// StratifiedIndex type is used. /// /// This is used instead of Optional<StratifiedIndex> because /// Optional<StratifiedIndex> would eat up a considerable amount of extra /// memory, after struct padding/alignment is taken into account. static const StratifiedIndex SetSentinel; /// The index for the set "above" current StratifiedIndex Above; /// The link for the set "below" current StratifiedIndex Below; /// Attributes for these StratifiedSets. AliasAttrs Attrs; StratifiedLink() : Above(SetSentinel), Below(SetSentinel) {} bool hasBelow() const { return Below != SetSentinel; } bool hasAbove() const { return Above != SetSentinel; } void clearBelow() { Below = SetSentinel; } void clearAbove() { Above = SetSentinel; } }; /// These are stratified sets, as described in "Fast algorithms for /// Dyck-CFL-reachability with applications to Alias Analysis" by Zhang Q, Lyu M /// R, Yuan H, and Su Z. -- in short, this is meant to represent different sets /// of Value*s. If two Value*s are in the same set, or if both sets have /// overlapping attributes, then the Value*s are said to alias. /// /// Sets may be related by position, meaning that one set may be considered as /// above or below another. In CFL Alias Analysis, this gives us an indication /// of how two variables are related; if the set of variable A is below a set /// containing variable B, then at some point, a variable that has interacted /// with B (or B itself) was either used in order to extract the variable A, or /// was used as storage of variable A. /// /// Sets may also have attributes (as noted above). These attributes are /// generally used for noting whether a variable in the set has interacted with /// a variable whose origins we don't quite know (i.e. globals/arguments), or if /// the variable may have had operations performed on it (modified in a function /// call). All attributes that exist in a set A must exist in all sets marked as /// below set A. template <typename T> class StratifiedSets { public: StratifiedSets() = default; StratifiedSets(StratifiedSets &&) = default; StratifiedSets &operator=(StratifiedSets &&) = default; StratifiedSets(DenseMap<T, StratifiedInfo> Map, std::vector<StratifiedLink> Links) : Values(std::move(Map)), Links(std::move(Links)) {} Optional<StratifiedInfo> find(const T &Elem) const { auto Iter = Values.find(Elem); if (Iter == Values.end()) return None; return Iter->second; } const StratifiedLink &getLink(StratifiedIndex Index) const { assert(inbounds(Index)); return Links[Index]; } private: DenseMap<T, StratifiedInfo> Values; std::vector<StratifiedLink> Links; bool inbounds(StratifiedIndex Idx) const { return Idx < Links.size(); } }; /// Generic Builder class that produces StratifiedSets instances. /// /// The goal of this builder is to efficiently produce correct StratifiedSets /// instances. To this end, we use a few tricks: /// > Set chains (A method for linking sets together) /// > Set remaps (A method for marking a set as an alias [irony?] of another) /// /// ==== Set chains ==== /// This builder has a notion of some value A being above, below, or with some /// other value B: /// > The `A above B` relationship implies that there is a reference edge /// going from A to B. Namely, it notes that A can store anything in B's set. /// > The `A below B` relationship is the opposite of `A above B`. It implies /// that there's a dereference edge going from A to B. /// > The `A with B` relationship states that there's an assignment edge going /// from A to B, and that A and B should be treated as equals. /// /// As an example, take the following code snippet: /// /// %a = alloca i32, align 4 /// %ap = alloca i32*, align 8 /// %app = alloca i32**, align 8 /// store %a, %ap /// store %ap, %app /// %aw = getelementptr %ap, i32 0 /// /// Given this, the following relations exist: /// - %a below %ap & %ap above %a /// - %ap below %app & %app above %ap /// - %aw with %ap & %ap with %aw /// /// These relations produce the following sets: /// [{%a}, {%ap, %aw}, {%app}] /// /// ...Which state that the only MayAlias relationship in the above program is /// between %ap and %aw. /// /// Because LLVM allows arbitrary casts, code like the following needs to be /// supported: /// %ip = alloca i64, align 8 /// %ipp = alloca i64*, align 8 /// %i = bitcast i64** ipp to i64 /// store i64* %ip, i64** %ipp /// store i64 %i, i64* %ip /// /// Which, because %ipp ends up *both* above and below %ip, is fun. /// /// This is solved by merging %i and %ipp into a single set (...which is the /// only way to solve this, since their bit patterns are equivalent). Any sets /// that ended up in between %i and %ipp at the time of merging (in this case, /// the set containing %ip) also get conservatively merged into the set of %i /// and %ipp. In short, the resulting StratifiedSet from the above code would be /// {%ip, %ipp, %i}. /// /// ==== Set remaps ==== /// More of an implementation detail than anything -- when merging sets, we need /// to update the numbers of all of the elements mapped to those sets. Rather /// than doing this at each merge, we note in the BuilderLink structure that a /// remap has occurred, and use this information so we can defer renumbering set /// elements until build time. template <typename T> class StratifiedSetsBuilder { /// Represents a Stratified Set, with information about the Stratified /// Set above it, the set below it, and whether the current set has been /// remapped to another. struct BuilderLink { const StratifiedIndex Number; BuilderLink(StratifiedIndex N) : Number(N) { Remap = StratifiedLink::SetSentinel; } bool hasAbove() const { assert(!isRemapped()); return Link.hasAbove(); } bool hasBelow() const { assert(!isRemapped()); return Link.hasBelow(); } void setBelow(StratifiedIndex I) { assert(!isRemapped()); Link.Below = I; } void setAbove(StratifiedIndex I) { assert(!isRemapped()); Link.Above = I; } void clearBelow() { assert(!isRemapped()); Link.clearBelow(); } void clearAbove() { assert(!isRemapped()); Link.clearAbove(); } StratifiedIndex getBelow() const { assert(!isRemapped()); assert(hasBelow()); return Link.Below; } StratifiedIndex getAbove() const { assert(!isRemapped()); assert(hasAbove()); return Link.Above; } AliasAttrs getAttrs() { assert(!isRemapped()); return Link.Attrs; } void setAttrs(AliasAttrs Other) { assert(!isRemapped()); Link.Attrs |= Other; } bool isRemapped() const { return Remap != StratifiedLink::SetSentinel; } /// For initial remapping to another set void remapTo(StratifiedIndex Other) { assert(!isRemapped()); Remap = Other; } StratifiedIndex getRemapIndex() const { assert(isRemapped()); return Remap; } /// Should only be called when we're already remapped. void updateRemap(StratifiedIndex Other) { assert(isRemapped()); Remap = Other; } /// Prefer the above functions to calling things directly on what's returned /// from this -- they guard against unexpected calls when the current /// BuilderLink is remapped. const StratifiedLink &getLink() const { return Link; } private: StratifiedLink Link; StratifiedIndex Remap; }; /// This function performs all of the set unioning/value renumbering /// that we've been putting off, and generates a vector<StratifiedLink> that /// may be placed in a StratifiedSets instance. void finalizeSets(std::vector<StratifiedLink> &StratLinks) { DenseMap<StratifiedIndex, StratifiedIndex> Remaps; for (auto &Link : Links) { if (Link.isRemapped()) continue; StratifiedIndex Number = StratLinks.size(); Remaps.insert(std::make_pair(Link.Number, Number)); StratLinks.push_back(Link.getLink()); } for (auto &Link : StratLinks) { if (Link.hasAbove()) { auto &Above = linksAt(Link.Above); auto Iter = Remaps.find(Above.Number); assert(Iter != Remaps.end()); Link.Above = Iter->second; } if (Link.hasBelow()) { auto &Below = linksAt(Link.Below); auto Iter = Remaps.find(Below.Number); assert(Iter != Remaps.end()); Link.Below = Iter->second; } } for (auto &Pair : Values) { auto &Info = Pair.second; auto &Link = linksAt(Info.Index); auto Iter = Remaps.find(Link.Number); assert(Iter != Remaps.end()); Info.Index = Iter->second; } } /// There's a guarantee in StratifiedLink where all bits set in a /// Link.externals will be set in all Link.externals "below" it. static void propagateAttrs(std::vector<StratifiedLink> &Links) { const auto getHighestParentAbove = [&Links](StratifiedIndex Idx) { const auto *Link = &Links[Idx]; while (Link->hasAbove()) { Idx = Link->Above; Link = &Links[Idx]; } return Idx; }; SmallSet<StratifiedIndex, 16> Visited; for (unsigned I = 0, E = Links.size(); I < E; ++I) { auto CurrentIndex = getHighestParentAbove(I); if (!Visited.insert(CurrentIndex).second) continue; while (Links[CurrentIndex].hasBelow()) { auto &CurrentBits = Links[CurrentIndex].Attrs; auto NextIndex = Links[CurrentIndex].Below; auto &NextBits = Links[NextIndex].Attrs; NextBits |= CurrentBits; CurrentIndex = NextIndex; } } } public: /// Builds a StratifiedSet from the information we've been given since either /// construction or the prior build() call. StratifiedSets<T> build() { std::vector<StratifiedLink> StratLinks; finalizeSets(StratLinks); propagateAttrs(StratLinks); Links.clear(); return StratifiedSets<T>(std::move(Values), std::move(StratLinks)); } bool has(const T &Elem) const { return get(Elem).hasValue(); } bool add(const T &Main) { if (get(Main).hasValue()) return false; auto NewIndex = getNewUnlinkedIndex(); return addAtMerging(Main, NewIndex); } /// Restructures the stratified sets as necessary to make "ToAdd" in a /// set above "Main". There are some cases where this is not possible (see /// above), so we merge them such that ToAdd and Main are in the same set. bool addAbove(const T &Main, const T &ToAdd) { assert(has(Main)); auto Index = *indexOf(Main); if (!linksAt(Index).hasAbove()) addLinkAbove(Index); auto Above = linksAt(Index).getAbove(); return addAtMerging(ToAdd, Above); } /// Restructures the stratified sets as necessary to make "ToAdd" in a /// set below "Main". There are some cases where this is not possible (see /// above), so we merge them such that ToAdd and Main are in the same set. bool addBelow(const T &Main, const T &ToAdd) { assert(has(Main)); auto Index = *indexOf(Main); if (!linksAt(Index).hasBelow()) addLinkBelow(Index); auto Below = linksAt(Index).getBelow(); return addAtMerging(ToAdd, Below); } bool addWith(const T &Main, const T &ToAdd) { assert(has(Main)); auto MainIndex = *indexOf(Main); return addAtMerging(ToAdd, MainIndex); } void noteAttributes(const T &Main, AliasAttrs NewAttrs) { assert(has(Main)); auto *Info = *get(Main); auto &Link = linksAt(Info->Index); Link.setAttrs(NewAttrs); } private: DenseMap<T, StratifiedInfo> Values; std::vector<BuilderLink> Links; /// Adds the given element at the given index, merging sets if necessary. bool addAtMerging(const T &ToAdd, StratifiedIndex Index) { StratifiedInfo Info = {Index}; auto Pair = Values.insert(std::make_pair(ToAdd, Info)); if (Pair.second) return true; auto &Iter = Pair.first; auto &IterSet = linksAt(Iter->second.Index); auto &ReqSet = linksAt(Index); // Failed to add where we wanted to. Merge the sets. if (&IterSet != &ReqSet) merge(IterSet.Number, ReqSet.Number); return false; } /// Gets the BuilderLink at the given index, taking set remapping into /// account. BuilderLink &linksAt(StratifiedIndex Index) { auto *Start = &Links[Index]; if (!Start->isRemapped()) return *Start; auto *Current = Start; while (Current->isRemapped()) Current = &Links[Current->getRemapIndex()]; auto NewRemap = Current->Number; // Run through everything that has yet to be updated, and update them to // remap to NewRemap Current = Start; while (Current->isRemapped()) { auto *Next = &Links[Current->getRemapIndex()]; Current->updateRemap(NewRemap); Current = Next; } return *Current; } /// Merges two sets into one another. Assumes that these sets are not /// already one in the same. void merge(StratifiedIndex Idx1, StratifiedIndex Idx2) { assert(inbounds(Idx1) && inbounds(Idx2)); assert(&linksAt(Idx1) != &linksAt(Idx2) && "Merging a set into itself is not allowed"); // CASE 1: If the set at `Idx1` is above or below `Idx2`, we need to merge // both the // given sets, and all sets between them, into one. if (tryMergeUpwards(Idx1, Idx2)) return; if (tryMergeUpwards(Idx2, Idx1)) return; // CASE 2: The set at `Idx1` is not in the same chain as the set at `Idx2`. // We therefore need to merge the two chains together. mergeDirect(Idx1, Idx2); } /// Merges two sets assuming that the set at `Idx1` is unreachable from /// traversing above or below the set at `Idx2`. void mergeDirect(StratifiedIndex Idx1, StratifiedIndex Idx2) { assert(inbounds(Idx1) && inbounds(Idx2)); auto *LinksInto = &linksAt(Idx1); auto *LinksFrom = &linksAt(Idx2); // Merging everything above LinksInto then proceeding to merge everything // below LinksInto becomes problematic, so we go as far "up" as possible! while (LinksInto->hasAbove() && LinksFrom->hasAbove()) { LinksInto = &linksAt(LinksInto->getAbove()); LinksFrom = &linksAt(LinksFrom->getAbove()); } if (LinksFrom->hasAbove()) { LinksInto->setAbove(LinksFrom->getAbove()); auto &NewAbove = linksAt(LinksInto->getAbove()); NewAbove.setBelow(LinksInto->Number); } // Merging strategy: // > If neither has links below, stop. // > If only `LinksInto` has links below, stop. // > If only `LinksFrom` has links below, reset `LinksInto.Below` to // match `LinksFrom.Below` // > If both have links above, deal with those next. while (LinksInto->hasBelow() && LinksFrom->hasBelow()) { auto FromAttrs = LinksFrom->getAttrs(); LinksInto->setAttrs(FromAttrs); // Remap needs to happen after getBelow(), but before // assignment of LinksFrom auto *NewLinksFrom = &linksAt(LinksFrom->getBelow()); LinksFrom->remapTo(LinksInto->Number); LinksFrom = NewLinksFrom; LinksInto = &linksAt(LinksInto->getBelow()); } if (LinksFrom->hasBelow()) { LinksInto->setBelow(LinksFrom->getBelow()); auto &NewBelow = linksAt(LinksInto->getBelow()); NewBelow.setAbove(LinksInto->Number); } LinksInto->setAttrs(LinksFrom->getAttrs()); LinksFrom->remapTo(LinksInto->Number); } /// Checks to see if lowerIndex is at a level lower than upperIndex. If so, it /// will merge lowerIndex with upperIndex (and all of the sets between) and /// return true. Otherwise, it will return false. bool tryMergeUpwards(StratifiedIndex LowerIndex, StratifiedIndex UpperIndex) { assert(inbounds(LowerIndex) && inbounds(UpperIndex)); auto *Lower = &linksAt(LowerIndex); auto *Upper = &linksAt(UpperIndex); if (Lower == Upper) return true; SmallVector<BuilderLink *, 8> Found; auto *Current = Lower; auto Attrs = Current->getAttrs(); while (Current->hasAbove() && Current != Upper) { Found.push_back(Current); Attrs |= Current->getAttrs(); Current = &linksAt(Current->getAbove()); } if (Current != Upper) return false; Upper->setAttrs(Attrs); if (Lower->hasBelow()) { auto NewBelowIndex = Lower->getBelow(); Upper->setBelow(NewBelowIndex); auto &NewBelow = linksAt(NewBelowIndex); NewBelow.setAbove(UpperIndex); } else { Upper->clearBelow(); } for (const auto &Ptr : Found) Ptr->remapTo(Upper->Number); return true; } Optional<const StratifiedInfo *> get(const T &Val) const { auto Result = Values.find(Val); if (Result == Values.end()) return None; return &Result->second; } Optional<StratifiedInfo *> get(const T &Val) { auto Result = Values.find(Val); if (Result == Values.end()) return None; return &Result->second; } Optional<StratifiedIndex> indexOf(const T &Val) { auto MaybeVal = get(Val); if (!MaybeVal.hasValue()) return None; auto *Info = *MaybeVal; auto &Link = linksAt(Info->Index); return Link.Number; } StratifiedIndex addLinkBelow(StratifiedIndex Set) { auto At = addLinks(); Links[Set].setBelow(At); Links[At].setAbove(Set); return At; } StratifiedIndex addLinkAbove(StratifiedIndex Set) { auto At = addLinks(); Links[At].setBelow(Set); Links[Set].setAbove(At); return At; } StratifiedIndex getNewUnlinkedIndex() { return addLinks(); } StratifiedIndex addLinks() { auto Link = Links.size(); Links.push_back(BuilderLink(Link)); return Link; } bool inbounds(StratifiedIndex N) const { return N < Links.size(); } }; } } #endif // LLVM_ADT_STRATIFIEDSETS_H
Upload File
Create Folder