LLZK 2.0.0
An open-source IR for Zero Knowledge (ZK) circuits
Loading...
Searching...
No Matches
Dialect.cpp
Go to the documentation of this file.
1//===-- Dialect.cpp - Felt dialect implementation ---------------*- 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
11
18#include "llzk/Util/Field.h"
19
20#include <mlir/IR/DialectImplementation.h>
21
22#include <llvm/ADT/TypeSwitch.h>
23
24// TableGen'd implementation files
26
27#define GET_TYPEDEF_CLASSES
29#define GET_ATTRDEF_CLASSES
31
32using namespace mlir;
33
34namespace llzk::felt {
35
36//===------------------------------------------------------------------===//
37// FieldSpecAttr
38//
39// Custom parse/print needs to be here where Attrs.cpp.inc is included, and
40// it doesn't work to put it in Attrs.cpp.
41//===------------------------------------------------------------------===//
42
43Attribute FieldSpecAttr::parse(AsmParser &odsParser, Type) {
44 Builder odsBuilder(odsParser.getContext());
45 llvm::SMLoc odsLoc = odsParser.getCurrentLocation();
46 FailureOr<StringAttr> fieldNameAttrRes;
47 FailureOr<llvm::APInt> primeRes;
48
49 // Parse literal '<'
50 if (odsParser.parseLess()) {
51 return {};
52 }
53
54 // Parse variable 'fieldName'
55 fieldNameAttrRes = FieldParser<StringAttr>::parse(odsParser);
56 if (failed(fieldNameAttrRes)) {
57 odsParser.emitError(
58 odsParser.getCurrentLocation(), "failed to parse LLZK_FieldSpecAttr parameter 'fieldName' "
59 "which is to be a `StringAttr`"
60 );
61 return {};
62 }
63 // Parse literal ','
64 if (odsParser.parseComma()) {
65 return {};
66 }
67
68 // Parse variable 'prime'
69 primeRes = FieldParser<llvm::APInt>::parse(odsParser);
70 if (failed(primeRes)) {
71 odsParser.emitError(
72 odsParser.getCurrentLocation(),
73 "failed to parse LLZK_FieldSpecAttr parameter 'prime' which is to be a `llvm::APInt`"
74 );
75 return {};
76 }
77 // Parse literal '>'
78 if (odsParser.parseGreater()) {
79 return {};
80 }
81 assert(succeeded(fieldNameAttrRes));
82 assert(succeeded(primeRes));
83
84 // Custom logic: cache the field, reporting an error if there's a conflict
85 auto errFn = [&odsParser]() {
86 return InFlightDiagnosticWrapper(odsParser.emitError(odsParser.getCurrentLocation()));
87 };
88 Field::addField(fieldNameAttrRes.value(), primeRes.value(), errFn);
89
90 return odsParser.getChecked<FieldSpecAttr>(
91 odsLoc, odsParser.getContext(), StringAttr(*fieldNameAttrRes), llvm::APInt(*primeRes)
92 );
93}
94
95void FieldSpecAttr::print(AsmPrinter &odsPrinter) const {
96 Builder odsBuilder(getContext());
97 odsPrinter << "<";
98 odsPrinter.printStrippedAttrOrType(getFieldName());
99 odsPrinter << ", ";
100 odsPrinter.printStrippedAttrOrType(getPrime());
101 odsPrinter << '>';
102}
103
104//===------------------------------------------------------------------===//
105// FeltConstAttr
106//===------------------------------------------------------------------===//
107
108Attribute FeltConstAttr::parse(AsmParser &odsParser, Type) {
109 SMLoc odsLoc = odsParser.getCurrentLocation();
110
111 // Parse the APInt value.
112 FailureOr<APInt> valueRes = FieldParser<APInt>::parse(odsParser);
113 if (failed(valueRes)) {
114 odsParser.emitError(
115 odsParser.getCurrentLocation(),
116 "failed to parse LLZK_FeltConstAttr parameter 'value' which is to be a `::llvm::APInt`"
117 );
118 return {};
119 }
120
121 FeltType type = FeltType::get(odsParser.getContext());
122
123 // v2 syntax: VALUE : !felt.type<"fieldName">
124 if (odsParser.parseOptionalColon().succeeded()) {
125 FailureOr<FeltType> typeRes = FieldParser<FeltType>::parse(odsParser);
126 if (failed(typeRes)) {
127 odsParser.emitError(
128 odsParser.getCurrentLocation(),
129 "failed to parse LLZK_FeltConstAttr parameter 'type' which is to be a `FeltType`"
130 );
131 return {};
132 }
133 type = *typeRes;
134 }
135 // v1 compat syntax: VALUE <"fieldName">
136 else if (odsParser.parseOptionalLess().succeeded()) {
137 FailureOr<StringAttr> fieldNameRes = FieldParser<StringAttr>::parse(odsParser);
138 if (failed(fieldNameRes)) {
139 odsParser.emitError(
140 odsParser.getCurrentLocation(), "failed to parse LLZK_FeltConstAttr(version 1) field "
141 "name parameter which is to be a `StringAttr`"
142 );
143 return {};
144 }
145 if (odsParser.parseGreater()) {
146 return {};
147 }
148 type = FeltType::get(odsParser.getContext(), (*fieldNameRes).getValue());
149 }
150
151 return odsParser.getChecked<FeltConstAttr>(odsLoc, odsParser.getContext(), *valueRes, type);
152}
153
154// Same as tablegen would generate to serialize version 2 IR.
155void FeltConstAttr::print(AsmPrinter &odsPrinter) const {
156 odsPrinter << ' ';
157 odsPrinter.printStrippedAttrOrType(getValue());
158 if (getType() != FeltType::get(getContext())) {
159 odsPrinter << " : ";
160 odsPrinter.printStrippedAttrOrType(getType());
161 }
162}
163
164//===------------------------------------------------------------------===//
165// FeltType
166//===------------------------------------------------------------------===//
167
168const Field &FeltType::getField() const { return Field::getField(getFieldName().getValue()); }
169
170llvm::LogicalResult
171FeltType::verify(llvm::function_ref<InFlightDiagnostic()> errFn, StringAttr fieldName) {
172 return fieldName ? Field::verifyFieldDefined(
173 fieldName.getValue(), wrapNonNullableInFlightDiagnostic(errFn)
174 )
175 : success();
176}
177
178//===------------------------------------------------------------------===//
179// FeltDialect
180//===------------------------------------------------------------------===//
181
182Operation *
183FeltDialect::materializeConstant(OpBuilder &builder, Attribute value, Type, Location loc) {
184 if (auto attr = llvm::dyn_cast<FeltConstAttr>(value)) {
185 return builder.create<FeltConstantOp>(loc, attr);
186 }
187 return nullptr;
188}
189
190auto FeltDialect::initialize() -> void {
191 // clang-format off
192 addOperations<
193 #define GET_OP_LIST
195 >();
196
197 // Suppress false positive from `clang-tidy`
198 // NOLINTNEXTLINE(clang-analyzer-core.StackAddressEscape)
199 addTypes<
200 #define GET_TYPEDEF_LIST
202 >();
203
204 addAttributes<
205 #define GET_ATTRDEF_LIST
207 >();
208 // clang-format on
209 addInterfaces<LLZKDialectBytecodeInterface<FeltDialect>>();
210}
211
212} // namespace llzk::felt
Information about the prime finite field used for the interval analysis.
Definition Field.h:35
static llvm::LogicalResult verifyFieldDefined(llvm::StringRef fieldName, EmitErrorFn errFn)
Search for a field with the given name, reporting an error if the field is not found.
Definition Field.cpp:60
static const Field & getField(llvm::StringRef fieldName, EmitErrorFn errFn)
Get a Field from a given field name string.
static void addField(llvm::StringRef fieldName, const llvm::APInt &prime, EmitErrorFn errFn)
Add a new field to the set of available prime fields.
Definition Field.h:40
::mlir::Operation * materializeConstant(::mlir::OpBuilder &builder, ::mlir::Attribute value, ::mlir::Type type, ::mlir::Location loc) override
Materialize a single constant operation from a given attribute value with the desired resultant type.
Definition Dialect.cpp:183
::llvm::LogicalResult verify(::llvm::function_ref<::mlir::InFlightDiagnostic()> emitError, ::mlir::StringAttr fieldName)
Definition Dialect.cpp:171
const ::llzk::Field & getField() const
Definition Dialect.cpp:168
::mlir::StringAttr getFieldName() const
static FeltType get(::mlir::MLIRContext *context, ::mlir::StringAttr fieldName)
Definition Types.cpp.inc:67
OwningEmitErrorFn wrapNonNullableInFlightDiagnostic(llvm::function_ref< mlir::InFlightDiagnostic()> emitError)