LLZK 3.0.0
An open-source IR for Zero Knowledge (ZK) circuits
Loading...
Searching...
No Matches
SparseAnalysis.h
Go to the documentation of this file.
1//===- SparseAnalysis.h - LLZK sparse data-flow adapter -------------------===//
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// Portions adapted from mlir/include/mlir/Analysis/DataFlow/SparseAnalysis.h.
9// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
10// See https://llvm.org/LICENSE.txt for license information.
11// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
12//
13//===----------------------------------------------------------------------===//
21//===----------------------------------------------------------------------===//
22
23#pragma once
24
25#include <mlir/Analysis/DataFlow/DeadCodeAnalysis.h>
26#include <mlir/Analysis/DataFlow/SparseAnalysis.h>
27#include <mlir/Analysis/DataFlowFramework.h>
28#include <mlir/IR/Block.h>
29#include <mlir/IR/Operation.h>
30#include <mlir/IR/Region.h>
31#include <mlir/IR/SymbolTable.h>
32#include <mlir/IR/Value.h>
33#include <mlir/Interfaces/CallInterfaces.h>
34#include <mlir/Interfaces/ControlFlowInterfaces.h>
35#include <mlir/Support/LLVM.h>
36
37#include <llvm/ADT/SmallVector.h>
38#include <llvm/Support/Casting.h>
39
40#include <type_traits>
41
42namespace llzk::dataflow {
43
44using AbstractSparseLattice = mlir::dataflow::AbstractSparseLattice;
45
46//===----------------------------------------------------------------------===//
47// AbstractSparseForwardDataFlowAnalysis
48//===----------------------------------------------------------------------===//
49
63 : public mlir::dataflow::AbstractSparseForwardDataFlowAnalysis {
64 using Base = mlir::dataflow::AbstractSparseForwardDataFlowAnalysis;
65
66public:
72 mlir::LogicalResult initialize(mlir::Operation *top) override;
73
76 mlir::LogicalResult visit(mlir::ProgramPoint *point) override;
77
78protected:
79 explicit AbstractSparseForwardDataFlowAnalysis(mlir::DataFlowSolver &s);
80
83 mlir::SymbolTableCollection tables;
84
85private:
93 mlir::LogicalResult initializeRecursivelyInProgramOrder(mlir::Operation *op);
94
96 mlir::LogicalResult visitOperationDuringInitialization(mlir::Operation *op);
97
99 bool isOperationLive(mlir::Operation *op);
100
103 llvm::SmallVector<const AbstractSparseLattice *, 4>
104 collectOperandLatticesAndSubscribe(mlir::Operation *op);
105
107 mlir::LogicalResult visitZeroResultCallOperation(
108 mlir::CallOpInterface call, mlir::ArrayRef<const AbstractSparseLattice *> operandLattices
109 );
110
114 mlir::LogicalResult visitZeroResultOperation(mlir::Operation *op);
115};
116
117//===----------------------------------------------------------------------===//
118// SparseForwardDataFlowAnalysis
119//===----------------------------------------------------------------------===//
120
125template <typename StateT>
127 static_assert(
128 std::is_base_of<AbstractSparseLattice, StateT>::value,
129 "analysis state class expected to subclass AbstractSparseLattice"
130 );
131
132public:
133 explicit SparseForwardDataFlowAnalysis(mlir::DataFlowSolver &s)
135
139 virtual mlir::LogicalResult visitOperation(
140 mlir::Operation *op, mlir::ArrayRef<const StateT *> operands, mlir::ArrayRef<StateT *> results
141 ) = 0;
142
145 virtual void visitExternalCall(
146 mlir::CallOpInterface /*call*/, mlir::ArrayRef<const StateT *> /*argumentLattices*/,
147 mlir::ArrayRef<StateT *> resultLattices
148 ) {
149 setAllToEntryStates(resultLattices);
150 }
151
159 mlir::Operation * /*op*/, const mlir::RegionSuccessor &successor,
160 mlir::ArrayRef<StateT *> argLattices, unsigned firstIndex
161 ) {
162 setAllToEntryStates(argLattices.take_front(firstIndex));
163 setAllToEntryStates(argLattices.drop_front(firstIndex + successor.getSuccessorInputs().size()));
164 }
165
166protected:
168 StateT *getLatticeElement(mlir::Value value) override { return getOrCreate<StateT>(value); }
169
172 const StateT *getLatticeElementFor(mlir::ProgramPoint *point, mlir::Value value) {
173 return static_cast<const StateT *>(
174 mlir::dataflow::AbstractSparseForwardDataFlowAnalysis::getLatticeElementFor(point, value)
175 );
176 }
177
179 virtual void setToEntryState(StateT *lattice) = 0;
180 void setAllToEntryStates(mlir::ArrayRef<StateT *> lattices) {
181 mlir::dataflow::AbstractSparseForwardDataFlowAnalysis::setAllToEntryStates(
182 {reinterpret_cast<AbstractSparseLattice *const *>(lattices.begin()), lattices.size()}
183 );
184 }
185
186private:
189 mlir::LogicalResult visitOperationImpl(
190 mlir::Operation *op, mlir::ArrayRef<const AbstractSparseLattice *> operandLattices,
191 mlir::ArrayRef<AbstractSparseLattice *> resultLattices
192 ) override {
193 return visitOperation(
194 op,
195 {reinterpret_cast<const StateT *const *>(operandLattices.begin()), operandLattices.size()},
196 {reinterpret_cast<StateT *const *>(resultLattices.begin()), resultLattices.size()}
197 );
198 }
199
200 void visitExternalCallImpl(
201 mlir::CallOpInterface call, mlir::ArrayRef<const AbstractSparseLattice *> argumentLattices,
202 mlir::ArrayRef<AbstractSparseLattice *> resultLattices
203 ) override {
205 call,
206 {reinterpret_cast<const StateT *const *>(argumentLattices.begin()),
207 argumentLattices.size()},
208 {reinterpret_cast<StateT *const *>(resultLattices.begin()), resultLattices.size()}
209 );
210 }
211
212 void visitNonControlFlowArgumentsImpl(
213 mlir::Operation *op, const mlir::RegionSuccessor &successor,
214 mlir::ArrayRef<AbstractSparseLattice *> argLattices, unsigned firstIndex
215 ) override {
217 op, successor, {reinterpret_cast<StateT *const *>(argLattices.begin()), argLattices.size()},
218 firstIndex
219 );
220 }
221
222 void setToEntryState(AbstractSparseLattice *lattice) override {
223 return setToEntryState(reinterpret_cast<StateT *>(lattice));
224 }
225};
226
227} // namespace llzk::dataflow
mlir::LogicalResult visit(mlir::ProgramPoint *point) override
Delegate block starts and result-producing operations to upstream MLIR.
mlir::LogicalResult initialize(mlir::Operation *top) override
Initialize the analysis while preserving the program-order visitation of the old LLZK sparse analysis...
mlir::SymbolTableCollection tables
LLZK: Kept as a compatibility cache for analyses that derived from the old ported class and used this...
const StateT * getLatticeElementFor(mlir::ProgramPoint *point, mlir::Value value)
Get the lattice element for a value and create a dependency on the provided program point.
virtual void visitExternalCall(mlir::CallOpInterface, mlir::ArrayRef< const StateT * >, mlir::ArrayRef< StateT * > resultLattices)
Visit a call operation to an externally defined function given the lattices of its arguments.
SparseForwardDataFlowAnalysis(mlir::DataFlowSolver &s)
virtual void visitNonControlFlowArguments(mlir::Operation *, const mlir::RegionSuccessor &successor, mlir::ArrayRef< StateT * > argLattices, unsigned firstIndex)
Given an operation with possible region control-flow, the lattices of the operands,...
void setAllToEntryStates(mlir::ArrayRef< StateT * > lattices)
virtual mlir::LogicalResult visitOperation(mlir::Operation *op, mlir::ArrayRef< const StateT * > operands, mlir::ArrayRef< StateT * > results)=0
Visit an operation with the lattices of its operands.
virtual void setToEntryState(StateT *lattice)=0
Set the given lattice element(s) at control-flow entry point(s).
StateT * getLatticeElement(mlir::Value value) override
Get the lattice element for a value.
mlir::dataflow::AbstractSparseLattice AbstractSparseLattice