static void addInstructionToGraph(CFLAliasAnalysis &Analysis, Instruction &Inst, SmallVectorImpl<Value *> &ReturnedValues, NodeMapT &Map, GraphT &Graph) { const auto findOrInsertNode = [&Map, &Graph](Value *Val) { auto Pair = Map.insert(std::make_pair(Val, GraphT::Node())); auto &Iter = Pair.first; if (Pair.second) { auto NewNode = Graph.addNode(); Iter->second = NewNode; } return Iter->second; }; // We don't want the edges of most "return" instructions, but we *do* want // to know what can be returned. if (isa<ReturnInst>(&Inst)) ReturnedValues.push_back(&Inst); if (!hasUsefulEdges(&Inst)) return; SmallVector<Edge, 8> Edges; argsToEdges(Analysis, &Inst, Edges); // In the case of an unused alloca (or similar), edges may be empty. Note // that it exists so we can potentially answer NoAlias. if (Edges.empty()) { auto MaybeVal = getTargetValue(&Inst); assert(MaybeVal.hasValue()); auto *Target = *MaybeVal; findOrInsertNode(Target); return; } const auto addEdgeToGraph = [&Graph, &findOrInsertNode](const Edge &E) { auto To = findOrInsertNode(E.To); auto From = findOrInsertNode(E.From); auto FlippedWeight = flipWeight(E.Weight); auto Attrs = E.AdditionalAttrs; Graph.addEdge(From, To, std::make_pair(E.Weight, Attrs), std::make_pair(FlippedWeight, Attrs)); }; SmallVector<ConstantExpr *, 4> ConstantExprs; for (const Edge &E : Edges) { addEdgeToGraph(E); if (auto *Constexpr = dyn_cast<ConstantExpr>(E.To)) ConstantExprs.push_back(Constexpr); if (auto *Constexpr = dyn_cast<ConstantExpr>(E.From)) ConstantExprs.push_back(Constexpr); } for (ConstantExpr *CE : ConstantExprs) { Edges.clear(); constexprToEdges(Analysis, *CE, Edges); std::for_each(Edges.begin(), Edges.end(), addEdgeToGraph); } }
// 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(CFLAliasAnalysis &Analysis, Function *Fn, SmallVectorImpl<Value *> &ReturnedValues, NodeMapT &Map, GraphT &Graph) { const auto findOrInsertNode = [&Map, &Graph](Value *Val) { auto Pair = Map.insert(std::make_pair(Val, GraphT::Node())); auto &Iter = Pair.first; if (Pair.second) { auto NewNode = Graph.addNode(); Iter->second = NewNode; } return Iter->second; }; SmallVector<Edge, 8> Edges; for (auto &Bb : Fn->getBasicBlockList()) { for (auto &Inst : Bb.getInstList()) { // We don't want the edges of most "return" instructions, but we *do* want // to know what can be returned. if (auto *Ret = dyn_cast<ReturnInst>(&Inst)) ReturnedValues.push_back(Ret); if (!hasUsefulEdges(&Inst)) continue; Edges.clear(); argsToEdges(Analysis, &Inst, Edges); // In the case of an unused alloca (or similar), edges may be empty. Note // that it exists so we can potentially answer NoAlias. if (Edges.empty()) { auto MaybeVal = getTargetValue(&Inst); assert(MaybeVal.hasValue()); auto *Target = *MaybeVal; findOrInsertNode(Target); continue; } for (const Edge &E : Edges) { auto To = findOrInsertNode(E.To); auto From = findOrInsertNode(E.From); auto FlippedWeight = flipWeight(E.Weight); auto Attrs = E.AdditionalAttrs; Graph.addEdge(From, To, std::make_pair(E.Weight, Attrs), std::make_pair(FlippedWeight, Attrs)); } } } }
static FunctionInfo buildSetsFrom(CFLAliasAnalysis &Analysis, Function *Fn) { NodeMapT Map; GraphT Graph; SmallVector<Value *, 4> ReturnedValues; buildGraphFrom(Analysis, Fn, ReturnedValues, Map, Graph); DenseMap<GraphT::Node, Value *> NodeValueMap; NodeValueMap.resize(Map.size()); for (const auto &Pair : Map) NodeValueMap.insert(std::make_pair(Pair.second, Pair.first)); const auto findValueOrDie = [&NodeValueMap](GraphT::Node Node) { auto ValIter = NodeValueMap.find(Node); assert(ValIter != NodeValueMap.end()); return ValIter->second; }; StratifiedSetsBuilder<Value *> Builder; SmallVector<GraphT::Node, 16> Worklist; for (auto &Pair : Map) { Worklist.clear(); auto *Value = Pair.first; Builder.add(Value); auto InitialNode = Pair.second; Worklist.push_back(InitialNode); while (!Worklist.empty()) { auto Node = Worklist.pop_back_val(); auto *CurValue = findValueOrDie(Node); if (isa<Constant>(CurValue) && !isa<GlobalValue>(CurValue)) continue; for (const auto &EdgeTuple : Graph.edgesFor(Node)) { auto Weight = std::get<0>(EdgeTuple); auto Label = Weight.first; auto &OtherNode = std::get<1>(EdgeTuple); auto *OtherValue = findValueOrDie(OtherNode); if (isa<Constant>(OtherValue) && !isa<GlobalValue>(OtherValue)) continue; bool Added; switch (directionOfEdgeType(Label)) { case Level::Above: Added = Builder.addAbove(CurValue, OtherValue); break; case Level::Below: Added = Builder.addBelow(CurValue, OtherValue); break; case Level::Same: Added = Builder.addWith(CurValue, OtherValue); break; } if (Added) { auto Aliasing = Weight.second; if (auto MaybeCurIndex = valueToAttrIndex(CurValue)) Aliasing.set(*MaybeCurIndex); if (auto MaybeOtherIndex = valueToAttrIndex(OtherValue)) Aliasing.set(*MaybeOtherIndex); Builder.noteAttributes(CurValue, Aliasing); Builder.noteAttributes(OtherValue, Aliasing); Worklist.push_back(OtherNode); } } } } // There are times when we end up with parameters not in our graph (i.e. if // it's only used as the condition of a branch). Other bits of code depend on // things that were present during construction being present in the graph. // So, we add all present arguments here. for (auto &Arg : Fn->args()) { Builder.add(&Arg); } return FunctionInfo(Builder.build(), std::move(ReturnedValues)); }