#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include #include #include #include #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/raw_ostream.h" #include "revng/ADT/Concepts.h" #include "revng/ADT/GenericGraph.h" #include "revng/ADT/ReversePostOrderTraversal.h" namespace MFP { template struct MFPResult { LatticeElement InValue; LatticeElement OutValue; }; /// GT is an instance of llvm::GraphTraits e.g. llvm::GraphTraits template auto successors(typename GT::NodeRef From) { return llvm::make_range(GT::child_begin(From), GT::child_end(From)); } template concept MonotoneFrameworkInstance = requires(const MFI &I, LatticeElement E1, LatticeElement E2, typename MFI::Label L) { /// To compute the reverse post order traversal of the graph starting from /// the extremal nodes, we need that the nodes also represent a subgraph typename llvm::GraphTraits::NodeRef; std::same_as::NodeRef>; // Disable clang-format, because it does not handle concepts very well yet // clang-format off { I.combineValues(E1, E2) } -> std::same_as; { I.isLessOrEqual(E1, E2) } -> std::same_as; { I.applyTransferFunction(L, E2) } -> std::same_as; // clang-format on }; /// Compute the maximum fixed points of an instance of monotone framework GT an /// instance of llvm::GraphTraits that tells us how to visit the graph LGT a /// graph type that tells us how to visit the subgraph induced by a node in the /// graph. This is needed for the RPOT because for certain graph (e.g. /// Inverse<...>) the nodes don't necessary carry all the information that /// GraphType has. template, typename LGT = typename MFI::Label> std::map> getMaximalFixedPoint(const MFI &Instance, const typename MFI::GraphType &Flow, typename MFI::LatticeElement InitialValue, typename MFI::LatticeElement ExtremalValue, const std::vector &ExtremalLabels, const std::vector &InitialNodes) { using Label = typename MFI::Label; using LatticeElement = typename MFI::LatticeElement; std::map PartialAnalysis; std::map> AnalysisResult; struct WorklistItem { size_t Priority; Label Item; // NOLINTNEXTLINE(readability-identifier-naming) std::strong_ordering operator<=>(const WorklistItem &) const = default; }; std::set Worklist; llvm::SmallSet Visited{}; std::map LabelPriority; // Step 1 initialize the worklist and extremal labels for (Label ExtremalLabel : ExtremalLabels) { AnalysisResult[ExtremalLabel].InValue = ExtremalValue; } for (Label Start : InitialNodes) { if (Visited.count(Start) == 0) { // Fill the worklist with nodes in reverse post order // lauching a visit from each remaining node ReversePostOrderTraversalExt, llvm::SmallSet> RPOTE(Start, Visited); for (Label Node : RPOTE) { LabelPriority[Node] = LabelPriority.size(); Worklist.insert({ LabelPriority.at(Node), Node }); // initialize the analysis value for non extremal nodes if (AnalysisResult.find(Node) == AnalysisResult.end()) { AnalysisResult[Node].InValue = InitialValue; } } } } // Step 2 iteration while (!Worklist.empty()) { WorklistItem First = *Worklist.begin(); Label Start = First.Item; Worklist.erase(First); auto &LabelAnalysis = AnalysisResult.at(Start); LabelAnalysis .OutValue = Instance.applyTransferFunction(Start, LabelAnalysis.InValue); for (Label End : successors(Start)) { auto &PartialEnd = AnalysisResult.at(End); if (!Instance.isLessOrEqual(LabelAnalysis.OutValue, PartialEnd.InValue)) { PartialEnd.InValue = Instance.combineValues(PartialEnd.InValue, LabelAnalysis.OutValue); Worklist.insert({ LabelPriority.at(End), End }); } } } return AnalysisResult; } template, typename LGT = typename MFI::Label> std::map> getMaximalFixedPoint(const MFI &Instance, const typename MFI::GraphType &Flow, typename MFI::LatticeElement InitialValue, typename MFI::LatticeElement ExtremalValue, const std::vector &ExtremalLabels) { using Label = typename MFI::Label; std::vector