31#include <mlir/IR/BuiltinOps.h>
32#include <mlir/Pass/AnalysisManager.h>
48 structDefOp = llvm::dyn_cast<component::StructDefOp>(op);
50 const char *error_message =
"StructAnalysis expects provided op to be a StructDefOp!";
51 op->emitError(error_message).report();
52 llvm::report_fatal_error(error_message);
55 if (mlir::failed(maybeModOp)) {
56 const char *error_message =
"StructAnalysis could not find root module from StructDefOp!";
57 op->emitError(error_message).report();
58 llvm::report_fatal_error(error_message);
76 mlir::DataFlowSolver &solver, mlir::AnalysisManager &moduleAnalysisManager,
const Context &ctx
80 bool constructed(
const Context &ctx)
const {
return res.contains(ctx); }
86 ": result has not been constructed for struct " +
101 auto [_, inserted] = res.insert(std::make_pair(ctx, std::make_unique<Result>(r)));
102 ensure(inserted,
"Result already initialized");
106 mlir::ModuleOp modOp;
108 std::unordered_map<Context, std::unique_ptr<Result>> res;
111template <
typename Context>
112concept ContextType =
requires(
const Context &a,
const Context &b) {
113 { a == b } -> std::convertible_to<bool>;
114 { std::hash<Context> {}(a) } -> std::convertible_to<std::size_t>;
123template <
typename Analysis,
typename Result,
typename Context>
125 requires std::is_base_of<StructAnalysis<Result, Context>, Analysis>::value;
135template <
typename Result,
typename Context, StructAnalysisType<Result, Context> StructAnalysisTy>
139 using StructResults = std::map<
147 using ResultMap = std::unordered_map<Context, StructResults>;
155 if (modOp = llvm::dyn_cast<mlir::ModuleOp>(op); !modOp) {
156 auto error_message =
"ModuleAnalysis expects provided op to be an mlir::ModuleOp!";
157 op->emitError(error_message).report();
158 llvm::report_fatal_error(error_message);
187 ensureResultCreated(op);
193 ensure(
constructed(),
"results are not yet constructed for the current context");
220 auto res =
solver.initializeAndRun(modOp);
221 ensure(res.succeeded(),
"solver failed to run on module!");
225 auto &childAnalysis = am.getChildAnalysis<StructAnalysisTy>(s);
228 if (!childAnalysis.constructed(ctx)) {
229 mlir::LogicalResult childAnalysisRes = childAnalysis.runAnalysis(
solver, am, ctx);
231 if (mlir::failed(childAnalysisRes)) {
232 auto error_message =
"StructAnalysis failed to run for " + mlir::Twine(s.getName());
233 s->emitError(error_message).report();
234 llvm::report_fatal_error(error_message);
238 auto [_, inserted] = results[ctx].insert(
239 std::make_pair(s, std::reference_wrapper(childAnalysis.getResult(ctx)))
241 ensure(inserted,
"struct location conflict");
242 return mlir::WalkResult::skip();
247 mlir::ModuleOp modOp;
253 ensure(
hasResult(op),
"Result does not exist for StructDefOp " + mlir::Twine(op.getName()));
This file implements (LLZK-tailored) dense data-flow analysis using the data-flow analysis framework.
mlir::DataFlowSolver solver
ModuleAnalysis(mlir::Operation *op)
Asserts that the analysis is being run on a ModuleOp.
virtual ~ModuleAnalysis()=default
mlir::DataFlowSolver & getSolver()
void ensureAnalysisRun(mlir::AnalysisManager &am)
Runs the analysis if the results do not already exist.
bool constructed() const
Check if the results of this analysis have been created for the currently available context.
virtual void initializeSolver()=0
Initialize the shared dataflow solver with any common analyses required by the contained struct analy...
virtual void runAnalysis(mlir::AnalysisManager &am)
Run the StructAnalysisTy struct analysis on all child structs.
const StructResults & getCurrentResults() const
Get the results for the current context.
virtual const Context & getContext() const =0
Return the current Context object.
const Result & getResult(component::StructDefOp op) const
Asserts that op has a result and returns it.
void constructChildAnalyses(mlir::AnalysisManager &am)
Construct and run the StructAnalysisTy analyses on each StructDefOp contained in the ModuleOp that is...
bool hasResult(component::StructDefOp op) const
Checks if op has a result contained in the current result map.
StructAnalysis(mlir::Operation *op)
Assert that this analysis is being run on a StructDefOp and initializes the analysis with the current...
component::StructDefOp getStruct() const
Get the current StructDefOp that is under analysis.
virtual mlir::LogicalResult runAnalysis(mlir::DataFlowSolver &solver, mlir::AnalysisManager &moduleAnalysisManager, const Context &ctx)=0
Perform the analysis and construct the Result output.
void setResult(const Context &ctx, Result &&r)
Initialize the final Result object.
const Result & getResult(const Context &ctx) const
Access the result iff it has been created for the given Context object ctx.
mlir::ModuleOp getModule() const
Get the ModuleOp that is the parent of the StructDefOp that is under analysis.
bool constructed(const Context &ctx) const
Query if the analysis has constructed a Result object for the given Context.
virtual ~StructAnalysis()=default
Any type that is a subclass of StructAnalysis and provided a Context that matches ContextType.
void markAllOpsAsLive(DataFlowSolver &solver, Operation *top)
void ensure(bool condition, const llvm::Twine &errMsg)
FailureOr< ModuleOp > getRootModule(Operation *from)
An empty struct that is used for convenience for analyses that do not require any context.