33#include <mlir/Dialect/Arith/IR/Arith.h>
34#include <mlir/Dialect/ControlFlow/IR/ControlFlowOps.h>
35#include <mlir/Dialect/Func/Extensions/InlinerExtension.h>
36#include <mlir/Dialect/Func/IR/FuncOps.h>
37#include <mlir/Dialect/MemRef/IR/MemRef.h>
38#include <mlir/Dialect/SCF/IR/SCF.h>
39#include <mlir/Dialect/SMT/IR/SMTDialect.h>
40#include <mlir/IR/BuiltinDialect.h>
41#include <mlir/IR/BuiltinOps.h>
42#include <mlir/IR/Diagnostics.h>
43#include <mlir/IR/DialectRegistry.h>
44#include <mlir/Parser/Parser.h>
46#include <llvm/ADT/StringExtras.h>
47#include <llvm/Support/CommandLine.h>
48#include <llvm/Support/FileSystem.h>
49#include <llvm/Support/FormatVariadic.h>
50#include <llvm/Support/JSON.h>
51#include <llvm/Support/MemoryBuffer.h>
52#include <llvm/Support/PrettyStackTrace.h>
53#include <llvm/Support/Signals.h>
54#include <llvm/Support/SourceMgr.h>
62static int runMain(
int argc,
char **argv) {
63 llvm::cl::opt<std::string> InputFilename(llvm::cl::Positional, llvm::cl::Required);
64 llvm::cl::opt<std::string> InputsFilename(
65 "inputs", llvm::cl::Required, llvm::cl::desc(
"JSON input file")
67 llvm::cl::list<std::string> IncludeDirs(
68 "I", llvm::cl::desc(
"Directory of include files"), llvm::cl::value_desc(
"directory"),
71 llvm::cl::opt<std::string> BackendName(
72 "backend", llvm::cl::desc(
"Execution backend: interpreter or execution-engine"),
73 llvm::cl::init(
"interpreter")
75 llvm::cl::opt<std::string> OutputScopeName(
76 "output-scope", llvm::cl::desc(
"Output scope: public or full-witness"),
77 llvm::cl::init(
"public")
79 llvm::cl::opt<std::string> UninitializedBehaviorName(
80 "uninitialized-behavior",
81 llvm::cl::desc(
"Uninitialized value behavior: zero, random, or fail"), llvm::cl::init(
"zero")
83 llvm::cl::opt<uint64_t> UninitializedSeed(
84 "uninitialized-seed", llvm::cl::desc(
"Seed for random uninitialized values")
86 llvm::cl::opt<bool> DumpJITCore(
"dump-jit-core", llvm::cl::desc(
"Print the pre-LLVM JIT module"));
87 llvm::cl::opt<bool> DumpJITLLVM(
88 "dump-jit-llvm", llvm::cl::desc(
"Print the post-LLVM JIT module")
90 llvm::cl::opt<std::string> CheckOutputFilename(
91 "check-output", llvm::cl::desc(
"JSON file with expected witgen output")
93 llvm::cl::opt<std::string> WtnsOutputFilename(
94 "output-wtns", llvm::cl::desc(
"Write a snarkjs-compatible .wtns file")
97 llvm::sys::PrintStackTraceOnErrorSignal(llvm::StringRef());
98 llvm::setBugReportMsg(
100 " and include the crash backtrace, relevant LLZK files, and associated run script(s).\n"
103 llvm::cl::ParseCommandLineOptions(
105 "llzk-witgen: execute LLZK compute semantics and emit JSON public outputs.\n"
106 "Note: llzk-witgen v1 ignores constrain() and traps on bool.assert.\n"
109 DialectRegistry registry;
112 mlir::func::registerInlinerExtension(registry);
114 mlir::arith::ArithDialect, mlir::cf::ControlFlowDialect, mlir::func::FuncDialect,
115 mlir::memref::MemRefDialect, mlir::scf::SCFDialect>();
118 context.appendDialectRegistry(registry);
119 context.loadAllAvailableDialects();
125 auto sourceBuffer = llvm::MemoryBuffer::getFileOrSTDIN(InputFilename);
127 llvm::errs() << sourceBuffer.getError().message() <<
'\n';
131 ParserConfig parserConfig(&context);
132 llvm::SourceMgr sourceMgr;
133 sourceMgr.AddNewSourceBuffer(std::move(*sourceBuffer), llvm::SMLoc());
135 SourceMgrDiagnosticHandler diagnosticHandler(sourceMgr, &context);
136 OwningOpRef<ModuleOp> moduleOp = parseSourceFile<ModuleOp>(sourceMgr, parserConfig);
141 auto buffer = llvm::MemoryBuffer::getFileOrSTDIN(InputsFilename);
143 llvm::errs() << buffer.getError().message() <<
'\n';
147 auto parsed = llvm::json::parse(buffer.get()->getBuffer());
149 llvm::errs() <<
"failed to parse JSON input: " << llvm::toString(parsed.takeError()) <<
'\n';
154 if (BackendName ==
"execution-engine") {
156 }
else if (BackendName ==
"interpreter") {
159 llvm::errs() <<
"unknown backend: " << BackendName <<
'\n';
162 if (OutputScopeName ==
"full-witness") {
164 }
else if (OutputScopeName ==
"public") {
167 llvm::errs() <<
"unknown output scope: " << OutputScopeName <<
'\n';
170 if (UninitializedBehaviorName ==
"zero") {
172 }
else if (UninitializedBehaviorName ==
"random") {
174 }
else if (UninitializedBehaviorName ==
"fail") {
177 llvm::errs() <<
"unknown uninitialized behavior: " << UninitializedBehaviorName <<
'\n';
180 if (UninitializedSeed.getNumOccurrences() > 0) {
186 if (WtnsOutputFilename.getNumOccurrences() > 0) {
187 if (WtnsOutputFilename ==
"-") {
188 llvm::errs() <<
"--output-wtns does not support stdout; specify an output file\n";
191 if (OutputScopeName.getNumOccurrences() > 0 && OutputScopeName !=
"full-witness") {
192 llvm::errs() <<
"--output-wtns conflicts with --output-scope=" << OutputScopeName
193 <<
"; use --output-scope=full-witness\n";
202 llvm::errs() <<
"llzk-witgen error: " << llvm::toString(result.takeError()) <<
'\n';
206 if (WtnsOutputFilename.getNumOccurrences() > 0) {
212 llvm::errs() <<
"llzk-witgen error: .wtns output requires exactly one field\n";
215 const llzk::Field &field = (*fields.begin()).get();
217 llvm::errs() <<
"llzk-witgen error: " << llvm::toString(std::move(error)) <<
'\n';
222 if (CheckOutputFilename.getNumOccurrences() > 0) {
223 auto expectedBuffer = llvm::MemoryBuffer::getFileOrSTDIN(CheckOutputFilename);
224 if (!expectedBuffer) {
225 llvm::errs() << expectedBuffer.getError().message() <<
'\n';
229 auto expected = llvm::json::parse(expectedBuffer.get()->getBuffer());
231 llvm::errs() <<
"failed to parse expected JSON output: "
232 << llvm::toString(expected.takeError()) <<
'\n';
236 llvm::SmallVector<llzk::witgen::JSONMismatch> mismatches;
238 if (!mismatches.empty()) {
239 llvm::errs() <<
"llzk-witgen output mismatch:\n";
244 llvm::outs() <<
"output matched expected JSON\n";
248 llvm::outs() << llvm::formatv(
"{0:2}", *result) <<
'\n';
252int main(
int argc,
char **argv)
noexcept {
254 return runMain(argc, argv);
255 }
catch (
const std::exception &ex) {
256 llvm::errs() <<
"llzk-witgen: unhandled exception: " << ex.what() <<
'\n';
258 llvm::errs() <<
"llzk-witgen: unhandled non-standard exception\n";
Information about the prime finite field used for the interval analysis.
static GlobalSourceMgr & get()
int main(int argc, char **argv) noexcept
Declares dialect and pass registration functions for core LLZK dialects.
@ Public
Emit only public outputs.
@ FullWitness
Emit inputs plus public outputs and members marked as witness signals.
@ R1CSWitness
Emit inputs plus every scalar main member needed to construct an R1CS witness.
void diffJSON(const llvm::json::Value &expected, const llvm::json::Value &actual, llvm::SmallVectorImpl< JSONMismatch > &out, llvm::StringRef path)
Compare two JSON values structurally and append any mismatches to out.
llvm::Expected< llvm::json::Value > runWitgen(ModuleOp moduleOp, const llvm::json::Value &input, const WitgenOptions &options)
Run include preprocessing, field validation, and backend execution.
llvm::Error writeWtns(ModuleOp moduleOp, const llvm::json::Value &fullWitness, const Field &field, StringRef outputFilename)
void printJSONMismatches(llvm::raw_ostream &os, llvm::ArrayRef< JSONMismatch > mismatches)
Render one human-readable mismatch report.
void registerDialects(mlir::DialectRegistry ®istry)
Register core LLZK dialects, the MLIR arith, scf, and smt dialects, and verification extensions in re...
llvm::SmallSet< FieldRef, 2 > FieldSet
Typealias for a set of Fields.
mlir::LogicalResult collectFields(mlir::Operation *root, FieldSet &fields, bool silent=true)
Collects all the fields used in a circuit.
void registerInliningExtensions(DialectRegistry ®istry)
Configure one llzk-witgen execution.
UninitializedBehavior uninitializedBehavior
std::optional< uint64_t > randomSeed