static Optional<InstantiatedValue> getNodeBelow(const CFLGraph &Graph, InstantiatedValue V) { auto NodeBelow = InstantiatedValue{V.Val, V.DerefLevel + 1}; if (Graph.getNode(NodeBelow)) return NodeBelow; return None; }
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; } }