LLZK 0.1.0
Veridise's ZK Language IR
Loading...
Searching...
No Matches
AnalysisWrappers.h
Go to the documentation of this file.
1//===-- AnalysisWrappers.h --------------------------------------*- C++ -*-===//
2//
3// Part of the LLZK Project, under the Apache License v2.0.
4// See LICENSE.txt for license information.
5// Copyright 2025 Veridise Inc.
6// SPDX-License-Identifier: Apache-2.0
7//
8//===----------------------------------------------------------------------===//
21//===----------------------------------------------------------------------===//
22
23#pragma once
24
27#include "llzk/Util/Compare.h"
30
31#include <mlir/IR/BuiltinOps.h>
32#include <mlir/Pass/AnalysisManager.h>
33
34#include <map>
35
36namespace llzk {
37
42template <typename Result, typename Context> class StructAnalysis {
43public:
47 StructAnalysis(mlir::Operation *op) {
48 structDefOp = mlir::dyn_cast<component::StructDefOp>(op);
49 if (!structDefOp) {
50 auto error_message = "StructAnalysis expects provided op to be a StructDefOp!";
51 op->emitError(error_message);
52 llvm::report_fatal_error(error_message);
53 }
54 auto maybeModOp = getRootModule(op);
55 if (mlir::failed(maybeModOp)) {
56 auto error_message = "StructAnalysis could not find root module from StructDefOp!";
57 op->emitError(error_message);
58 llvm::report_fatal_error(error_message);
59 }
60 modOp = *maybeModOp;
61 }
62
74 virtual mlir::LogicalResult runAnalysis(
75 mlir::DataFlowSolver &solver, mlir::AnalysisManager &moduleAnalysisManager, Context &ctx
76 ) = 0;
77
79 bool constructed() const { return res != nullptr; }
80
82 const Result &getResult() const {
83 ensure(constructed(), mlir::Twine(__PRETTY_FUNCTION__) + ": result has not been constructed");
84 return *res;
85 }
86
87protected:
89 mlir::ModuleOp getModule() const { return modOp; }
90
92 component::StructDefOp getStruct() const { return structDefOp; }
93
95 void setResult(Result &&r) { res = std::make_unique<Result>(r); }
96
97private:
98 mlir::ModuleOp modOp;
99 component::StructDefOp structDefOp;
100 std::unique_ptr<Result> res;
101};
102
105struct NoContext {};
106
108template <typename Analysis, typename Result, typename Context>
110 requires { requires std::is_base_of<StructAnalysis<Result, Context>, Analysis>::value; };
111
118template <typename Result, typename Context, StructAnalysisType<Result, Context> StructAnalysisTy>
122 using ResultMap = std::map<
123 component::StructDefOp, std::reference_wrapper<const Result>,
125
126public:
131 ModuleAnalysis(mlir::Operation *op) {
132 if (modOp = mlir::dyn_cast<mlir::ModuleOp>(op); !modOp) {
133 auto error_message = "ModuleAnalysis expects provided op to be an mlir::ModuleOp!";
134 op->emitError(error_message);
135 llvm::report_fatal_error(error_message);
136 }
137 }
138
143 virtual void runAnalysis(mlir::AnalysisManager &am) { constructChildAnalyses(am); }
144
146 bool hasResult(component::StructDefOp op) const { return results.find(op) != results.end(); }
147
149 const Result &getResult(component::StructDefOp op) const {
150 ensureResultCreated(op);
151 return results.at(op).get();
152 }
153
154 ResultMap::iterator begin() { return results.begin(); }
155 ResultMap::iterator end() { return results.end(); }
156 ResultMap::const_iterator cbegin() const { return results.cbegin(); }
157 ResultMap::const_iterator cend() const { return results.cend(); }
158
159 const mlir::DataFlowSolver &getSolver() const { return solver; }
160
161protected:
165 virtual void initializeSolver(mlir::DataFlowSolver &solver) = 0;
166
170 virtual Context getContext() = 0;
171
175 void constructChildAnalyses(mlir::AnalysisManager &am) {
176 dataflow::markAllOpsAsLive(solver, modOp);
177
178 // The analysis is run at the module level so that lattices are computed
179 // for global functions as well.
180 initializeSolver(solver);
181 auto res = solver.initializeAndRun(modOp);
182 ensure(res.succeeded(), "solver failed to run on module!");
183
184 auto ctx = getContext();
185 modOp.walk([this, &am, &ctx](component::StructDefOp s) mutable {
186 auto &childAnalysis = am.getChildAnalysis<StructAnalysisTy>(s);
187 if (mlir::failed(childAnalysis.runAnalysis(solver, am, ctx))) {
188 auto error_message = "StructAnalysis failed to run for " + mlir::Twine(s.getName());
189 s->emitError(error_message);
190 llvm::report_fatal_error(error_message);
191 }
192 ensure(results.find(s) == results.end(), "struct location conflict");
193 results.insert(std::make_pair(s, std::reference_wrapper(childAnalysis.getResult())));
194 return mlir::WalkResult::skip();
195 });
196 }
197
198private:
199 mlir::ModuleOp modOp;
200 ResultMap results;
201 mlir::DataFlowSolver solver;
202
205 void ensureResultCreated(component::StructDefOp op) const {
206 ensure(hasResult(op), "Result does not exist for StructDefOp " + mlir::Twine(op.getName()));
207 }
208};
209
210} // namespace llzk
This file implements (LLZK-tailored) dense data-flow analysis using the data-flow analysis framework.
virtual void initializeSolver(mlir::DataFlowSolver &solver)=0
Initialize the shared dataflow solver with any common analyses required by the contained struct analy...
virtual Context getContext()=0
Create and return a valid Context object.
ModuleAnalysis(mlir::Operation *op)
Asserts that the analysis is being run on a ModuleOp.
ResultMap::const_iterator cbegin() const
ResultMap::iterator begin()
virtual void runAnalysis(mlir::AnalysisManager &am)
Run the StructAnalysisTy struct analysis on all child structs.
ResultMap::iterator end()
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...
ResultMap::const_iterator cend() const
bool hasResult(component::StructDefOp op) const
Checks if op has a result contained in the current result map.
const mlir::DataFlowSolver & getSolver() const
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, Context &ctx)=0
Perform the analysis and construct the Result output.
mlir::ModuleOp getModule() const
Get the ModuleOp that is the parent of the StructDefOp that is under analysis.
bool constructed() const
Query if the analysis has constructed a Result object.
void setResult(Result &&r)
Initialize the final Result object.
const Result & getResult() const
Access the result iff it has been created.
Any type that is a subclass of StructAnalysis.
void markAllOpsAsLive(mlir::DataFlowSolver &solver, mlir::Operation *top)
LLZK: Added this utility to ensure analysis is performed for all structs in a given module.
FailureOr< ModuleOp > getRootModule(Operation *from)
void ensure(bool condition, llvm::Twine errMsg)
Definition ErrorHelper.h:32
An empty struct that is used for convenience for analyses that do not require any context.