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 virtual ~StructAnalysis() = default;
63
75 virtual mlir::LogicalResult runAnalysis(
76 mlir::DataFlowSolver &solver, mlir::AnalysisManager &moduleAnalysisManager, Context &ctx
77 ) = 0;
78
80 bool constructed() const { return res != nullptr; }
81
83 const Result &getResult() const {
84 ensure(constructed(), mlir::Twine(__PRETTY_FUNCTION__) + ": result has not been constructed");
85 return *res;
86 }
87
88protected:
90 mlir::ModuleOp getModule() const { return modOp; }
91
93 component::StructDefOp getStruct() const { return structDefOp; }
94
96 void setResult(Result &&r) { res = std::make_unique<Result>(r); }
97
98private:
99 mlir::ModuleOp modOp;
100 component::StructDefOp structDefOp;
101 std::unique_ptr<Result> res;
102};
103
106struct NoContext {};
107
109template <typename Analysis, typename Result, typename Context>
111 requires { requires std::is_base_of<StructAnalysis<Result, Context>, Analysis>::value; };
112
119template <typename Result, typename Context, StructAnalysisType<Result, Context> StructAnalysisTy>
123 using ResultMap = std::map<
124 component::StructDefOp, std::reference_wrapper<const Result>,
126
127public:
132 ModuleAnalysis(mlir::Operation *op) {
133 if (modOp = mlir::dyn_cast<mlir::ModuleOp>(op); !modOp) {
134 auto error_message = "ModuleAnalysis expects provided op to be an mlir::ModuleOp!";
135 op->emitError(error_message);
136 llvm::report_fatal_error(error_message);
137 }
138 }
139 virtual ~ModuleAnalysis() = default;
140
145 virtual void runAnalysis(mlir::AnalysisManager &am) { constructChildAnalyses(am); }
146
148 bool hasResult(component::StructDefOp op) const { return results.find(op) != results.end(); }
149
151 const Result &getResult(component::StructDefOp op) const {
152 ensureResultCreated(op);
153 return results.at(op).get();
154 }
155
156 ResultMap::iterator begin() { return results.begin(); }
157 ResultMap::iterator end() { return results.end(); }
158 ResultMap::const_iterator cbegin() const { return results.cbegin(); }
159 ResultMap::const_iterator cend() const { return results.cend(); }
160
161 const mlir::DataFlowSolver &getSolver() const { return solver; }
162
163protected:
164 mlir::DataFlowSolver solver;
165
169 virtual void initializeSolver() = 0;
170
174 virtual Context getContext() = 0;
175
179 void constructChildAnalyses(mlir::AnalysisManager &am) {
181
182 // The analysis is run at the module level so that lattices are computed
183 // for global functions as well.
185 auto res = solver.initializeAndRun(modOp);
186 ensure(res.succeeded(), "solver failed to run on module!");
187
188 auto ctx = getContext();
189 modOp.walk([this, &am, &ctx](component::StructDefOp s) mutable {
190 auto &childAnalysis = am.getChildAnalysis<StructAnalysisTy>(s);
191 if (mlir::failed(childAnalysis.runAnalysis(solver, am, ctx))) {
192 auto error_message = "StructAnalysis failed to run for " + mlir::Twine(s.getName());
193 s->emitError(error_message);
194 llvm::report_fatal_error(error_message);
195 }
196 ensure(results.find(s) == results.end(), "struct location conflict");
197 results.insert(std::make_pair(s, std::reference_wrapper(childAnalysis.getResult())));
198 return mlir::WalkResult::skip();
199 });
200 }
201
202private:
203 mlir::ModuleOp modOp;
204 ResultMap results;
205
208 void ensureResultCreated(component::StructDefOp op) const {
209 ensure(hasResult(op), "Result does not exist for StructDefOp " + mlir::Twine(op.getName()));
210 }
211};
212
213} // namespace llzk
This file implements (LLZK-tailored) dense data-flow analysis using the data-flow analysis framework.
mlir::DataFlowSolver solver
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
virtual ~ModuleAnalysis()=default
ResultMap::iterator begin()
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.
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.
virtual ~StructAnalysis()=default
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:35
An empty struct that is used for convenience for analyses that do not require any context.