LLZK 3.0.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
26#include "llzk/Util/Compare.h"
27#include "llzk/Util/Field.h"
28
29#include <mlir/Analysis/DataFlow/DenseAnalysis.h>
30#include <mlir/IR/BuiltinOps.h>
31#include <mlir/Pass/AnalysisManager.h>
32#include <mlir/Support/LLVM.h>
33
34#include <llvm/ADT/DynamicAPInt.h>
35#include <llvm/ADT/MapVector.h>
36#include <llvm/ADT/ScopeExit.h>
37#include <llvm/Support/SMTAPI.h>
38
39#include <array>
40#include <mutex>
41#include <optional>
42#include <unordered_set>
43
44namespace llzk {
45
46/* ExpressionValue */
47
51public:
52 /* Must be default initializable to be a ScalarLatticeValue. */
53 ExpressionValue() : i(), expr(nullptr), unreduced(std::nullopt) {}
54
55 explicit ExpressionValue(const Field &f)
56 : i(Interval::Entire(f)), expr(nullptr), unreduced(std::nullopt) {}
57
58 ExpressionValue(const Field &f, llvm::SMTExprRef exprRef)
59 : i(Interval::Entire(f)), expr(exprRef), unreduced(std::nullopt) {}
60
61 ExpressionValue(const Field &f, llvm::SMTExprRef exprRef, const llvm::DynamicAPInt &singleVal)
62 : i(Interval::Degenerate(f, singleVal)), expr(exprRef), unreduced(std::nullopt) {}
63
65 llvm::SMTExprRef exprRef, const Interval &interval,
66 std::optional<UnreducedInterval> unreducedInterval = std::nullopt
67 )
68 : i(interval), expr(exprRef), unreduced(std::move(unreducedInterval)) {}
69
70 llvm::SMTExprRef getExpr() const { return expr; }
71
72 const Interval &getInterval() const { return i; }
73
74 bool hasUnreducedInterval() const { return unreduced.has_value(); }
75
76 const std::optional<UnreducedInterval> &getOptionalUnreducedInterval() const { return unreduced; }
77
79 ensure(unreduced.has_value(), "unreduced interval not set");
80 return *unreduced;
81 }
82
83 const Field &getField() const { return i.getField(); }
84
88 ExpressionValue withInterval(const Interval &newInterval) const {
89 return ExpressionValue(expr, newInterval, unreduced);
90 }
91
93 ExpressionValue withExpression(const llvm::SMTExprRef &newExpr) const {
94 return ExpressionValue(newExpr, i, unreduced);
95 }
96
97 ExpressionValue withUnreducedInterval(const UnreducedInterval &newUnreducedInterval) const {
98 return ExpressionValue(expr, i, newUnreducedInterval);
99 }
100
102 withOptionalUnreducedInterval(std::optional<UnreducedInterval> newUnreducedInterval) const {
103 return ExpressionValue(expr, i, std::move(newUnreducedInterval));
104 }
105
106 ExpressionValue dropUnreducedInterval() const { return ExpressionValue(expr, i, std::nullopt); }
107
108 /* Required to be a ScalarLatticeValue. */
112 unreduced = std::nullopt;
113 return *this;
114 }
115
116 bool operator==(const ExpressionValue &rhs) const;
117
118 bool isBoolSort(const llvm::SMTSolverRef &solver) const {
119 return solver->getBoolSort() == solver->getSort(expr);
120 }
121
129 const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs
130 );
131
138 friend ExpressionValue
139 join(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
140
141 // arithmetic ops
142
143 friend ExpressionValue
144 add(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
145
146 friend ExpressionValue
147 sub(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
148
149 friend ExpressionValue
150 mul(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
151
152 friend ExpressionValue
153 div(const llvm::SMTSolverRef &solver, mlir::Operation *op, const ExpressionValue &lhs,
154 const ExpressionValue &rhs);
155
157 const llvm::SMTSolverRef &solver, mlir::Operation *op, const ExpressionValue &lhs,
158 const ExpressionValue &rhs
159 );
160
162 const llvm::SMTSolverRef &solver, mlir::Operation *op, const ExpressionValue &lhs,
163 const ExpressionValue &rhs
164 );
165
166 friend ExpressionValue
167 mod(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
168
169 friend ExpressionValue
170 bitAnd(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
171
172 friend ExpressionValue
173 bitOr(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
174
175 friend ExpressionValue
176 bitXor(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
177
179 const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs
180 );
181
183 const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs
184 );
185
186 friend ExpressionValue
187 cmp(const llvm::SMTSolverRef &solver, boolean::CmpOp op, const ExpressionValue &lhs,
188 const ExpressionValue &rhs);
189
190 friend ExpressionValue
191 boolAnd(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
192
193 friend ExpressionValue
194 boolOr(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
195
196 friend ExpressionValue
197 boolXor(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs);
198
199 friend ExpressionValue neg(const llvm::SMTSolverRef &solver, const ExpressionValue &val);
200
201 friend ExpressionValue notOp(const llvm::SMTSolverRef &solver, const ExpressionValue &val);
202
203 friend ExpressionValue boolNot(const llvm::SMTSolverRef &solver, const ExpressionValue &val);
204
206 const llvm::SMTSolverRef &solver, mlir::Operation *op, const ExpressionValue &val
207 );
208
209 /* Utility */
210
211 void print(mlir::raw_ostream &os) const;
212
213 friend mlir::raw_ostream &operator<<(mlir::raw_ostream &os, const ExpressionValue &e) {
214 e.print(os);
215 return os;
216 }
217
218 struct Hash {
219 unsigned operator()(const ExpressionValue &e) const {
220 return Interval::Hash {}(e.i) ^ llvm::hash_value(e.expr) ^
221 std::hash<bool> {}(e.unreduced.has_value()) ^
222 (e.unreduced.has_value() ? UnreducedInterval::Hash {}(*e.unreduced) : 0U);
223 }
224 };
225
226private:
227 Interval i;
228 llvm::SMTExprRef expr;
229 std::optional<UnreducedInterval> unreduced;
230};
231
232/* IntervalAnalysisLatticeValue */
233
234// NOLINTNEXTLINE(bugprone-exception-escape)
248
249/* IntervalAnalysisLattice */
250
252
254public:
256 // Map mlir::Values to LatticeValues
257 using ValueMap = mlir::DenseMap<mlir::Value, LatticeValue>;
258 // Map member references to LatticeValues. Used for member reads and writes.
259 // Structure is component value -> member attribute -> latticeValue
260 using MemberMap = mlir::DenseMap<mlir::Value, mlir::DenseMap<mlir::StringAttr, LatticeValue>>;
261 // Expression to interval map for convenience.
262 using ExpressionIntervals = mlir::DenseMap<llvm::SMTExprRef, Interval>;
263 // Tracks all constraints and assignments in insertion order
264 using ConstraintSet = llvm::SetVector<ExpressionValue>;
265
266 using AbstractSparseLattice::AbstractSparseLattice;
267
268 mlir::ChangeResult join(const AbstractSparseLattice &other) override;
269
270 mlir::ChangeResult meet(const AbstractSparseLattice &other) override;
271
272 void print(mlir::raw_ostream &os) const override;
273
274 const LatticeValue &getValue() const { return val; }
275
276 mlir::ChangeResult setValue(const LatticeValue &val);
277 mlir::ChangeResult setValue(const ExpressionValue &e);
278
279 mlir::ChangeResult addSolverConstraint(const ExpressionValue &e);
280
281 friend mlir::raw_ostream &operator<<(mlir::raw_ostream &os, const IntervalAnalysisLattice &l) {
282 l.print(os);
283 return os;
284 }
285
286 const ConstraintSet &getConstraints() const { return constraints; }
287
288 mlir::FailureOr<Interval> findInterval(llvm::SMTExprRef expr) const;
289 mlir::ChangeResult setInterval(llvm::SMTExprRef expr, const Interval &i);
290
291private:
292 LatticeValue val;
293 ConstraintSet constraints;
294};
295
296/* IntervalDataFlowAnalysis */
297
299 : public dataflow::SparseForwardDataFlowAnalysis<IntervalAnalysisLattice> {
301 using Lattice = IntervalAnalysisLattice;
302 using LatticeValue = IntervalAnalysisLattice::LatticeValue;
303
304 // Map SourceRefs to their symbols.
305 using SymbolMap = mlir::DenseMap<SourceRef, llvm::SMTExprRef>;
306
307public:
309 mlir::DataFlowSolver &dataflowSolver, llvm::SMTSolverRef smt, const Field &f,
310 bool propInputConstraints, bool shouldTrackUnreducedIntervals
311 )
312 : Base::SparseForwardDataFlowAnalysis(dataflowSolver), _dataflowSolver(dataflowSolver),
313 smtSolver(std::move(smt)), field(f), propagateInputConstraints(propInputConstraints),
314 trackUnreducedIntervals(shouldTrackUnreducedIntervals) {}
315
316 mlir::LogicalResult visitOperation(
317 mlir::Operation *op, mlir::ArrayRef<const Lattice *> operands,
318 mlir::ArrayRef<Lattice *> results
319 ) override;
320
325 llvm::SMTExprRef getOrCreateSymbol(const SourceRef &r);
326
327 const llvm::DenseMap<SourceRef, llvm::DenseSet<Lattice *>> &getReadResults() const {
328 return readResults;
329 }
330
331 const llvm::DenseMap<SourceRef, ExpressionValue> &getWriteResults() const { return writeResults; }
332
333private:
334 mlir::DataFlowSolver &_dataflowSolver;
335 llvm::SMTSolverRef smtSolver;
336 SymbolMap refSymbols;
337 std::reference_wrapper<const Field> field;
338 bool propagateInputConstraints;
339 bool trackUnreducedIntervals;
340 mlir::SymbolTableCollection tables;
341
342 // Track SourceRef-indexed reads so writes to rooted storage can update existing readers.
343 llvm::DenseMap<SourceRef, llvm::DenseSet<Lattice *>> readResults;
344 // Track SourceRef-indexed writes. For now, we'll overapproximate repeated writes.
345 llvm::DenseMap<SourceRef, ExpressionValue> writeResults;
346
347 void setToEntryState(Lattice *lattice) override {
348 // Initialize the value with an interval in our specified field.
349 (void)lattice->setValue(ExpressionValue(field.get()));
350 }
351
352 static bool isBooleanType(mlir::Type ty) {
353 if (auto intTy = llvm::dyn_cast<mlir::IntegerType>(ty)) {
354 return intTy.getWidth() == 1;
355 }
356 return false;
357 }
358
359 Interval getDefaultIntervalForType(mlir::Type ty) const {
360 return isBooleanType(ty) ? Interval::Boolean(field.get()) : Interval::Entire(field.get());
361 }
362
363 std::optional<UnreducedInterval> getDefaultUnreducedIntervalForType(mlir::Type ty) const;
364
365 std::optional<UnreducedInterval> getRefUnreducedInterval(const SourceRef &ref);
366
367 llvm::SMTExprRef createSymbol(mlir::Type ty, const char *name) const;
368
369 llvm::SMTExprRef createSymbol(const SourceRef &r) const;
370
371 llvm::SMTExprRef createSymbol(mlir::Value val) const;
372
373 ExpressionValue createUnknownValue(mlir::Value val) const {
374 return ExpressionValue(
375 createSymbol(val), getDefaultIntervalForType(val.getType()),
376 getDefaultUnreducedIntervalForType(val.getType())
377 );
378 }
379
380 inline bool isConstOp(mlir::Operation *op) const {
381 return llvm::isa<
382 felt::FeltConstantOp, mlir::arith::ConstantIndexOp, mlir::arith::ConstantIntOp>(op);
383 }
384
385 inline bool isBoolConstOp(mlir::Operation *op) const {
386 if (auto constIntOp = llvm::dyn_cast<mlir::arith::ConstantIntOp>(op)) {
387 auto valAttr = dyn_cast<mlir::IntegerAttr>(constIntOp.getValue());
388 ensure(valAttr != nullptr, "arith::ConstantIntOp must have an IntegerAttr as its value");
389 return valAttr.getValue().getBitWidth() == 1;
390 }
391 return false;
392 }
393
394 llvm::DynamicAPInt getConst(mlir::Operation *op) const;
395
396 inline llvm::SMTExprRef createConstBitvectorExpr(const llvm::DynamicAPInt &v) const {
397 return createConstBitvectorExpr(toAPSInt(v));
398 }
399
400 inline llvm::SMTExprRef createConstBitvectorExpr(const llvm::APSInt &v) const {
401 return smtSolver->mkBitvector(v, field.get().bitWidth());
402 }
403
404 llvm::SMTExprRef createConstBoolExpr(bool v) const { return smtSolver->mkBoolean(v); }
405
406 bool isArithmeticOp(mlir::Operation *op) const {
407 return llvm::isa<
408 felt::AddFeltOp, felt::SubFeltOp, felt::MulFeltOp, felt::DivFeltOp, felt::UnsignedModFeltOp,
409 felt::SignedModFeltOp, felt::SignedIntDivFeltOp, felt::UnsignedIntDivFeltOp,
410 mlir::arith::XOrIOp, felt::NegFeltOp, felt::InvFeltOp, felt::AndFeltOp, felt::OrFeltOp,
411 felt::XorFeltOp, felt::NotFeltOp, felt::ShlFeltOp, felt::ShrFeltOp, boolean::CmpOp,
412 boolean::AndBoolOp, boolean::OrBoolOp, boolean::XorBoolOp, boolean::NotBoolOp>(op);
413 }
414
415 ExpressionValue
416 performBinaryArithmetic(mlir::Operation *op, const LatticeValue &a, const LatticeValue &b);
417
418 ExpressionValue performUnaryArithmetic(mlir::Operation *op, const LatticeValue &a);
419
426 void applyInterval(mlir::Operation *originalOp, mlir::Value val, Interval newInterval);
427
429 mlir::FailureOr<std::pair<llvm::DenseSet<mlir::Value>, Interval>>
430 getGeneralizedDecompInterval(mlir::Operation *baseOp, mlir::Value lhs, mlir::Value rhs);
431
432 bool isReadOp(mlir::Operation *op) const {
433 return llvm::isa<
434 component::MemberReadOp, polymorphic::ConstReadOp, array::ReadArrayOp, pod::ReadPodOp>(op);
435 }
436
437 bool isDefinitionOp(mlir::Operation *op) const {
438 return llvm::isa<
439 component::StructDefOp, function::FuncDefOp, component::MemberDefOp, global::GlobalDefOp,
440 mlir::ModuleOp>(op);
441 }
442
443 bool isReturnOp(mlir::Operation *op) const { return llvm::isa<function::ReturnOp>(op); }
444
448 std::vector<SourceRefIndex>
449 getArrayAccessIndices(mlir::Operation *baseOp, array::ArrayAccessOpInterface arrayAccessOp);
450
453 mlir::FailureOr<SourceRef>
454 getArrayAccessRef(mlir::Operation *baseOp, array::ArrayAccessOpInterface arrayAccessOp);
455
458 Interval getRefInterval(const SourceRef &ref);
459
463 ExpressionValue getRefValue(const SourceRef &ref, mlir::Value val);
464
470 void recordRefWrite(
471 const SourceRef &writtenRef, const ExpressionValue &writeVal, bool mayBeSkipped = false
472 );
473
475 SourceRefLatticeValue getSourceRefState(mlir::Value val);
476};
477
478/* StructIntervals */
479
483 llvm::SMTSolverRef smtSolver;
484 std::optional<std::reference_wrapper<const Field>> field;
487
488 llvm::SMTExprRef getSymbol(const SourceRef &r) const { return intervalDFA->getOrCreateSymbol(r); }
489 bool hasField() const { return field.has_value(); }
490 const Field &getField() const {
491 ensure(field.has_value(), "field not set within context");
492 return field->get();
493 }
496
497 friend bool
499};
500
501} // namespace llzk
502
503template <> struct std::hash<llzk::IntervalAnalysisContext> {
505 return llvm::hash_combine(
507 std::hash<const llzk::IntervalDataFlowAnalysis *> {}(c.intervalDFA),
508 std::hash<const llvm::SMTSolver *> {}(c.smtSolver.get()),
509 std::hash<bool> {}(c.propagateInputConstraints),
510 std::hash<bool> {}(c.trackUnreducedIntervals)
511 );
512 }
513};
514
515namespace llzk {
516
517class StructIntervals {
518public:
529 static mlir::FailureOr<StructIntervals> compute(
530 mlir::ModuleOp mod, component::StructDefOp s, mlir::DataFlowSolver &solver,
531 mlir::AnalysisManager &am, const IntervalAnalysisContext &ctx
532 ) {
533 StructIntervals si(mod, s);
534 if (si.computeIntervals(solver, am, ctx).failed()) {
535 return mlir::failure();
536 }
537 return si;
538 }
539
540 mlir::LogicalResult computeIntervals(
541 mlir::DataFlowSolver &solver, mlir::AnalysisManager &am, const IntervalAnalysisContext &ctx
542 );
543
544 void print(
545 mlir::raw_ostream &os, bool withConstraints = false, bool printCompute = false,
546 bool printUnreduced = false
547 ) const;
548
549 const llvm::MapVector<SourceRef, Interval> &getConstrainIntervals() const {
550 return constrainMemberRanges;
551 }
552
553 const llvm::MapVector<SourceRef, UnreducedInterval> &getConstrainUnreducedIntervals() const {
554 return constrainMemberUnreducedRanges;
555 }
556
557 const llvm::SetVector<ExpressionValue> getConstrainSolverConstraints() const {
558 return constrainSolverConstraints;
559 }
560
561 const llvm::MapVector<SourceRef, Interval> &getComputeIntervals() const {
562 return computeMemberRanges;
563 }
564
565 const llvm::MapVector<SourceRef, UnreducedInterval> &getComputeUnreducedIntervals() const {
566 return computeMemberUnreducedRanges;
567 }
568
569 const llvm::SetVector<ExpressionValue> getComputeSolverConstraints() const {
570 return computeSolverConstraints;
571 }
572
573 friend mlir::raw_ostream &operator<<(mlir::raw_ostream &os, const StructIntervals &si) {
574 si.print(os);
575 return os;
576 }
577
578private:
579 mlir::ModuleOp mod;
580 component::StructDefOp structDef;
581 llvm::SMTSolverRef smtSolver;
582 // llvm::MapVector keeps insertion order for consistent iteration
583 llvm::MapVector<SourceRef, Interval> constrainMemberRanges, computeMemberRanges;
584 llvm::MapVector<SourceRef, UnreducedInterval> constrainMemberUnreducedRanges,
585 computeMemberUnreducedRanges;
586 // llvm::SetVector for the same reasons as above
587 llvm::SetVector<ExpressionValue> constrainSolverConstraints, computeSolverConstraints;
588
589 StructIntervals(mlir::ModuleOp m, component::StructDefOp s) : mod(m), structDef(s) {}
590};
591
592/* StructIntervalAnalysis */
593
595
596class StructIntervalAnalysis : public StructAnalysis<StructIntervals, IntervalAnalysisContext> {
597public:
599 ~StructIntervalAnalysis() override = default;
600
601 bool inProgress(const IntervalAnalysisContext &ctx) const {
602 return inProgressContexts.contains(ctx);
603 }
604
605 mlir::LogicalResult runAnalysis(
606 mlir::DataFlowSolver &solver, mlir::AnalysisManager &am, const IntervalAnalysisContext &ctx
607 ) override {
608 if (inProgress(ctx)) {
609 return mlir::failure();
610 }
611 inProgressContexts.insert(ctx);
612 auto cleanup = llvm::scope_exit([this, &ctx] { inProgressContexts.erase(ctx); });
613
614 auto computeRes = StructIntervals::compute(getModule(), getStruct(), solver, am, ctx);
615 if (mlir::failed(computeRes)) {
616 return mlir::failure();
617 }
618 setResult(ctx, std::move(*computeRes));
619 return mlir::success();
620 }
621
622private:
623 std::unordered_set<IntervalAnalysisContext> inProgressContexts;
624};
625
626/* ModuleIntervalAnalysis */
627
629 : public ModuleAnalysis<StructIntervals, IntervalAnalysisContext, StructIntervalAnalysis> {
630
631public:
632 // We set intraprocedural to false for the sake of the SourceRefAnalysis
633 ModuleIntervalAnalysis(mlir::Operation *op)
634 : ModuleAnalysis(op, mlir::DataFlowConfig().setInterprocedural(false)), ctx {} {
635 ctx.smtSolver = llvm::CreateZ3Solver();
636 }
637 ~ModuleIntervalAnalysis() override = default;
638
639 void setField(const Field &f) { ctx.field = f; }
640 void setPropagateInputConstraints(bool prop) { ctx.propagateInputConstraints = prop; }
641 void setTrackUnreducedIntervals(bool track) { ctx.trackUnreducedIntervals = track; }
642
643protected:
644 void initializeSolver() override {
645 ensure(ctx.hasField(), "field not set, could not generate analysis context");
646 (void)solver.load<SourceRefAnalysis>();
647 auto smtSolverRef = ctx.smtSolver;
648 bool prop = ctx.propagateInputConstraints;
649 bool track = ctx.trackUnreducedIntervals;
650 ctx.intervalDFA =
651 solver.load<IntervalDataFlowAnalysis, llvm::SMTSolverRef, const Field &, bool, bool>(
652 std::move(smtSolverRef), ctx.getField(),
653 std::move(prop), // NOLINT(performance-move-const-arg)
654 std::move(track) // NOLINT(performance-move-const-arg)
655 );
656 }
657
658 const IntervalAnalysisContext &getContext() const override {
659 ensure(ctx.field.has_value(), "field not set, could not generate analysis context");
660 return ctx;
661 }
662
663private:
665};
666
667} // namespace llzk
668
669namespace llvm {
670
671template <> struct DenseMapInfo<llzk::ExpressionValue> {
672 static unsigned getHashValue(const llzk::ExpressionValue &e) {
673 return llzk::ExpressionValue::Hash {}(e);
674 }
675 static bool isEqual(const llzk::ExpressionValue &lhs, const llzk::ExpressionValue &rhs) {
676 return lhs == rhs;
677 }
678};
679
680} // namespace llvm
Convenience classes for a frequent pattern of dataflow analysis used in LLZK, where an analysis is ru...
This file provides LLZK's sparse forward data-flow analysis compatibility layer.
Tracks a solver expression and an interval range for that expression.
friend ExpressionValue boolAnd(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
ExpressionValue withUnreducedInterval(const UnreducedInterval &newUnreducedInterval) const
friend ExpressionValue sintDiv(const llvm::SMTSolverRef &solver, mlir::Operation *op, const ExpressionValue &lhs, const ExpressionValue &rhs)
ExpressionValue withExpression(const llvm::SMTExprRef &newExpr) const
Return the current expression with a new SMT expression.
friend ExpressionValue fallbackUnaryOp(const llvm::SMTSolverRef &solver, mlir::Operation *op, const ExpressionValue &val)
friend ExpressionValue bitOr(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
friend ExpressionValue notOp(const llvm::SMTSolverRef &solver, const ExpressionValue &val)
friend ExpressionValue shiftRight(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
friend ExpressionValue intersection(const 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...
ExpressionValue(llvm::SMTExprRef exprRef, const Interval &interval, std::optional< UnreducedInterval > unreducedInterval=std::nullopt)
friend ExpressionValue uintDiv(const llvm::SMTSolverRef &solver, mlir::Operation *op, const ExpressionValue &lhs, const ExpressionValue &rhs)
const Interval & getInterval() const
friend ExpressionValue mul(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
friend ExpressionValue div(const llvm::SMTSolverRef &solver, mlir::Operation *op, const ExpressionValue &lhs, const ExpressionValue &rhs)
ExpressionValue(const Field &f, llvm::SMTExprRef exprRef)
const std::optional< UnreducedInterval > & getOptionalUnreducedInterval() const
ExpressionValue(const Field &f)
ExpressionValue withOptionalUnreducedInterval(std::optional< UnreducedInterval > newUnreducedInterval) const
friend ExpressionValue sub(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
ExpressionValue withInterval(const Interval &newInterval) const
Return the current expression with a new interval.
friend ExpressionValue boolXor(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
void print(mlir::raw_ostream &os) const
bool operator==(const ExpressionValue &rhs) const
friend ExpressionValue shiftLeft(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
friend ExpressionValue mod(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
friend ExpressionValue bitXor(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
friend ExpressionValue bitAnd(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
llvm::SMTExprRef getExpr() const
bool isBoolSort(const llvm::SMTSolverRef &solver) const
friend ExpressionValue cmp(const llvm::SMTSolverRef &solver, boolean::CmpOp op, const ExpressionValue &lhs, const ExpressionValue &rhs)
friend ExpressionValue join(const 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...
bool hasUnreducedInterval() const
ExpressionValue(const Field &f, llvm::SMTExprRef exprRef, const llvm::DynamicAPInt &singleVal)
friend ExpressionValue boolOr(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
friend ExpressionValue boolNot(const llvm::SMTSolverRef &solver, const ExpressionValue &val)
friend mlir::raw_ostream & operator<<(mlir::raw_ostream &os, const ExpressionValue &e)
const Field & getField() const
const UnreducedInterval & getUnreducedInterval() const
ExpressionValue & join(const ExpressionValue &)
Fold two expressions together when overapproximating array elements.
friend ExpressionValue neg(const llvm::SMTSolverRef &solver, const ExpressionValue &val)
friend ExpressionValue add(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
ExpressionValue dropUnreducedInterval() const
Information about the prime finite field used for the interval analysis.
Definition Field.h:36
static const Field & getField(llvm::StringRef fieldName, EmitErrorFn errFn)
Get a Field from a given field name string.
IntervalAnalysisLatticeValue & operator=(const IntervalAnalysisLatticeValue &)=default
IntervalAnalysisLatticeValue(IntervalAnalysisLatticeValue &&)=default
IntervalAnalysisLatticeValue(const IntervalAnalysisLatticeValue &)=default
IntervalAnalysisLatticeValue(mlir::ArrayRef< int64_t > shape)
IntervalAnalysisLatticeValue & operator=(IntervalAnalysisLatticeValue &&)=default
IntervalAnalysisLatticeValue(ExpressionValue e)
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
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::ChangeResult addSolverConstraint(const ExpressionValue &e)
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, ExpressionValue > & getWriteResults() const
const llvm::DenseMap< SourceRef, llvm::DenseSet< Lattice * > > & getReadResults() const
IntervalDataFlowAnalysis(mlir::DataFlowSolver &dataflowSolver, llvm::SMTSolverRef smt, const Field &f, bool propInputConstraints, bool shouldTrackUnreducedIntervals)
Intervals over a finite field.
Definition Intervals.h:207
static Interval Boolean(const Field &f)
Definition Intervals.h:228
ModuleAnalysis(mlir::Operation *op, const mlir::DataFlowConfig &config=mlir::DataFlowConfig())
ModuleIntervalAnalysis(mlir::Operation *op)
~ModuleIntervalAnalysis() override=default
void setPropagateInputConstraints(bool prop)
void initializeSolver() override
Initialize the shared dataflow solver with any common analyses required by the contained struct analy...
void setTrackUnreducedIntervals(bool track)
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:152
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)
mlir::LogicalResult runAnalysis(mlir::DataFlowSolver &solver, mlir::AnalysisManager &am, const IntervalAnalysisContext &ctx) override
Perform the analysis and construct the Result output.
~StructIntervalAnalysis() override=default
StructAnalysis(mlir::Operation *op)
Assert that this analysis is being run on a StructDefOp and initializes the analysis with the current...
bool inProgress(const IntervalAnalysisContext &ctx) const
const llvm::MapVector< SourceRef, Interval > & getConstrainIntervals() const
static mlir::FailureOr< StructIntervals > compute(mlir::ModuleOp mod, component::StructDefOp s, mlir::DataFlowSolver &solver, mlir::AnalysisManager &am, const IntervalAnalysisContext &ctx)
Compute the struct intervals.
const llvm::SetVector< ExpressionValue > getConstrainSolverConstraints() const
const llvm::MapVector< SourceRef, UnreducedInterval > & getConstrainUnreducedIntervals() 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, bool printUnreduced=false) const
friend mlir::raw_ostream & operator<<(mlir::raw_ostream &os, const StructIntervals &si)
const llvm::MapVector< SourceRef, UnreducedInterval > & getComputeUnreducedIntervals() const
mlir::LogicalResult computeIntervals(mlir::DataFlowSolver &solver, mlir::AnalysisManager &am, const IntervalAnalysisContext &ctx)
An inclusive interval [a, b] where a and b are arbitrary integers not necessarily bound to a given fi...
Definition Intervals.h:26
mlir::SymbolTableCollection tables
LLZK: Kept as a compatibility cache for analyses that derived from the old ported class and used this...
A sparse forward data-flow analysis for propagating SSA value lattices across the IR by implementing ...
mlir::dataflow::AbstractSparseLattice AbstractSparseLattice
ExpressionValue mod(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
void ensure(bool condition, const llvm::Twine &errMsg)
APSInt toAPSInt(const DynamicAPInt &i)
static unsigned getHashValue(const llzk::ExpressionValue &e)
static bool isEqual(const llzk::ExpressionValue &lhs, const llzk::ExpressionValue &rhs)
unsigned operator()(const ExpressionValue &e) const
Hash the prime modulus (consistent with the equality operator).
Definition Field.h:120
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