LLZK 0.1.0
An open-source IR for Zero Knowledge (ZK) circuits
Loading...
Searching...
No Matches
IntervalAnalysis.h
Go to the documentation of this file.
1//===-- IntervalAnalysis.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
16#include "llzk/Analysis/Field.h"
27#include "llzk/Util/Compare.h"
28
29#include <mlir/IR/BuiltinOps.h>
30#include <mlir/Pass/AnalysisManager.h>
31#include <mlir/Support/LLVM.h>
32
33#include <llvm/ADT/DynamicAPInt.h>
34#include <llvm/ADT/MapVector.h>
35#include <llvm/Support/SMTAPI.h>
36
37#include <array>
38#include <mutex>
39
40namespace llzk {
41
42/* ExpressionValue */
43
47public:
48 /* Must be default initializable to be a ScalarLatticeValue. */
49 ExpressionValue() : i(), expr(nullptr) {}
50
51 explicit ExpressionValue(const Field &f) : i(Interval::Entire(f)), expr(nullptr) {}
52
53 ExpressionValue(const Field &f, llvm::SMTExprRef exprRef)
54 : i(Interval::Entire(f)), expr(exprRef) {}
55
56 ExpressionValue(const Field &f, llvm::SMTExprRef exprRef, const llvm::DynamicAPInt &singleVal)
57 : i(Interval::Degenerate(f, singleVal)), expr(exprRef) {}
58
59 ExpressionValue(llvm::SMTExprRef exprRef, const Interval &interval)
60 : i(interval), expr(exprRef) {}
61
62 llvm::SMTExprRef getExpr() const { return expr; }
63
64 const Interval &getInterval() const { return i; }
65
66 const Field &getField() const { return i.getField(); }
67
71 ExpressionValue withInterval(const Interval &newInterval) const {
72 return ExpressionValue(expr, newInterval);
73 }
74
76 ExpressionValue withExpression(const llvm::SMTExprRef &newExpr) const {
77 return ExpressionValue(newExpr, i);
78 }
79
80 /* Required to be a ScalarLatticeValue. */
84 return *this;
85 }
86
87 bool operator==(const ExpressionValue &rhs) const;
88
89 bool isBoolSort(llvm::SMTSolverRef solver) const {
90 return solver->getBoolSort() == solver->getSort(expr);
91 }
92
99 friend ExpressionValue
100 intersection(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
101
108 friend ExpressionValue
109 join(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
110
111 // arithmetic ops
112
113 friend ExpressionValue
114 add(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
115
116 friend ExpressionValue
117 sub(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
118
119 friend ExpressionValue
120 mul(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
121
122 friend ExpressionValue
123 div(llvm::SMTSolverRef solver, felt::DivFeltOp op, const ExpressionValue &lhs,
124 const ExpressionValue &rhs);
125
126 friend ExpressionValue
127 mod(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
128
129 friend ExpressionValue
130 bitAnd(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
131
132 friend ExpressionValue
133 shiftLeft(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
134
135 friend ExpressionValue
136 shiftRight(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
137
138 friend ExpressionValue
139 cmp(llvm::SMTSolverRef solver, boolean::CmpOp op, const ExpressionValue &lhs,
140 const ExpressionValue &rhs);
141
142 friend ExpressionValue
143 boolAnd(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
144
145 friend ExpressionValue
146 boolOr(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
147
148 friend ExpressionValue
149 boolXor(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
150
160 llvm::SMTSolverRef solver, mlir::Operation *op, const ExpressionValue &lhs,
161 const ExpressionValue &rhs
162 );
163
164 friend ExpressionValue neg(llvm::SMTSolverRef solver, const ExpressionValue &val);
165
166 friend ExpressionValue notOp(llvm::SMTSolverRef solver, const ExpressionValue &val);
167
168 friend ExpressionValue boolNot(llvm::SMTSolverRef solver, const ExpressionValue &val);
169
170 friend ExpressionValue
171 fallbackUnaryOp(llvm::SMTSolverRef solver, mlir::Operation *op, const ExpressionValue &val);
172
173 /* Utility */
174
175 void print(mlir::raw_ostream &os) const;
176
177 friend mlir::raw_ostream &operator<<(mlir::raw_ostream &os, const ExpressionValue &e) {
178 e.print(os);
179 return os;
180 }
181
182 struct Hash {
183 unsigned operator()(const ExpressionValue &e) const {
184 return Interval::Hash {}(e.i) ^ llvm::hash_value(e.expr);
185 }
186 };
187
188private:
189 Interval i;
190 llvm::SMTExprRef expr;
191};
192
193/* IntervalAnalysisLatticeValue */
194
196 : public dataflow::AbstractLatticeValue<IntervalAnalysisLatticeValue, ExpressionValue> {
197public:
198 using AbstractLatticeValue::AbstractLatticeValue;
199};
200
201/* IntervalAnalysisLattice */
202
204
206public:
208 // Map mlir::Values to LatticeValues
209 using ValueMap = mlir::DenseMap<mlir::Value, LatticeValue>;
210 // Map member references to LatticeValues. Used for member reads and writes.
211 // Structure is component value -> member attribute -> latticeValue
212 using MemberMap = mlir::DenseMap<mlir::Value, mlir::DenseMap<mlir::StringAttr, LatticeValue>>;
213 // Expression to interval map for convenience.
214 using ExpressionIntervals = mlir::DenseMap<llvm::SMTExprRef, Interval>;
215 // Tracks all constraints and assignments in insertion order
216 using ConstraintSet = llvm::SetVector<ExpressionValue>;
217
218 using AbstractSparseLattice::AbstractSparseLattice;
219
220 mlir::ChangeResult join(const AbstractSparseLattice &other) override;
221
222 mlir::ChangeResult meet(const AbstractSparseLattice &other) override;
223
224 void print(mlir::raw_ostream &os) const override;
225
226 const LatticeValue &getValue() const { return val; }
227
228 mlir::ChangeResult setValue(const LatticeValue &val);
229 mlir::ChangeResult setValue(ExpressionValue e);
230
231 mlir::ChangeResult addSolverConstraint(ExpressionValue e);
232
233 friend mlir::raw_ostream &operator<<(mlir::raw_ostream &os, const IntervalAnalysisLattice &l) {
234 l.print(os);
235 return os;
236 }
237
238 const ConstraintSet &getConstraints() const { return constraints; }
239
240 mlir::FailureOr<Interval> findInterval(llvm::SMTExprRef expr) const;
241 mlir::ChangeResult setInterval(llvm::SMTExprRef expr, const Interval &i);
242
243private:
244 LatticeValue val;
245 ConstraintSet constraints;
246};
247
248/* IntervalDataFlowAnalysis */
249
251 : public dataflow::SparseForwardDataFlowAnalysis<IntervalAnalysisLattice> {
253 using Lattice = IntervalAnalysisLattice;
254 using LatticeValue = IntervalAnalysisLattice::LatticeValue;
255
256 // Map members to their symbols
257 using SymbolMap = mlir::DenseMap<SourceRef, llvm::SMTExprRef>;
258
259public:
261 mlir::DataFlowSolver &dataflowSolver, llvm::SMTSolverRef smt, const Field &f,
262 bool propInputConstraints
263 )
264 : Base::SparseForwardDataFlowAnalysis(dataflowSolver), _dataflowSolver(dataflowSolver),
265 smtSolver(smt), field(f), propagateInputConstraints(propInputConstraints) {}
266
267 mlir::LogicalResult visitOperation(
268 mlir::Operation *op, mlir::ArrayRef<const Lattice *> operands,
269 mlir::ArrayRef<Lattice *> results
270 ) override;
271
276 llvm::SMTExprRef getOrCreateSymbol(const SourceRef &r);
277
278 const llvm::DenseMap<SourceRef, llvm::DenseSet<Lattice *>> &getMemberReadResults() const {
279 return memberReadResults;
280 }
281
282 const llvm::DenseMap<SourceRef, ExpressionValue> &getMemberWriteResults() const {
283 return memberWriteResults;
284 }
285
286private:
287 mlir::DataFlowSolver &_dataflowSolver;
288 llvm::SMTSolverRef smtSolver;
289 SymbolMap refSymbols;
290 std::reference_wrapper<const Field> field;
291 bool propagateInputConstraints;
292 mlir::SymbolTableCollection tables;
293
294 // Track member reads so that propagations to members can be all updated efficiently.
295 llvm::DenseMap<SourceRef, llvm::DenseSet<Lattice *>> memberReadResults;
296 // Track member writes values. For now, we'll overapproximate this.
297 llvm::DenseMap<SourceRef, ExpressionValue> memberWriteResults;
298
299 void setToEntryState(Lattice *lattice) override {
300 // Initialize the value with an interval in our specified field.
301 (void)lattice->setValue(ExpressionValue(field.get()));
302 }
303
304 llvm::SMTExprRef createFeltSymbol(const SourceRef &r) const;
305
306 llvm::SMTExprRef createFeltSymbol(mlir::Value val) const;
307
308 llvm::SMTExprRef createFeltSymbol(const char *name) const;
309
310 inline bool isConstOp(mlir::Operation *op) const {
311 return llvm::isa<
312 felt::FeltConstantOp, mlir::arith::ConstantIndexOp, mlir::arith::ConstantIntOp>(op);
313 }
314
315 inline bool isBoolConstOp(mlir::Operation *op) const {
316 if (auto constIntOp = llvm::dyn_cast<mlir::arith::ConstantIntOp>(op)) {
317 auto valAttr = dyn_cast<mlir::IntegerAttr>(constIntOp.getValue());
318 ensure(valAttr != nullptr, "arith::ConstantIntOp must have an IntegerAttr as its value");
319 return valAttr.getValue().getBitWidth() == 1;
320 }
321 return false;
322 }
323
324 llvm::DynamicAPInt getConst(mlir::Operation *op) const;
325
326 inline llvm::SMTExprRef createConstBitvectorExpr(const llvm::DynamicAPInt &v) const {
327 return createConstBitvectorExpr(toAPSInt(v));
328 }
329
330 inline llvm::SMTExprRef createConstBitvectorExpr(const llvm::APSInt &v) const {
331 return smtSolver->mkBitvector(v, field.get().bitWidth());
332 }
333
334 llvm::SMTExprRef createConstBoolExpr(bool v) const { return smtSolver->mkBoolean(v); }
335
336 bool isArithmeticOp(mlir::Operation *op) const {
337 return llvm::isa<
338 felt::AddFeltOp, felt::SubFeltOp, felt::MulFeltOp, felt::DivFeltOp, felt::UnsignedModFeltOp,
339 felt::SignedModFeltOp, felt::SignedIntDivFeltOp, felt::UnsignedIntDivFeltOp,
340 felt::NegFeltOp, felt::InvFeltOp, felt::AndFeltOp, felt::OrFeltOp, felt::XorFeltOp,
341 felt::NotFeltOp, felt::ShlFeltOp, felt::ShrFeltOp, boolean::CmpOp, boolean::AndBoolOp,
342 boolean::OrBoolOp, boolean::XorBoolOp, boolean::NotBoolOp>(op);
343 }
344
345 ExpressionValue
346 performBinaryArithmetic(mlir::Operation *op, const LatticeValue &a, const LatticeValue &b);
347
348 ExpressionValue performUnaryArithmetic(mlir::Operation *op, const LatticeValue &a);
349
356 void applyInterval(mlir::Operation *originalOp, mlir::Value val, Interval newInterval);
357
359 mlir::FailureOr<std::pair<llvm::DenseSet<mlir::Value>, Interval>>
360 getGeneralizedDecompInterval(mlir::Operation *baseOp, mlir::Value lhs, mlir::Value rhs);
361
362 bool isReadOp(mlir::Operation *op) const {
363 return llvm::isa<component::MemberReadOp, polymorphic::ConstReadOp, array::ReadArrayOp>(op);
364 }
365
366 bool isDefinitionOp(mlir::Operation *op) const {
367 return llvm::isa<
368 component::StructDefOp, function::FuncDefOp, component::MemberDefOp, global::GlobalDefOp,
369 mlir::ModuleOp>(op);
370 }
371
372 bool isReturnOp(mlir::Operation *op) const { return llvm::isa<function::ReturnOp>(op); }
373
376 const SourceRefLattice *getSourceRefLattice(mlir::Operation *baseOp, mlir::Value val);
377};
378
379/* StructIntervals */
380
384 llvm::SMTSolverRef smtSolver;
385 std::optional<std::reference_wrapper<const Field>> field;
387
388 llvm::SMTExprRef getSymbol(const SourceRef &r) const { return intervalDFA->getOrCreateSymbol(r); }
389 bool hasField() const { return field.has_value(); }
390 const Field &getField() const {
391 ensure(field.has_value(), "field not set within context");
392 return field->get();
393 }
395
396 friend bool
398};
399
400} // namespace llzk
401
402template <> struct std::hash<llzk::IntervalAnalysisContext> {
404 return llvm::hash_combine(
405 std::hash<const llzk::IntervalDataFlowAnalysis *> {}(c.intervalDFA),
406 std::hash<const llvm::SMTSolver *> {}(c.smtSolver.get()),
407 std::hash<const llzk::Field *> {}(&c.getField()),
408 std::hash<bool> {}(c.propagateInputConstraints)
409 );
410 }
411};
412
413namespace llzk {
414
415class StructIntervals {
416public:
426 static mlir::FailureOr<StructIntervals> compute(
427 mlir::ModuleOp mod, component::StructDefOp s, mlir::DataFlowSolver &solver,
428 const IntervalAnalysisContext &ctx
429 ) {
430 StructIntervals si(mod, s);
431 if (si.computeIntervals(solver, ctx).failed()) {
432 return mlir::failure();
433 }
434 return si;
435 }
436
437 mlir::LogicalResult
438 computeIntervals(mlir::DataFlowSolver &solver, const IntervalAnalysisContext &ctx);
439
440 void print(mlir::raw_ostream &os, bool withConstraints = false, bool printCompute = false) const;
441
442 const llvm::MapVector<SourceRef, Interval> &getConstrainIntervals() const {
443 return constrainMemberRanges;
444 }
445
446 const llvm::SetVector<ExpressionValue> getConstrainSolverConstraints() const {
447 return constrainSolverConstraints;
448 }
449
450 const llvm::MapVector<SourceRef, Interval> &getComputeIntervals() const {
451 return computeMemberRanges;
452 }
453
454 const llvm::SetVector<ExpressionValue> getComputeSolverConstraints() const {
455 return computeSolverConstraints;
456 }
457
458 friend mlir::raw_ostream &operator<<(mlir::raw_ostream &os, const StructIntervals &si) {
459 si.print(os);
460 return os;
461 }
462
463private:
464 mlir::ModuleOp mod;
465 component::StructDefOp structDef;
466 llvm::SMTSolverRef smtSolver;
467 // llvm::MapVector keeps insertion order for consistent iteration
468 llvm::MapVector<SourceRef, Interval> constrainMemberRanges, computeMemberRanges;
469 // llvm::SetVector for the same reasons as above
470 llvm::SetVector<ExpressionValue> constrainSolverConstraints, computeSolverConstraints;
471
472 StructIntervals(mlir::ModuleOp m, component::StructDefOp s) : mod(m), structDef(s) {}
473};
474
475/* StructIntervalAnalysis */
476
478
479class StructIntervalAnalysis : public StructAnalysis<StructIntervals, IntervalAnalysisContext> {
480public:
482 virtual ~StructIntervalAnalysis() = default;
483
484 mlir::LogicalResult runAnalysis(
485 mlir::DataFlowSolver &solver, mlir::AnalysisManager &, const IntervalAnalysisContext &ctx
486 ) override {
487 auto computeRes = StructIntervals::compute(getModule(), getStruct(), solver, ctx);
488 if (mlir::failed(computeRes)) {
489 return mlir::failure();
490 }
491 setResult(ctx, std::move(*computeRes));
492 return mlir::success();
493 }
494};
495
496/* ModuleIntervalAnalysis */
497
499 : public ModuleAnalysis<StructIntervals, IntervalAnalysisContext, StructIntervalAnalysis> {
500
501public:
502 ModuleIntervalAnalysis(mlir::Operation *op) : ModuleAnalysis(op), ctx {} {
503 ctx.smtSolver = llvm::CreateZ3Solver();
504 }
505 virtual ~ModuleIntervalAnalysis() = default;
506
507 void setField(const Field &f) { ctx.field = f; }
508 void setPropagateInputConstraints(bool prop) { ctx.propagateInputConstraints = prop; }
509
510protected:
511 void initializeSolver() override {
512 ensure(ctx.hasField(), "field not set, could not generate analysis context");
513 (void)solver.load<SourceRefAnalysis>();
514 auto smtSolverRef = ctx.smtSolver;
515 bool prop = ctx.propagateInputConstraints;
516 ctx.intervalDFA =
517 solver.load<IntervalDataFlowAnalysis, llvm::SMTSolverRef, const Field &, bool>(
518 std::move(smtSolverRef), ctx.getField(), std::move(prop)
519 );
520 }
521
522 const IntervalAnalysisContext &getContext() const override {
523 ensure(ctx.field.has_value(), "field not set, could not generate analysis context");
524 return ctx;
525 }
526
527private:
529};
530
531} // namespace llzk
532
533namespace llvm {
534
535template <> struct DenseMapInfo<llzk::ExpressionValue> {
536
537 static SMTExprRef getEmptyExpr() {
538 static auto emptyPtr = reinterpret_cast<SMTExprRef>(1);
539 return emptyPtr;
540 }
541 static SMTExprRef getTombstoneExpr() {
542 static auto tombstonePtr = reinterpret_cast<SMTExprRef>(2);
543 return tombstonePtr;
544 }
545
552 static unsigned getHashValue(const llzk::ExpressionValue &e) {
553 return llzk::ExpressionValue::Hash {}(e);
554 }
555 static bool isEqual(const llzk::ExpressionValue &lhs, const llzk::ExpressionValue &rhs) {
556 if (lhs.getExpr() == getEmptyExpr() || lhs.getExpr() == getTombstoneExpr() ||
557 rhs.getExpr() == getEmptyExpr() || rhs.getExpr() == getTombstoneExpr()) {
558 return lhs.getExpr() == rhs.getExpr();
559 }
560 return lhs == rhs;
561 }
562};
563
564} // namespace llvm
Convenience classes for a frequent pattern of dataflow analysis used in LLZK, where an analysis is ru...
This file implements (LLZK-tailored) dense data-flow analysis using the data-flow analysis framework.
This file implements sparse data-flow analysis using the data-flow analysis framework.
Tracks a solver expression and an interval range for that expression.
ExpressionValue(llvm::SMTExprRef exprRef, const Interval &interval)
ExpressionValue withExpression(const llvm::SMTExprRef &newExpr) const
Return the current expression with a new SMT expression.
friend ExpressionValue neg(llvm::SMTSolverRef solver, const ExpressionValue &val)
friend ExpressionValue notOp(llvm::SMTSolverRef solver, const ExpressionValue &val)
const Interval & getInterval() const
friend ExpressionValue cmp(llvm::SMTSolverRef solver, boolean::CmpOp op, const ExpressionValue &lhs, const ExpressionValue &rhs)
ExpressionValue(const Field &f, llvm::SMTExprRef exprRef)
friend ExpressionValue sub(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
ExpressionValue(const Field &f)
friend ExpressionValue mul(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
bool isBoolSort(llvm::SMTSolverRef solver) const
friend ExpressionValue fallbackUnaryOp(llvm::SMTSolverRef solver, mlir::Operation *op, const ExpressionValue &val)
friend ExpressionValue boolOr(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
friend ExpressionValue div(llvm::SMTSolverRef solver, felt::DivFeltOp op, const ExpressionValue &lhs, const ExpressionValue &rhs)
ExpressionValue withInterval(const Interval &newInterval) const
Return the current expression with a new interval.
void print(mlir::raw_ostream &os) const
bool operator==(const ExpressionValue &rhs) const
friend ExpressionValue add(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
friend ExpressionValue shiftRight(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
llvm::SMTExprRef getExpr() const
friend ExpressionValue fallbackBinaryOp(llvm::SMTSolverRef solver, mlir::Operation *op, const ExpressionValue &lhs, const ExpressionValue &rhs)
Computes a solver expression based on the operation, but computes a fallback interval (which is just ...
ExpressionValue(const Field &f, llvm::SMTExprRef exprRef, const llvm::DynamicAPInt &singleVal)
friend ExpressionValue bitAnd(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
friend ExpressionValue boolXor(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
friend ExpressionValue join(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
Compute the union of the lhs and rhs intervals, and create a solver expression that constrains both s...
friend mlir::raw_ostream & operator<<(mlir::raw_ostream &os, const ExpressionValue &e)
friend ExpressionValue boolAnd(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
const Field & getField() const
friend ExpressionValue mod(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
friend ExpressionValue shiftLeft(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
ExpressionValue & join(const ExpressionValue &)
Fold two expressions together when overapproximating array elements.
friend ExpressionValue intersection(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
Compute the intersection of the lhs and rhs intervals, and create a solver expression that constrains...
friend ExpressionValue boolNot(llvm::SMTSolverRef solver, const ExpressionValue &val)
Information about the prime finite field used for the interval analysis.
Definition Field.h:27
static const Field & getField(const char *fieldName)
Get a Field from a given field name string.
Definition Field.cpp:31
friend mlir::raw_ostream & operator<<(mlir::raw_ostream &os, const IntervalAnalysisLattice &l)
const LatticeValue & getValue() const
llvm::SetVector< ExpressionValue > ConstraintSet
mlir::ChangeResult setValue(const LatticeValue &val)
IntervalAnalysisLatticeValue LatticeValue
mlir::DenseMap< mlir::Value, LatticeValue > ValueMap
mlir::ChangeResult meet(const AbstractSparseLattice &other) override
mlir::ChangeResult addSolverConstraint(ExpressionValue e)
const ConstraintSet & getConstraints() const
mlir::DenseMap< mlir::Value, mlir::DenseMap< mlir::StringAttr, LatticeValue > > MemberMap
void print(mlir::raw_ostream &os) const override
mlir::ChangeResult join(const AbstractSparseLattice &other) override
mlir::ChangeResult setInterval(llvm::SMTExprRef expr, const Interval &i)
mlir::DenseMap< llvm::SMTExprRef, Interval > ExpressionIntervals
mlir::FailureOr< Interval > findInterval(llvm::SMTExprRef expr) const
mlir::LogicalResult visitOperation(mlir::Operation *op, mlir::ArrayRef< const Lattice * > operands, mlir::ArrayRef< Lattice * > results) override
Visit an operation with the lattices of its operands.
llvm::SMTExprRef getOrCreateSymbol(const SourceRef &r)
Either return the existing SMT expression that corresponds to the SourceRef, or create one.
const llvm::DenseMap< SourceRef, llvm::DenseSet< Lattice * > > & getMemberReadResults() const
const llvm::DenseMap< SourceRef, ExpressionValue > & getMemberWriteResults() const
IntervalDataFlowAnalysis(mlir::DataFlowSolver &dataflowSolver, llvm::SMTSolverRef smt, const Field &f, bool propInputConstraints)
Intervals over a finite field.
Definition Intervals.h:200
ModuleIntervalAnalysis(mlir::Operation *op)
virtual ~ModuleIntervalAnalysis()=default
void setPropagateInputConstraints(bool prop)
void initializeSolver() override
Initialize the shared dataflow solver with any common analyses required by the contained struct analy...
const IntervalAnalysisContext & getContext() const override
Return the current Context object.
void setField(const Field &f)
The dataflow analysis that computes the set of references that LLZK operations use and produce.
A reference to a "source", which is the base value from which other SSA values are derived.
Definition SourceRef.h:127
StructAnalysis(mlir::Operation *op)
Assert that this analysis is being run on a StructDefOp and initializes the analysis with the current...
void setResult(const IntervalAnalysisContext &ctx, StructIntervals &&r)
StructAnalysis(mlir::Operation *op)
Assert that this analysis is being run on a StructDefOp and initializes the analysis with the current...
virtual ~StructIntervalAnalysis()=default
mlir::LogicalResult runAnalysis(mlir::DataFlowSolver &solver, mlir::AnalysisManager &, const IntervalAnalysisContext &ctx) override
Perform the analysis and construct the Result output.
const llvm::MapVector< SourceRef, Interval > & getConstrainIntervals() const
const llvm::SetVector< ExpressionValue > getConstrainSolverConstraints() const
const llvm::SetVector< ExpressionValue > getComputeSolverConstraints() const
const llvm::MapVector< SourceRef, Interval > & getComputeIntervals() const
void print(mlir::raw_ostream &os, bool withConstraints=false, bool printCompute=false) const
static mlir::FailureOr< StructIntervals > compute(mlir::ModuleOp mod, component::StructDefOp s, mlir::DataFlowSolver &solver, const IntervalAnalysisContext &ctx)
Compute the struct intervals.
friend mlir::raw_ostream & operator<<(mlir::raw_ostream &os, const StructIntervals &si)
mlir::LogicalResult computeIntervals(mlir::DataFlowSolver &solver, const IntervalAnalysisContext &ctx)
mlir::SymbolTableCollection tables
LLZK: Added for use of symbol helper caching.
A sparse forward data-flow analysis for propagating SSA value lattices across the IR by implementing ...
mlir::dataflow::AbstractSparseLattice AbstractSparseLattice
void ensure(bool condition, const llvm::Twine &errMsg)
APSInt toAPSInt(const DynamicAPInt &i)
ExpressionValue mod(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
static unsigned getHashValue(const llzk::ExpressionValue &e)
static bool isEqual(const llzk::ExpressionValue &lhs, const llzk::ExpressionValue &rhs)
static llzk::ExpressionValue getTombstoneKey()
static llzk::ExpressionValue getEmptyKey()
unsigned operator()(const ExpressionValue &e) const
Parameters and shared objects to pass to child analyses.
const Field & getField() const
friend bool operator==(const IntervalAnalysisContext &a, const IntervalAnalysisContext &b)=default
std::optional< std::reference_wrapper< const Field > > field
IntervalDataFlowAnalysis * intervalDFA
llvm::SMTExprRef getSymbol(const SourceRef &r) const
size_t operator()(const llzk::IntervalAnalysisContext &c) const