forked from OSchip/llvm-project
parent
748b06514a
commit
cae581d13f
|
@ -62,7 +62,7 @@ CFLAAResult::CFLAAResult() : AAResultBase() {}
|
|||
CFLAAResult::CFLAAResult(CFLAAResult &&Arg) : AAResultBase(std::move(Arg)) {}
|
||||
CFLAAResult::~CFLAAResult() {}
|
||||
|
||||
// \brief Information we have about a function and would like to keep around
|
||||
/// Information we have about a function and would like to keep around.
|
||||
struct CFLAAResult::FunctionInfo {
|
||||
StratifiedSets<Value *> Sets;
|
||||
// Lots of functions have < 4 returns. Adjust as necessary.
|
||||
|
@ -72,33 +72,31 @@ struct CFLAAResult::FunctionInfo {
|
|||
: Sets(std::move(S)), ReturnedValues(std::move(RV)) {}
|
||||
};
|
||||
|
||||
// Try to go from a Value* to a Function*. Never returns nullptr.
|
||||
/// Try to go from a Value* to a Function*. Never returns nullptr.
|
||||
static Optional<Function *> parentFunctionOfValue(Value *);
|
||||
|
||||
// Returns possible functions called by the Inst* into the given
|
||||
// SmallVectorImpl. Returns true if targets found, false otherwise.
|
||||
// This is templated because InvokeInst/CallInst give us the same
|
||||
// set of functions that we care about, and I don't like repeating
|
||||
// myself.
|
||||
/// Returns possible functions called by the Inst* into the given
|
||||
/// SmallVectorImpl. Returns true if targets found, false otherwise. This is
|
||||
/// templated so we can use it with CallInsts and InvokeInsts.
|
||||
template <typename Inst>
|
||||
static bool getPossibleTargets(Inst *, SmallVectorImpl<Function *> &);
|
||||
|
||||
// Some instructions need to have their users tracked. Instructions like
|
||||
// `add` require you to get the users of the Instruction* itself, other
|
||||
// instructions like `store` require you to get the users of the first
|
||||
// operand. This function gets the "proper" value to track for each
|
||||
// type of instruction we support.
|
||||
/// Some instructions need to have their users tracked. Instructions like
|
||||
/// `add` require you to get the users of the Instruction* itself, other
|
||||
/// instructions like `store` require you to get the users of the first
|
||||
/// operand. This function gets the "proper" value to track for each
|
||||
/// type of instruction we support.
|
||||
static Optional<Value *> getTargetValue(Instruction *);
|
||||
|
||||
// There are certain instructions (i.e. FenceInst, etc.) that we ignore.
|
||||
// This notes that we should ignore those.
|
||||
/// Determines whether or not we an instruction is useless to us (e.g.
|
||||
/// FenceInst)
|
||||
static bool hasUsefulEdges(Instruction *);
|
||||
|
||||
const StratifiedIndex StratifiedLink::SetSentinel =
|
||||
std::numeric_limits<StratifiedIndex>::max();
|
||||
|
||||
namespace {
|
||||
// StratifiedInfo Attribute things.
|
||||
/// StratifiedInfo Attribute things.
|
||||
typedef unsigned StratifiedAttr;
|
||||
LLVM_CONSTEXPR unsigned MaxStratifiedAttrIndex = NumStratifiedAttrs;
|
||||
LLVM_CONSTEXPR unsigned AttrAllIndex = 0;
|
||||
|
@ -112,53 +110,53 @@ LLVM_CONSTEXPR StratifiedAttr AttrNone = 0;
|
|||
LLVM_CONSTEXPR StratifiedAttr AttrUnknown = 1 << AttrUnknownIndex;
|
||||
LLVM_CONSTEXPR StratifiedAttr AttrAll = ~AttrNone;
|
||||
|
||||
// \brief StratifiedSets call for knowledge of "direction", so this is how we
|
||||
// represent that locally.
|
||||
/// StratifiedSets call for knowledge of "direction", so this is how we
|
||||
/// represent that locally.
|
||||
enum class Level { Same, Above, Below };
|
||||
|
||||
// \brief Edges can be one of four "weights" -- each weight must have an inverse
|
||||
// weight (Assign has Assign; Reference has Dereference).
|
||||
/// Edges can be one of four "weights" -- each weight must have an inverse
|
||||
/// weight (Assign has Assign; Reference has Dereference).
|
||||
enum class EdgeType {
|
||||
// The weight assigned when assigning from or to a value. For example, in:
|
||||
// %b = getelementptr %a, 0
|
||||
// ...The relationships are %b assign %a, and %a assign %b. This used to be
|
||||
// two edges, but having a distinction bought us nothing.
|
||||
/// The weight assigned when assigning from or to a value. For example, in:
|
||||
/// %b = getelementptr %a, 0
|
||||
/// ...The relationships are %b assign %a, and %a assign %b. This used to be
|
||||
/// two edges, but having a distinction bought us nothing.
|
||||
Assign,
|
||||
|
||||
// The edge used when we have an edge going from some handle to a Value.
|
||||
// Examples of this include:
|
||||
// %b = load %a (%b Dereference %a)
|
||||
// %b = extractelement %a, 0 (%a Dereference %b)
|
||||
/// The edge used when we have an edge going from some handle to a Value.
|
||||
/// Examples of this include:
|
||||
/// %b = load %a (%b Dereference %a)
|
||||
/// %b = extractelement %a, 0 (%a Dereference %b)
|
||||
Dereference,
|
||||
|
||||
// The edge used when our edge goes from a value to a handle that may have
|
||||
// contained it at some point. Examples:
|
||||
// %b = load %a (%a Reference %b)
|
||||
// %b = extractelement %a, 0 (%b Reference %a)
|
||||
/// The edge used when our edge goes from a value to a handle that may have
|
||||
/// contained it at some point. Examples:
|
||||
/// %b = load %a (%a Reference %b)
|
||||
/// %b = extractelement %a, 0 (%b Reference %a)
|
||||
Reference
|
||||
};
|
||||
|
||||
// \brief Encodes the notion of a "use"
|
||||
struct Edge {
|
||||
// \brief Which value the edge is coming from
|
||||
/// Which value the edge is coming from
|
||||
Value *From;
|
||||
|
||||
// \brief Which value the edge is pointing to
|
||||
/// Which value the edge is pointing to
|
||||
Value *To;
|
||||
|
||||
// \brief Edge weight
|
||||
/// Edge weight
|
||||
EdgeType Weight;
|
||||
|
||||
// \brief Whether we aliased any external values along the way that may be
|
||||
// invisible to the analysis (i.e. landingpad for exceptions, calls for
|
||||
// interprocedural analysis, etc.)
|
||||
/// Whether we aliased any external values along the way that may be
|
||||
/// invisible to the analysis (i.e. landingpad for exceptions, calls for
|
||||
/// interprocedural analysis, etc.)
|
||||
StratifiedAttrs AdditionalAttrs;
|
||||
|
||||
Edge(Value *From, Value *To, EdgeType W, StratifiedAttrs A)
|
||||
: From(From), To(To), Weight(W), AdditionalAttrs(A) {}
|
||||
};
|
||||
|
||||
// \brief Gets the edges our graph should have, based on an Instruction*
|
||||
/// Gets the edges our graph should have, based on an Instruction*
|
||||
class GetEdgesVisitor : public InstVisitor<GetEdgesVisitor, void> {
|
||||
CFLAAResult &AA;
|
||||
SmallVectorImpl<Edge> &Output;
|
||||
|
@ -258,8 +256,8 @@ public:
|
|||
return Fn->isDeclaration() || !Fn->hasLocalLinkage();
|
||||
}
|
||||
|
||||
// Gets whether the sets at Index1 above, below, or equal to the sets at
|
||||
// Index2. Returns None if they are not in the same set chain.
|
||||
/// Gets whether the sets at Index1 above, below, or equal to the sets at
|
||||
/// Index2. Returns None if they are not in the same set chain.
|
||||
static Optional<Level> getIndexRelation(const StratifiedSets<Value *> &Sets,
|
||||
StratifiedIndex Index1,
|
||||
StratifiedIndex Index2) {
|
||||
|
@ -291,8 +289,8 @@ public:
|
|||
const unsigned MaxSupportedArgs = 50;
|
||||
assert(Fns.size() > 0);
|
||||
|
||||
// I put this here to give us an upper bound on time taken by IPA. Is it
|
||||
// really (realistically) needed? Keep in mind that we do have an n^2 algo.
|
||||
// This algorithm is n^2, so an arbitrary upper-bound of 50 args was
|
||||
// selected, so it doesn't take too long in insane cases.
|
||||
if (std::distance(Args.begin(), Args.end()) > (int)MaxSupportedArgs)
|
||||
return false;
|
||||
|
||||
|
@ -351,12 +349,12 @@ public:
|
|||
if (Parameters.size() != Arguments.size())
|
||||
return false;
|
||||
|
||||
// Adding edges between arguments for arguments that may end up aliasing
|
||||
// each other. This is necessary for functions such as
|
||||
// void foo(int** a, int** b) { *a = *b; }
|
||||
// (Technically, the proper sets for this would be those below
|
||||
// Arguments[I] and Arguments[X], but our algorithm will produce
|
||||
// extremely similar, and equally correct, results either way)
|
||||
/// Adding edges between arguments for arguments that may end up aliasing
|
||||
/// each other. This is necessary for functions such as
|
||||
/// void foo(int** a, int** b) { *a = *b; }
|
||||
/// (Technically, the proper sets for this would be those below
|
||||
/// Arguments[I] and Arguments[X], but our algorithm will produce
|
||||
/// extremely similar, and equally correct, results either way)
|
||||
for (unsigned I = 0, E = Arguments.size(); I != E; ++I) {
|
||||
auto &MainVal = Arguments[I];
|
||||
auto &MainInfo = Parameters[I];
|
||||
|
@ -406,11 +404,10 @@ public:
|
|||
|
||||
void visitInvokeInst(InvokeInst &Inst) { visitCallLikeInst(Inst); }
|
||||
|
||||
// Because vectors/aggregates are immutable and unaddressable,
|
||||
// there's nothing we can do to coax a value out of them, other
|
||||
// than calling Extract{Element,Value}. We can effectively treat
|
||||
// them as pointers to arbitrary memory locations we can store in
|
||||
// and load from.
|
||||
/// Because vectors/aggregates are immutable and unaddressable, there's
|
||||
/// nothing we can do to coax a value out of them, other than calling
|
||||
/// Extract{Element,Value}. We can effectively treat them as pointers to
|
||||
/// arbitrary memory locations we can store in and load from.
|
||||
void visitExtractElementInst(ExtractElementInst &Inst) {
|
||||
auto *Ptr = Inst.getVectorOperand();
|
||||
auto *Val = &Inst;
|
||||
|
@ -464,16 +461,16 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
// For a given instruction, we need to know which Value* to get the
|
||||
// users of in order to build our graph. In some cases (i.e. add),
|
||||
// we simply need the Instruction*. In other cases (i.e. store),
|
||||
// finding the users of the Instruction* is useless; we need to find
|
||||
// the users of the first operand. This handles determining which
|
||||
// value to follow for us.
|
||||
//
|
||||
// Note: we *need* to keep this in sync with GetEdgesVisitor. Add
|
||||
// something to GetEdgesVisitor, add it here -- remove something from
|
||||
// GetEdgesVisitor, remove it here.
|
||||
/// For a given instruction, we need to know which Value* to get the
|
||||
/// users of in order to build our graph. In some cases (i.e. add),
|
||||
/// we simply need the Instruction*. In other cases (i.e. store),
|
||||
/// finding the users of the Instruction* is useless; we need to find
|
||||
/// the users of the first operand. This handles determining which
|
||||
/// value to follow for us.
|
||||
///
|
||||
/// Note: we *need* to keep this in sync with GetEdgesVisitor. Add
|
||||
/// something to GetEdgesVisitor, add it here -- remove something from
|
||||
/// GetEdgesVisitor, remove it here.
|
||||
class GetTargetValueVisitor
|
||||
: public InstVisitor<GetTargetValueVisitor, Value *> {
|
||||
public:
|
||||
|
@ -498,7 +495,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
// Set building requires a weighted bidirectional graph.
|
||||
/// Set building requires a weighted bidirectional graph.
|
||||
template <typename EdgeTypeT> class WeightedBidirectionalGraph {
|
||||
public:
|
||||
typedef std::size_t Node;
|
||||
|
@ -531,12 +528,10 @@ private:
|
|||
NodeImpl &getNode(Node N) { return NodeImpls[N]; }
|
||||
|
||||
public:
|
||||
// ----- Various Edge iterators for the graph ----- //
|
||||
|
||||
// \brief Iterator for edges. Because this graph is bidirected, we don't
|
||||
// allow modification of the edges using this iterator. Additionally, the
|
||||
// iterator becomes invalid if you add edges to or from the node you're
|
||||
// getting the edges of.
|
||||
/// \brief Iterator for edges. Because this graph is bidirected, we don't
|
||||
/// allow modification of the edges using this iterator. Additionally, the
|
||||
/// iterator becomes invalid if you add edges to or from the node you're
|
||||
/// getting the edges of.
|
||||
struct EdgeIterator : public std::iterator<std::forward_iterator_tag,
|
||||
std::tuple<EdgeTypeT, Node *>> {
|
||||
EdgeIterator(const typename std::vector<Edge>::const_iterator &Iter)
|
||||
|
@ -573,7 +568,7 @@ public:
|
|||
std::tuple<EdgeTypeT, Node> Store;
|
||||
};
|
||||
|
||||
// Wrapper for EdgeIterator with begin()/end() calls.
|
||||
/// Wrapper for EdgeIterator with begin()/end() calls.
|
||||
struct EdgeIterable {
|
||||
EdgeIterable(const std::vector<Edge> &Edges)
|
||||
: BeginIter(Edges.begin()), EndIter(Edges.end()) {}
|
||||
|
@ -617,16 +612,16 @@ public:
|
|||
ToNode.Edges.push_back(Edge(ReverseWeight, From));
|
||||
}
|
||||
|
||||
EdgeIterable edgesFor(const Node &N) const {
|
||||
iterator_range<EdgeIterator> edgesFor(const Node &N) const {
|
||||
const auto &Node = getNode(N);
|
||||
return EdgeIterable(Node.Edges);
|
||||
return make_range(EdgeIterator(Node.Edges.begin()),
|
||||
EdgeIterator(Node.Edges.end()));
|
||||
}
|
||||
|
||||
bool empty() const { return NodeImpls.empty(); }
|
||||
std::size_t size() const { return NodeImpls.size(); }
|
||||
|
||||
// \brief Gets an arbitrary node in the graph as a starting point for
|
||||
// traversal.
|
||||
/// Gets an arbitrary node in the graph as a starting point for traversal.
|
||||
Node getEntryNode() {
|
||||
assert(inbounds(StartNode));
|
||||
return StartNode;
|
||||
|
@ -641,47 +636,47 @@ typedef DenseMap<Value *, GraphT::Node> NodeMapT;
|
|||
// Function declarations that require types defined in the namespace above
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Given an argument number, returns the appropriate Attr index to set.
|
||||
static StratifiedAttr argNumberToAttrIndex(StratifiedAttr);
|
||||
/// Given an argument number, returns the appropriate Attr index to set.
|
||||
static StratifiedAttr argNumberToAttrIndex(unsigned ArgNum);
|
||||
|
||||
// Given a Value, potentially return which AttrIndex it maps to.
|
||||
/// Given a Value, potentially return which AttrIndex it maps to.
|
||||
static Optional<StratifiedAttr> valueToAttrIndex(Value *Val);
|
||||
|
||||
// Gets the inverse of a given EdgeType.
|
||||
static EdgeType flipWeight(EdgeType);
|
||||
/// Gets the inverse of a given EdgeType.
|
||||
static EdgeType flipWeight(EdgeType Initial);
|
||||
|
||||
// Gets edges of the given Instruction*, writing them to the SmallVector*.
|
||||
/// Gets edges of the given Instruction*, writing them to the SmallVector*.
|
||||
static void argsToEdges(CFLAAResult &, Instruction *, SmallVectorImpl<Edge> &);
|
||||
|
||||
// Gets edges of the given ConstantExpr*, writing them to the SmallVector*.
|
||||
/// Gets edges of the given ConstantExpr*, writing them to the SmallVector*.
|
||||
static void argsToEdges(CFLAAResult &, ConstantExpr *, SmallVectorImpl<Edge> &);
|
||||
|
||||
// Gets the "Level" that one should travel in StratifiedSets
|
||||
// given an EdgeType.
|
||||
/// Gets the "Level" that one should travel in StratifiedSets
|
||||
/// given an EdgeType.
|
||||
static Level directionOfEdgeType(EdgeType);
|
||||
|
||||
// Builds the graph needed for constructing the StratifiedSets for the
|
||||
// given function
|
||||
/// Builds the graph needed for constructing the StratifiedSets for the
|
||||
/// given function
|
||||
static void buildGraphFrom(CFLAAResult &, Function *,
|
||||
SmallVectorImpl<Value *> &, NodeMapT &, GraphT &);
|
||||
|
||||
// Gets the edges of a ConstantExpr as if it was an Instruction. This
|
||||
// function also acts on any nested ConstantExprs, adding the edges
|
||||
// of those to the given SmallVector as well.
|
||||
/// Gets the edges of a ConstantExpr as if it was an Instruction. This function
|
||||
/// also acts on any nested ConstantExprs, adding the edges of those to the
|
||||
/// given SmallVector as well.
|
||||
static void constexprToEdges(CFLAAResult &, ConstantExpr &,
|
||||
SmallVectorImpl<Edge> &);
|
||||
|
||||
// Given an Instruction, this will add it to the graph, along with any
|
||||
// Instructions that are potentially only available from said Instruction
|
||||
// For example, given the following line:
|
||||
// %0 = load i16* getelementptr ([1 x i16]* @a, 0, 0), align 2
|
||||
// addInstructionToGraph would add both the `load` and `getelementptr`
|
||||
// instructions to the graph appropriately.
|
||||
/// Given an Instruction, this will add it to the graph, along with any
|
||||
/// Instructions that are potentially only available from said Instruction
|
||||
/// For example, given the following line:
|
||||
/// %0 = load i16* getelementptr ([1 x i16]* @a, 0, 0), align 2
|
||||
/// addInstructionToGraph would add both the `load` and `getelementptr`
|
||||
/// instructions to the graph appropriately.
|
||||
static void addInstructionToGraph(CFLAAResult &, Instruction &,
|
||||
SmallVectorImpl<Value *> &, NodeMapT &,
|
||||
GraphT &);
|
||||
|
||||
// Notes whether it would be pointless to add the given Value to our sets.
|
||||
/// Determines whether it would be pointless to add the given Value to our sets.
|
||||
static bool canSkipAddingToSets(Value *Val);
|
||||
|
||||
static Optional<Function *> parentFunctionOfValue(Value *Val) {
|
||||
|
@ -848,7 +843,7 @@ static void addInstructionToGraph(CFLAAResult &Analysis, Instruction &Inst,
|
|||
return;
|
||||
}
|
||||
|
||||
const auto addEdgeToGraph = [&Graph, &findOrInsertNode](const Edge &E) {
|
||||
auto addEdgeToGraph = [&](const Edge &E) {
|
||||
auto To = findOrInsertNode(E.To);
|
||||
auto From = findOrInsertNode(E.From);
|
||||
auto FlippedWeight = flipWeight(E.Weight);
|
||||
|
@ -873,13 +868,11 @@ static void addInstructionToGraph(CFLAAResult &Analysis, Instruction &Inst,
|
|||
}
|
||||
}
|
||||
|
||||
// Aside: We may remove graph construction entirely, because it doesn't really
|
||||
// buy us much that we don't already have. I'd like to add interprocedural
|
||||
// analysis prior to this however, in case that somehow requires the graph
|
||||
// produced by this for efficient execution
|
||||
static void buildGraphFrom(CFLAAResult &Analysis, Function *Fn,
|
||||
SmallVectorImpl<Value *> &ReturnedValues,
|
||||
NodeMapT &Map, GraphT &Graph) {
|
||||
// (N.B. We may remove graph construction entirely, because it doesn't really
|
||||
// buy us much.)
|
||||
for (auto &Bb : Fn->getBasicBlockList())
|
||||
for (auto &Inst : Bb.getInstList())
|
||||
addInstructionToGraph(Analysis, Inst, ReturnedValues, Map, Graph);
|
||||
|
@ -1003,15 +996,14 @@ void CFLAAResult::scan(Function *Fn) {
|
|||
assert(InsertPair.second &&
|
||||
"Trying to scan a function that has already been cached");
|
||||
|
||||
FunctionInfo Info(buildSetsFrom(Fn));
|
||||
Cache[Fn] = std::move(Info);
|
||||
Cache[Fn] = buildSetsFrom(Fn);
|
||||
Handles.push_front(FunctionHandle(Fn, this));
|
||||
}
|
||||
|
||||
void CFLAAResult::evict(Function *Fn) { Cache.erase(Fn); }
|
||||
|
||||
/// \brief Ensures that the given function is available in the cache.
|
||||
/// Returns the appropriate entry from the cache.
|
||||
/// Ensures that the given function is available in the cache, and returns the
|
||||
/// entry.
|
||||
const Optional<CFLAAResult::FunctionInfo> &
|
||||
CFLAAResult::ensureCached(Function *Fn) {
|
||||
auto Iter = Cache.find(Fn);
|
||||
|
@ -1033,8 +1025,8 @@ AliasResult CFLAAResult::query(const MemoryLocation &LocA,
|
|||
auto MaybeFnA = parentFunctionOfValue(ValA);
|
||||
auto MaybeFnB = parentFunctionOfValue(ValB);
|
||||
if (!MaybeFnA.hasValue() && !MaybeFnB.hasValue()) {
|
||||
// The only times this is known to happen are when globals + InlineAsm
|
||||
// are involved
|
||||
// The only times this is known to happen are when globals + InlineAsm are
|
||||
// involved
|
||||
DEBUG(dbgs() << "CFLAA: could not extract parent function information.\n");
|
||||
return MayAlias;
|
||||
}
|
||||
|
@ -1067,28 +1059,23 @@ AliasResult CFLAAResult::query(const MemoryLocation &LocA,
|
|||
|
||||
// Stratified set attributes are used as markets to signify whether a member
|
||||
// of a StratifiedSet (or a member of a set above the current set) has
|
||||
// interacted with either arguments or globals. "Interacted with" meaning
|
||||
// its value may be different depending on the value of an argument or
|
||||
// global. The thought behind this is that, because arguments and globals
|
||||
// may alias each other, if AttrsA and AttrsB have touched args/globals,
|
||||
// we must conservatively say that they alias. However, if at least one of
|
||||
// the sets has no values that could legally be altered by changing the value
|
||||
// of an argument or global, then we don't have to be as conservative.
|
||||
// interacted with either arguments or globals. "Interacted with" meaning its
|
||||
// value may be different depending on the value of an argument or global. The
|
||||
// thought behind this is that, because arguments and globals may alias each
|
||||
// other, if AttrsA and AttrsB have touched args/globals, we must
|
||||
// conservatively say that they alias. However, if at least one of the sets
|
||||
// has no values that could legally be altered by changing the value of an
|
||||
// argument or global, then we don't have to be as conservative.
|
||||
if (AttrsA.any() && AttrsB.any())
|
||||
return MayAlias;
|
||||
|
||||
// We currently unify things even if the accesses to them may not be in
|
||||
// bounds, so we can't return partial alias here because we don't
|
||||
// know whether the pointer is really within the object or not.
|
||||
// IE Given an out of bounds GEP and an alloca'd pointer, we may
|
||||
// unify the two. We can't return partial alias for this case.
|
||||
// Since we do not currently track enough information to
|
||||
// differentiate
|
||||
|
||||
if (SetA.Index == SetB.Index)
|
||||
return MayAlias;
|
||||
|
||||
return NoAlias;
|
||||
// bounds, so we can't return partial alias here because we don't know whether
|
||||
// the pointer is really within the object or not.
|
||||
// e.g. Given an out of bounds GEP and an alloca'd pointer, we may unify the
|
||||
// two. We can't return partial alias for this case. Since we do not currently
|
||||
// track enough information to differentiate.
|
||||
return SetA.Index == SetB.Index ? MayAlias : NoAlias;
|
||||
}
|
||||
|
||||
char CFLAA::PassID;
|
||||
|
|
|
@ -25,44 +25,45 @@
|
|||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
// \brief An index into Stratified Sets.
|
||||
/// An index into Stratified Sets.
|
||||
typedef unsigned StratifiedIndex;
|
||||
// NOTE: ^ This can't be a short -- bootstrapping clang has a case where
|
||||
// ~1M sets exist.
|
||||
/// NOTE: ^ This can't be a short -- bootstrapping clang has a case where
|
||||
/// ~1M sets exist.
|
||||
|
||||
// \brief Container of information related to a value in a StratifiedSet.
|
||||
struct StratifiedInfo {
|
||||
StratifiedIndex Index;
|
||||
// For field sensitivity, etc. we can tack attributes on to this struct.
|
||||
/// For field sensitivity, etc. we can tack fields on here.
|
||||
};
|
||||
|
||||
// The number of attributes that StratifiedAttrs should contain. Attributes are
|
||||
// described below, and 32 was an arbitrary choice because it fits nicely in 32
|
||||
// bits (because we use a bitset for StratifiedAttrs).
|
||||
/// The number of attributes that StratifiedAttrs should contain. Attributes are
|
||||
/// described below, and 32 was an arbitrary choice because it fits nicely in 32
|
||||
/// bits (because we use a bitset for StratifiedAttrs).
|
||||
static const unsigned NumStratifiedAttrs = 32;
|
||||
|
||||
// These are attributes that the users of StratifiedSets/StratifiedSetBuilders
|
||||
// may use for various purposes. These also have the special property of that
|
||||
// they are merged down. So, if set A is above set B, and one decides to set an
|
||||
// attribute in set A, then the attribute will automatically be set in set B.
|
||||
/// These are attributes that the users of StratifiedSets/StratifiedSetBuilders
|
||||
/// may use for various purposes. These also have the special property of that
|
||||
/// they are merged down. So, if set A is above set B, and one decides to set an
|
||||
/// attribute in set A, then the attribute will automatically be set in set B.
|
||||
typedef std::bitset<NumStratifiedAttrs> StratifiedAttrs;
|
||||
|
||||
// \brief A "link" between two StratifiedSets.
|
||||
/// A "link" between two StratifiedSets.
|
||||
struct StratifiedLink {
|
||||
// \brief 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.
|
||||
/// \brief 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;
|
||||
|
||||
// \brief The index for the set "above" current
|
||||
/// The index for the set "above" current
|
||||
StratifiedIndex Above;
|
||||
|
||||
// \brief The link for the set "below" current
|
||||
/// The link for the set "below" current
|
||||
StratifiedIndex Below;
|
||||
|
||||
// \brief Attributes for these StratifiedSets.
|
||||
/// Attributes for these StratifiedSets.
|
||||
StratifiedAttrs Attrs;
|
||||
|
||||
StratifiedLink() : Above(SetSentinel), Below(SetSentinel) {}
|
||||
|
@ -74,25 +75,25 @@ struct StratifiedLink {
|
|||
void clearAbove() { Above = SetSentinel; }
|
||||
};
|
||||
|
||||
// \brief 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.
|
||||
/// \brief 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() {}
|
||||
|
@ -111,9 +112,8 @@ public:
|
|||
|
||||
Optional<StratifiedInfo> find(const T &Elem) const {
|
||||
auto Iter = Values.find(Elem);
|
||||
if (Iter == Values.end()) {
|
||||
return NoneType();
|
||||
}
|
||||
if (Iter == Values.end())
|
||||
return None;
|
||||
return Iter->second;
|
||||
}
|
||||
|
||||
|
@ -129,91 +129,91 @@ private:
|
|||
bool inbounds(StratifiedIndex Idx) const { return Idx < Links.size(); }
|
||||
};
|
||||
|
||||
// \brief 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, 0
|
||||
//
|
||||
// Given this, the follow 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 states that the only MayAlias relationship in the above program is
|
||||
// between %ap and %aw.
|
||||
//
|
||||
// Life gets more complicated when we actually have logic in our programs. So,
|
||||
// we either must remove this logic from our programs, or make consessions for
|
||||
// it in our AA algorithms. In this case, we have decided to select the latter
|
||||
// option.
|
||||
//
|
||||
// First complication: Conditionals
|
||||
// Motivation:
|
||||
// %ad = alloca int, align 4
|
||||
// %a = alloca int*, align 8
|
||||
// %b = alloca int*, align 8
|
||||
// %bp = alloca int**, align 8
|
||||
// %c = call i1 @SomeFunc()
|
||||
// %k = select %c, %ad, %bp
|
||||
// store %ad, %a
|
||||
// store %b, %bp
|
||||
//
|
||||
// %k has 'with' edges to both %a and %b, which ordinarily would not be linked
|
||||
// together. So, we merge the set that contains %a with the set that contains
|
||||
// %b. We then recursively merge the set above %a with the set above %b, and
|
||||
// the set below %a with the set below %b, etc. Ultimately, the sets for this
|
||||
/// 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, 0
|
||||
///
|
||||
/// Given this, the follow 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 states that the only MayAlias relationship in the above program is
|
||||
/// between %ap and %aw.
|
||||
///
|
||||
/// Life gets more complicated when we actually have logic in our programs. So,
|
||||
/// we either must remove this logic from our programs, or make consessions for
|
||||
/// it in our AA algorithms. In this case, we have decided to select the latter
|
||||
/// option.
|
||||
///
|
||||
/// First complication: Conditionals
|
||||
/// Motivation:
|
||||
/// %ad = alloca int, align 4
|
||||
/// %a = alloca int*, align 8
|
||||
/// %b = alloca int*, align 8
|
||||
/// %bp = alloca int**, align 8
|
||||
/// %c = call i1 @SomeFunc()
|
||||
/// %k = select %c, %ad, %bp
|
||||
/// store %ad, %a
|
||||
/// store %b, %bp
|
||||
///
|
||||
/// %k has 'with' edges to both %a and %b, which ordinarily would not be linked
|
||||
/// together. So, we merge the set that contains %a with the set that contains
|
||||
/// %b. We then recursively merge the set above %a with the set above %b, and
|
||||
/// the set below %a with the set below %b, etc. Ultimately, the sets for this
|
||||
// program would end up like: {%ad}, {%a, %b, %k}, {%bp}, where {%ad} is below
|
||||
// {%a, %b, %c} is below {%ad}.
|
||||
//
|
||||
// Second complication: Arbitrary casts
|
||||
// Motivation:
|
||||
// %ip = alloca int*, align 8
|
||||
// %ipp = alloca int**, align 8
|
||||
// %i = bitcast ipp to int
|
||||
// store %ip, %ipp
|
||||
// store %i, %ip
|
||||
//
|
||||
// This is impossible to construct with any of the rules above, because a set
|
||||
// containing both {%i, %ipp} is supposed to exist, the set with %i is supposed
|
||||
// to be below the set with %ip, and the set with %ip is supposed to be below
|
||||
// the set with %ipp. Because we don't allow circular relationships like this,
|
||||
// we merge all concerned sets into one. So, the above code would generate a
|
||||
// single StratifiedSet: {%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.
|
||||
/// {%a, %b, %c} is below {%ad}.
|
||||
///
|
||||
/// Second complication: Arbitrary casts
|
||||
/// Motivation:
|
||||
/// %ip = alloca int*, align 8
|
||||
/// %ipp = alloca int**, align 8
|
||||
/// %i = bitcast ipp to int
|
||||
/// store %ip, %ipp
|
||||
/// store %i, %ip
|
||||
///
|
||||
/// This is impossible to construct with any of the rules above, because a set
|
||||
/// containing both {%i, %ipp} is supposed to exist, the set with %i is supposed
|
||||
/// to be below the set with %ip, and the set with %ip is supposed to be below
|
||||
/// the set with %ipp. Because we don't allow circular relationships like this,
|
||||
/// we merge all concerned sets into one. So, the above code would generate a
|
||||
/// single StratifiedSet: {%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 {
|
||||
// \brief 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.
|
||||
/// \brief 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;
|
||||
|
||||
|
@ -281,7 +281,7 @@ template <typename T> class StratifiedSetsBuilder {
|
|||
|
||||
bool isRemapped() const { return Remap != StratifiedLink::SetSentinel; }
|
||||
|
||||
// \brief For initial remapping to another set
|
||||
/// For initial remapping to another set
|
||||
void remapTo(StratifiedIndex Other) {
|
||||
assert(!isRemapped());
|
||||
Remap = Other;
|
||||
|
@ -292,15 +292,15 @@ template <typename T> class StratifiedSetsBuilder {
|
|||
return Remap;
|
||||
}
|
||||
|
||||
// \brief Should only be called when we're already remapped.
|
||||
/// Should only be called when we're already remapped.
|
||||
void updateRemap(StratifiedIndex Other) {
|
||||
assert(isRemapped());
|
||||
Remap = Other;
|
||||
}
|
||||
|
||||
// \brief 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.
|
||||
/// 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:
|
||||
|
@ -308,15 +308,14 @@ template <typename T> class StratifiedSetsBuilder {
|
|||
StratifiedIndex Remap;
|
||||
};
|
||||
|
||||
// \brief 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.
|
||||
/// \brief 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()) {
|
||||
if (Link.isRemapped())
|
||||
continue;
|
||||
}
|
||||
|
||||
StratifiedIndex Number = StratLinks.size();
|
||||
Remaps.insert(std::make_pair(Link.Number, Number));
|
||||
|
@ -348,8 +347,8 @@ template <typename T> class StratifiedSetsBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
// \brief There's a guarantee in StratifiedLink where all bits set in a
|
||||
// Link.externals will be set in all Link.externals "below" it.
|
||||
/// \brief 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];
|
||||
|
@ -363,9 +362,8 @@ template <typename T> class StratifiedSetsBuilder {
|
|||
SmallSet<StratifiedIndex, 16> Visited;
|
||||
for (unsigned I = 0, E = Links.size(); I < E; ++I) {
|
||||
auto CurrentIndex = getHighestParentAbove(I);
|
||||
if (!Visited.insert(CurrentIndex).second) {
|
||||
if (!Visited.insert(CurrentIndex).second)
|
||||
continue;
|
||||
}
|
||||
|
||||
while (Links[CurrentIndex].hasBelow()) {
|
||||
auto &CurrentBits = Links[CurrentIndex].Attrs;
|
||||
|
@ -378,8 +376,8 @@ template <typename T> class StratifiedSetsBuilder {
|
|||
}
|
||||
|
||||
public:
|
||||
// \brief Builds a StratifiedSet from the information we've been given since
|
||||
// either construction or the prior build() call.
|
||||
/// 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);
|
||||
|
@ -401,9 +399,9 @@ public:
|
|||
return addAtMerging(Main, NewIndex);
|
||||
}
|
||||
|
||||
// \brief 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.
|
||||
/// \brief 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);
|
||||
|
@ -414,9 +412,9 @@ public:
|
|||
return addAtMerging(ToAdd, Above);
|
||||
}
|
||||
|
||||
// \brief 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.
|
||||
/// \brief 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);
|
||||
|
@ -467,9 +465,9 @@ public:
|
|||
return Attrs[AttrNum];
|
||||
}
|
||||
|
||||
// \brief Gets the attributes that have been applied to the set that Main
|
||||
// belongs to. It ignores attributes in any sets above the one that Main
|
||||
// resides in.
|
||||
/// \brief Gets the attributes that have been applied to the set that Main
|
||||
/// belongs to. It ignores attributes in any sets above the one that Main
|
||||
/// resides in.
|
||||
StratifiedAttrs getRawAttributes(const T &Main) {
|
||||
assert(has(Main));
|
||||
auto *Info = *get(Main);
|
||||
|
@ -477,9 +475,9 @@ public:
|
|||
return Link.getAttrs();
|
||||
}
|
||||
|
||||
// \brief Gets an attribute from the attributes that have been applied to the
|
||||
// set that Main belongs to. It ignores attributes in any sets above the one
|
||||
// that Main resides in.
|
||||
/// \brief Gets an attribute from the attributes that have been applied to the
|
||||
/// set that Main belongs to. It ignores attributes in any sets above the one
|
||||
/// that Main resides in.
|
||||
bool getRawAttribute(const T &Main, unsigned AttrNum) {
|
||||
assert(AttrNum < StratifiedLink::SetSentinel);
|
||||
auto Attrs = getRawAttributes(Main);
|
||||
|
@ -490,8 +488,7 @@ private:
|
|||
DenseMap<T, StratifiedInfo> Values;
|
||||
std::vector<BuilderLink> Links;
|
||||
|
||||
// \brief Adds the given element at the given index, merging sets if
|
||||
// necessary.
|
||||
/// 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));
|
||||
|
@ -509,8 +506,8 @@ private:
|
|||
return false;
|
||||
}
|
||||
|
||||
// \brief Gets the BuilderLink at the given index, taking set remapping into
|
||||
// account.
|
||||
/// Gets the BuilderLink at the given index, taking set remapping into
|
||||
/// account.
|
||||
BuilderLink &linksAt(StratifiedIndex Index) {
|
||||
auto *Start = &Links[Index];
|
||||
if (!Start->isRemapped())
|
||||
|
@ -534,8 +531,8 @@ private:
|
|||
return *Current;
|
||||
}
|
||||
|
||||
// \brief Merges two sets into one another. Assumes that these sets are not
|
||||
// already one in the same
|
||||
/// \brief 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) &&
|
||||
|
@ -555,8 +552,8 @@ private:
|
|||
mergeDirect(Idx1, Idx2);
|
||||
}
|
||||
|
||||
// \brief Merges two sets assuming that the set at `Idx1` is unreachable from
|
||||
// traversing above or below the set at `Idx2`.
|
||||
/// \brief 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));
|
||||
|
||||
|
@ -602,9 +599,9 @@ private:
|
|||
LinksFrom->remapTo(LinksInto->Number);
|
||||
}
|
||||
|
||||
// \brief 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.
|
||||
/// 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);
|
||||
|
@ -644,21 +641,21 @@ private:
|
|||
Optional<const StratifiedInfo *> get(const T &Val) const {
|
||||
auto Result = Values.find(Val);
|
||||
if (Result == Values.end())
|
||||
return NoneType();
|
||||
return None;
|
||||
return &Result->second;
|
||||
}
|
||||
|
||||
Optional<StratifiedInfo *> get(const T &Val) {
|
||||
auto Result = Values.find(Val);
|
||||
if (Result == Values.end())
|
||||
return NoneType();
|
||||
return None;
|
||||
return &Result->second;
|
||||
}
|
||||
|
||||
Optional<StratifiedIndex> indexOf(const T &Val) {
|
||||
auto MaybeVal = get(Val);
|
||||
if (!MaybeVal.hasValue())
|
||||
return NoneType();
|
||||
return None;
|
||||
auto *Info = *MaybeVal;
|
||||
auto &Link = linksAt(Info->Index);
|
||||
return Link.Number;
|
||||
|
|
Loading…
Reference in New Issue