static AliasAttrMap buildAttrMap(const CFLGraph &Graph, const ReachabilitySet &ReachSet) { AliasAttrMap AttrMap; std::vector<InstantiatedValue> WorkList, NextList; // Initialize each node with its original AliasAttrs in CFLGraph for (const auto &Mapping : Graph.value_mappings()) { auto Val = Mapping.first; auto &ValueInfo = Mapping.second; for (unsigned I = 0, E = ValueInfo.getNumLevels(); I < E; ++I) { auto Node = InstantiatedValue{Val, I}; AttrMap.add(Node, ValueInfo.getNodeInfoAtLevel(I).Attr); WorkList.push_back(Node); } } while (!WorkList.empty()) { for (const auto &Dst : WorkList) { auto DstAttr = AttrMap.getAttrs(Dst); if (DstAttr.none()) continue; // Propagate attr on the same level for (const auto &Mapping : ReachSet.reachableValueAliases(Dst)) { auto Src = Mapping.first; if (AttrMap.add(Src, DstAttr)) NextList.push_back(Src); } // Propagate attr to the levels below auto DstBelow = getNodeBelow(Graph, Dst); while (DstBelow) { if (AttrMap.add(*DstBelow, DstAttr)) { NextList.push_back(*DstBelow); break; } DstBelow = getNodeBelow(Graph, *DstBelow); } } WorkList.swap(NextList); NextList.clear(); } return AttrMap; }
static void processWorkListItem(const WorkListItem &Item, const CFLGraph &Graph, ReachabilitySet &ReachSet, AliasMemSet &MemSet, std::vector<WorkListItem> &WorkList) { auto FromNode = Item.From; auto ToNode = Item.To; auto NodeInfo = Graph.getNode(ToNode); assert(NodeInfo != nullptr); // TODO: propagate field offsets // FIXME: Here is a neat trick we can do: since both ReachSet and MemSet holds // relations that are symmetric, we could actually cut the storage by half by // sorting FromNode and ToNode before insertion happens. // The newly added value alias pair may potentially generate more memory // alias pairs. Check for them here. auto FromNodeBelow = getNodeBelow(Graph, FromNode); auto ToNodeBelow = getNodeBelow(Graph, ToNode); if (FromNodeBelow && ToNodeBelow && MemSet.insert(*FromNodeBelow, *ToNodeBelow)) { propagate(*FromNodeBelow, *ToNodeBelow, MatchState::FlowFromMemAliasNoReadWrite, ReachSet, WorkList); for (const auto &Mapping : ReachSet.reachableValueAliases(*FromNodeBelow)) { auto Src = Mapping.first; auto MemAliasPropagate = [&](MatchState FromState, MatchState ToState) { if (Mapping.second.test(static_cast<size_t>(FromState))) propagate(Src, *ToNodeBelow, ToState, ReachSet, WorkList); }; MemAliasPropagate(MatchState::FlowFromReadOnly, MatchState::FlowFromMemAliasReadOnly); MemAliasPropagate(MatchState::FlowToWriteOnly, MatchState::FlowToMemAliasWriteOnly); MemAliasPropagate(MatchState::FlowToReadWrite, MatchState::FlowToMemAliasReadWrite); } } // This is the core of the state machine walking algorithm. We expand ReachSet // based on which state we are at (which in turn dictates what edges we // should examine) // From a high-level point of view, the state machine here guarantees two // properties: // - If *X and *Y are memory aliases, then X and Y are value aliases // - If Y is an alias of X, then reverse assignment edges (if there is any) // should precede any assignment edges on the path from X to Y. auto NextAssignState = [&](MatchState State) { for (const auto &AssignEdge : NodeInfo->Edges) propagate(FromNode, AssignEdge.Other, State, ReachSet, WorkList); }; auto NextRevAssignState = [&](MatchState State) { for (const auto &RevAssignEdge : NodeInfo->ReverseEdges) propagate(FromNode, RevAssignEdge.Other, State, ReachSet, WorkList); }; auto NextMemState = [&](MatchState State) { if (auto AliasSet = MemSet.getMemoryAliases(ToNode)) { for (const auto &MemAlias : *AliasSet) propagate(FromNode, MemAlias, State, ReachSet, WorkList); } }; switch (Item.State) { case MatchState::FlowFromReadOnly: NextRevAssignState(MatchState::FlowFromReadOnly); NextAssignState(MatchState::FlowToReadWrite); NextMemState(MatchState::FlowFromMemAliasReadOnly); break; case MatchState::FlowFromMemAliasNoReadWrite: NextRevAssignState(MatchState::FlowFromReadOnly); NextAssignState(MatchState::FlowToWriteOnly); break; case MatchState::FlowFromMemAliasReadOnly: NextRevAssignState(MatchState::FlowFromReadOnly); NextAssignState(MatchState::FlowToReadWrite); break; case MatchState::FlowToWriteOnly: NextAssignState(MatchState::FlowToWriteOnly); NextMemState(MatchState::FlowToMemAliasWriteOnly); break; case MatchState::FlowToReadWrite: NextAssignState(MatchState::FlowToReadWrite); NextMemState(MatchState::FlowToMemAliasReadWrite); break; case MatchState::FlowToMemAliasWriteOnly: NextAssignState(MatchState::FlowToWriteOnly); break; case MatchState::FlowToMemAliasReadWrite: NextAssignState(MatchState::FlowToReadWrite); break; } }