LLZK 0.1.0
Veridise's ZK Language IR
Loading...
Searching...
No Matches
ConstraintDependencyGraph.h
Go to the documentation of this file.
1//===-- ConstraintDependencyGraph.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//===----------------------------------------------------------------------===//
9
10#pragma once
11
15
16#include <mlir/Pass/AnalysisManager.h>
17
18#include <llvm/ADT/EquivalenceClasses.h>
19
20namespace mlir {
21
22class DataFlowSolver;
23
24} // namespace mlir
25
26namespace llzk {
27
28using ConstrainRefRemappings = std::vector<std::pair<ConstrainRef, ConstrainRefLatticeValue>>;
29
35public:
36 using dataflow::DenseForwardDataFlowAnalysis<ConstrainRefLattice>::DenseForwardDataFlowAnalysis;
37
39 mlir::CallOpInterface call, dataflow::CallControlFlowAction action,
40 const ConstrainRefLattice &before, ConstrainRefLattice *after
41 ) override;
42
47 void visitOperation(
48 mlir::Operation *op, const ConstrainRefLattice &before, ConstrainRefLattice *after
49 ) override;
50
51protected:
52 void setToEntryState(ConstrainRefLattice *lattice) override {
53 // the entry state is empty, so do nothing.
54 }
55
56 // Perform a standard union of operands into the results value.
57 mlir::ChangeResult fallbackOpUpdate(
58 mlir::Operation *op, const ConstrainRefLattice::ValueMap &operandVals,
59 const ConstrainRefLattice &before, ConstrainRefLattice *after
60 );
61
62 // Perform the update for either a array.read op or an array.extract op, which
63 // operate very similarly: index into the first operand using a variable number
64 // of provided indices.
66 mlir::Operation *op, const ConstrainRefLattice::ValueMap &operandVals,
67 const ConstrainRefLattice &before, ConstrainRefLattice *after
68 );
69
70private:
71 mlir::SymbolTableCollection tables;
72};
73
101public:
111 static mlir::FailureOr<ConstraintDependencyGraph> compute(
112 mlir::ModuleOp mod, component::StructDefOp s, mlir::DataFlowSolver &solver,
113 mlir::AnalysisManager &am
114 );
115
117 void dump() const;
120 void print(mlir::raw_ostream &os) const;
121
130
140
141 /*
142 Rule of three, needed for the mlir::SymbolTableCollection, which has no copy constructor.
143 Since the mlir::SymbolTableCollection is a caching mechanism, we simply allow default, empty
144 construction for copies.
145 */
146
148 : mod(other.mod), structDef(other.structDef), signalSets(other.signalSets),
149 constantSets(other.constantSets), tables() {}
151 mod = other.mod;
152 structDef = other.structDef;
153 signalSets = other.signalSets;
154 constantSets = other.constantSets;
155 }
157
158private:
159 mlir::ModuleOp mod;
160 // Using mutable because many operations are not const by default, even for "const"-like
161 // operations, like "getName()", and this reduces const_casts.
162 mutable component::StructDefOp structDef;
163
164 // Transitive closure only over signals.
165 llvm::EquivalenceClasses<ConstrainRef> signalSets;
166 // A simple set mapping of constants, as we do not want to compute a transitive closure over
167 // constants.
168 std::unordered_map<ConstrainRef, ConstrainRefSet, ConstrainRef::Hash> constantSets;
169
170 // Also mutable for caching within otherwise const lookup operations.
171 mutable mlir::SymbolTableCollection tables;
172
177 : mod(m), structDef(s), signalSets() {}
178
184 mlir::LogicalResult computeConstraints(mlir::DataFlowSolver &solver, mlir::AnalysisManager &am);
185
192 void walkConstrainOp(mlir::DataFlowSolver &solver, mlir::Operation *emitOp);
193};
194
200 : public StructAnalysis<ConstraintDependencyGraph, NoContext> {
201public:
203
204 mlir::LogicalResult runAnalysis(
205 mlir::DataFlowSolver &solver, mlir::AnalysisManager &moduleAnalysisManager, NoContext &_
206 ) override {
207 return runAnalysis(solver, moduleAnalysisManager);
208 }
209
212 mlir::LogicalResult
213 runAnalysis(mlir::DataFlowSolver &solver, mlir::AnalysisManager &moduleAnalysisManager);
214};
215
219 : public ModuleAnalysis<
220 ConstraintDependencyGraph, NoContext, ConstraintDependencyGraphStructAnalysis> {
221
222public:
224
225protected:
226 void initializeSolver(mlir::DataFlowSolver &solver) override {
227 (void)solver.load<ConstrainRefAnalysis>();
228 }
229
230 NoContext getContext() override { return {}; }
231};
232
233} // namespace llzk
Convenience classes for a frequent pattern of dataflow analysis used in LLZK, where an analysis is ru...
The dataflow analysis that computes the set of references that LLZK operations use and produce.
void visitCallControlFlowTransfer(mlir::CallOpInterface call, dataflow::CallControlFlowAction action, const ConstrainRefLattice &before, ConstrainRefLattice *after) override
Hook for customizing the behavior of lattice propagation along the call control flow edges.
mlir::ChangeResult fallbackOpUpdate(mlir::Operation *op, const ConstrainRefLattice::ValueMap &operandVals, const ConstrainRefLattice &before, ConstrainRefLattice *after)
void arraySubdivisionOpUpdate(mlir::Operation *op, const ConstrainRefLattice::ValueMap &operandVals, const ConstrainRefLattice &before, ConstrainRefLattice *after)
void setToEntryState(ConstrainRefLattice *lattice) override
Set the dense lattice at control flow entry point and propagate an update if it changed.
void visitOperation(mlir::Operation *op, const ConstrainRefLattice &before, ConstrainRefLattice *after) override
Propagate constrain reference lattice values from operands to results.
A lattice for use in dense analysis.
mlir::DenseMap< mlir::Value, ConstrainRefLatticeValue > ValueMap
Defines a reference to a llzk object within a constrain function call.
A module-level analysis for constructing ConstraintDependencyGraph objects for all structs in the giv...
ModuleAnalysis(mlir::Operation *op)
Asserts that the analysis is being run on a ModuleOp.
NoContext getContext() override
Create and return a valid Context object.
void initializeSolver(mlir::DataFlowSolver &solver) override
Initialize the shared dataflow solver with any common analyses required by the contained struct analy...
An analysis wrapper around the ConstraintDependencyGraph for a given struct.
StructAnalysis(mlir::Operation *op)
Assert that this analysis is being run on a StructDefOp and initializes the analysis with the current...
mlir::LogicalResult runAnalysis(mlir::DataFlowSolver &solver, mlir::AnalysisManager &moduleAnalysisManager, NoContext &_) override
Perform the analysis and construct the Result output.
static mlir::FailureOr< ConstraintDependencyGraph > compute(mlir::ModuleOp mod, component::StructDefOp s, mlir::DataFlowSolver &solver, mlir::AnalysisManager &am)
Compute a ConstraintDependencyGraph (CDG)
ConstraintDependencyGraph & operator=(const ConstraintDependencyGraph &other)
void print(mlir::raw_ostream &os) const
Print the CDG to the specified output stream.
ConstraintDependencyGraph translate(ConstrainRefRemappings translation) const
Translate the ConstrainRefs in this CDG to that of a different context.
ConstrainRefSet getConstrainingValues(const ConstrainRef &ref) const
Get the values that are connected to the given ref via emitted constraints.
ConstraintDependencyGraph(const ConstraintDependencyGraph &other)
void dump() const
Dumps the CDG to stderr.
ModuleAnalysis(mlir::Operation *op)
Asserts that the analysis is being run on a ModuleOp.
StructAnalysis(mlir::Operation *op)
Assert that this analysis is being run on a StructDefOp and initializes the analysis with the current...
LLZK: This class has been ported so that it can inherit from our port of the AbstractDenseForwardData...
mlir::dataflow::CallControlFlowAction CallControlFlowAction
std::vector< std::pair< ConstrainRef, ConstrainRefLatticeValue > > ConstrainRefRemappings
An empty struct that is used for convenience for analyses that do not require any context.