LLZK 3.0.0
An open-source IR for Zero Knowledge (ZK) circuits
Loading...
Searching...
No Matches
IntervalAnalysisPass.cpp
Go to the documentation of this file.
1//===-- IntervalAnalysisPass.cpp --------------------------------*- 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//===----------------------------------------------------------------------===//
13//===----------------------------------------------------------------------===//
14
20#include "llzk/Util/Constants.h"
22
23#include <mlir/IR/AsmState.h>
24
25#include <llvm/ADT/STLExtras.h>
26#include <llvm/ADT/SmallVector.h>
27#include <llvm/Support/Debug.h>
28#include <llvm/Support/ErrorHandling.h>
29
30namespace llzk {
31#define GEN_PASS_DEF_INTERVALANALYSISPRINTERPASS
33} // namespace llzk
34
35#define DEBUG_TYPE "llzk-interval-analysis-pass"
36
37using namespace mlir;
38using namespace llzk;
39using namespace llzk::component;
40using namespace llzk::function;
41
42namespace {
43
44class PassImpl : public llzk::impl::IntervalAnalysisPrinterPassBase<PassImpl> {
45 using Base = IntervalAnalysisPrinterPassBase<PassImpl>;
46 using Base::Base;
47
48 void runOnOperation() override {
49 markAllAnalysesPreserved();
50
51 auto modOp = llvm::dyn_cast<ModuleOp>(getOperation());
52 if (!modOp) {
53 constexpr const char *msg = "IntervalAnalysisPrinterPass error: should be run on ModuleOp!";
54 getOperation()->emitError(msg).report();
55 return;
56 }
57
58 // Initialize to the fallback field value
59 FieldRef selectedField = Field::getField("bn128");
60 if (!fieldName.empty()) {
61 auto fieldLookupRes = Field::tryGetField(fieldName.c_str());
62 if (failed(fieldLookupRes)) {
63 modOp->emitError()
64 .append(
65 "IntervalAnalysisPrinterPass error: unknown field \"", fieldName, "\" specified"
66 )
67 .report();
68 return;
69 }
70 selectedField = fieldLookupRes.value();
71 LLVM_DEBUG(
72 llvm::dbgs() << "[IntervalAnalysisPrinterPass] using explicit -field override '"
73 << selectedField.get().name() << "'\n";
74 );
75 } else if (auto detectedField = tryDetectSpecifiedField(modOp)) {
76 selectedField = detectedField.value();
77 LLVM_DEBUG(
78 llvm::dbgs() << "[IntervalAnalysisPrinterPass] detected module field '"
79 << selectedField.get().name() << "' from module felt usage\n";
80 );
81 } else {
82 modOp->emitWarning() << "could not detect a unique module field; falling back to '"
83 << selectedField.get().name() << '\'';
84 LLVM_DEBUG(
85 llvm::dbgs() << "[IntervalAnalysisPrinterPass] no explicit or detectable module field; "
86 "falling back to '"
87 << selectedField.get().name() << "'\n";
88 );
89 }
90
91 auto &mia = getAnalysis<ModuleIntervalAnalysis>();
92 mia.setField(selectedField);
93 mia.setPropagateInputConstraints(propagateInputConstraints);
94 mia.setTrackUnreducedIntervals(printUnreducedIntervals);
95 auto am = getAnalysisManager();
96 mia.ensureAnalysisRun(am);
97 AsmState asmState(modOp);
98
99 auto printValueInterval = [this, &asmState, &mia](raw_ostream &out, int indent, Value value) {
100 if (llvm::isa<llzk::array::ArrayType, StructType, llzk::pod::PodType>(value.getType())) {
101 return;
102 }
103 const auto *lattice = mia.getSolver().lookupState<IntervalAnalysisLattice>(value);
104 if (!lattice) {
105 return;
106 }
107 const ExpressionValue &expr = lattice->getValue().getScalarValue();
108 out << '\n';
109 out.indent(indent);
110 value.printAsOperand(out, asmState);
111 if (auto opResult = llvm::dyn_cast<OpResult>(value)) {
112 out << " [" << opResult.getOwner()->getName().getStringRef() << "]";
113 }
114 out << " in " << expr.getInterval();
115 if (printUnreducedIntervals && expr.hasUnreducedInterval()) {
116 out << " ( unreduced: " << expr.getUnreducedInterval() << " )";
117 }
118 };
119
120 auto printFunctionSSAIntervals =
121 [&printValueInterval](raw_ostream &out, FuncDefOp fn, llvm::StringRef fnName) {
122 if (!fn) {
123 return;
124 }
125
126 out << '\n';
127 out.indent(4) << fnName << " {";
128 for (BlockArgument arg : fn.getArguments()) {
129 printValueInterval(out, 8, arg);
130 }
131 fn.walk([&](Operation *op) {
132 if (op == fn.getOperation()) {
133 return;
134 }
135 for (Value result : op->getResults()) {
136 printValueInterval(out, 8, result);
137 }
138 });
139 out << '\n';
140 out.indent(4) << '}';
141 };
142
143 auto &os = llzk::toStream(outputStream);
144 for (const auto &[s, si] : mia.getCurrentResults()) {
145 auto &structDef = const_cast<StructDefOp &>(s);
146 auto fullName = getPathFromTopRoot(structDef);
147 ensure(
148 succeeded(fullName),
149 "could not resolve fully qualified name of struct " + Twine(structDef.getName())
150 );
151 os << fullName.value() << ' ';
152 si.get().print(os, printSolverConstraints, printComputeIntervals, printUnreducedIntervals);
153 if (printSSAIntervals) {
154 os << fullName.value() << " SSAIntervals {";
155 if (printComputeIntervals) {
156 printFunctionSSAIntervals(os, structDef.getComputeFuncOp(), FUNC_NAME_COMPUTE);
157 }
158 printFunctionSSAIntervals(os, structDef.getConstrainFuncOp(), FUNC_NAME_CONSTRAIN);
159 if (auto productFn = structDef.getProductFuncOp();
160 productFn && (!structDef.getConstrainFuncOp() || printComputeIntervals)) {
161 printFunctionSSAIntervals(os, productFn, FUNC_NAME_PRODUCT);
162 }
163 os << "\n}\n";
164 }
165 }
166 }
167};
168
169} // namespace
Tracks a solver expression and an interval range for that expression.
const Interval & getInterval() const
bool hasUnreducedInterval() const
const UnreducedInterval & getUnreducedInterval() const
static llvm::FailureOr< std::reference_wrapper< const Field > > tryGetField(llvm::StringRef fieldName)
Get a Field from a given field name string, or failure if the field is not defined.
Definition Field.cpp:54
static const Field & getField(llvm::StringRef fieldName, EmitErrorFn errFn)
Get a Field from a given field name string.
constexpr char FUNC_NAME_COMPUTE[]
Symbol name for the witness generation (and resp.
Definition Constants.h:16
std::reference_wrapper< const Field > FieldRef
Typealias for a stable reference to a known Field.
Definition Field.h:157
constexpr char FUNC_NAME_CONSTRAIN[]
Definition Constants.h:17
llvm::raw_ostream & toStream(OutputStream val)
void ensure(bool condition, const llvm::Twine &errMsg)
constexpr char FUNC_NAME_PRODUCT[]
Definition Constants.h:18
FailureOr< SymbolRefAttr > getPathFromTopRoot(SymbolOpInterface to, ModuleOp *foundRoot)
std::optional< std::reference_wrapper< const Field > > tryDetectSpecifiedField(mlir::Operation *root)
Try to detect a uniquely used field from the enclosing LLZK module.