LLZK 0.1.0
Veridise's ZK Language IR
Loading...
Searching...
No Matches
Ops.td
Go to the documentation of this file.
1//===-- Ops.td ---------------------------------------------*- tablegen -*-===//
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// Adapted from mlir/include/mlir/Dialect/Func/IR/FuncOps.td
9// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
10// See https://llvm.org/LICENSE.txt for license information.
11// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLZK_STRUCT_OPS
16#define LLZK_STRUCT_OPS
17
18include "llzk/Dialect/Function/IR/OpTraits.td"
19include "llzk/Dialect/Struct/IR/Dialect.td"
20include "llzk/Dialect/Struct/IR/OpInterfaces.td"
21include "llzk/Dialect/Struct/IR/Types.td"
22include "llzk/Dialect/Shared/OpTraits.td"
23
24include "mlir/IR/OpAsmInterface.td"
25include "mlir/IR/RegionKindInterface.td"
26include "mlir/IR/SymbolInterfaces.td"
27
28class StructDialectOp<string mnemonic, list<Trait> traits = []>
29 : Op<StructDialect, mnemonic, traits>;
30
31/// Only valid/implemented for StructDefOp. Sets the proper `AllowWitnessAttr`
32/// and `AllowConstraintAttr` on the functions defined within the StructDefOp.
33def SetFuncAllowAttrs : NativeOpTrait<"SetFuncAllowAttrs">, StructuralOpTrait {
34 string cppNamespace = "::llzk::component";
35}
36
37//===------------------------------------------------------------------===//
38// Struct Operations
39//===------------------------------------------------------------------===//
40
41def LLZK_StructDefOp
42 : StructDialectOp<
43 "def", [HasParent<"::mlir::ModuleOp">, Symbol, SymbolTable,
44 IsolatedFromAbove, SetFuncAllowAttrs,
45 DeclareOpInterfaceMethods<SymbolUserOpInterface>,
46 NoRegionArguments]#GraphRegionNoTerminator.traits> {
47 let summary = "circuit component definition";
48 let description = [{
49 This operation describes a component in a circuit. It can contain any number
50 of fields that hold inputs, outputs, intermediate values, and subcomponents
51 of the defined component. It also contains a `compute()` function that holds
52 the witness generation code for the component and a `constrain()` function
53 that holds that constraint generation code for the component.
54
55 Example:
56
57 ```llzk
58 struct.def @ComponentA {
59 field @f1 : !array.type<5 x index>
60 field @f2 : !felt.type {llzk.pub}
61
62 function.def @compute(%p: !felt.type) -> !struct.type<@ComponentA> {
63 %self = struct.new : !struct.type<@ComponentA>
64 // initialize all fields of `%self` here
65 return %self : !struct.type<@ComponentA>
66 }
67
68 function.def @constrain(%self: !struct.type<@ComponentA>, %p: !felt.type) {
69 // emit constraints here
70 return
71 }
72 }
73 ```
74 }];
75
76 // Note: `$const_params` contains symbol definitions that do not use the
77 // standard SymbolTable mechanism. Instead hasParamNamed() can be used to
78 // check if a certain FlatSymbolRefAttr is a parameter in the function.
79 let arguments = (ins SymbolNameAttr:$sym_name,
80 OptionalAttr<FlatSymbolRefArrayAttr>:$const_params);
81
82 let regions = (region SizedRegion<1>:$bodyRegion);
83
84 let assemblyFormat = [{
85 $sym_name (`<` $const_params^ `>`)? $bodyRegion attr-dict
86 }];
87
88 let extraClassDeclaration = [{
89 /// Gets the StructType representing this struct. If the `constParams` to use in
90 /// the type are not given, the StructType will use `this->getConstParamsAttr()`.
91 StructType getType(::std::optional<::mlir::ArrayAttr> constParams = {});
92 inline StructType getType(::std::optional<::mlir::ArrayAttr> constParams = {}) const {
93 return const_cast<StructDefOp*>(this)->getType(constParams);
94 }
95
96 /// Gets the FieldDefOp that defines the field in this
97 /// structure with the given name, if present.
98 FieldDefOp getFieldDef(::mlir::StringAttr fieldName);
99
100 /// Get all FieldDefOp in this structure.
101 ::std::vector<FieldDefOp> getFieldDefs();
102
103 /// Returns wether the struct defines fields marked as columns.
104 ::mlir::LogicalResult hasColumns() {
105 return ::mlir::success(::llvm::any_of(getFieldDefs(), [](FieldDefOp fdOp) {
106 return fdOp.getColumn();
107 }));
108 }
109
110 /// Gets the FuncDefOp that defines the compute function in this structure, if present, or `nullptr` otherwise.
111 ::llzk::function::FuncDefOp getComputeFuncOp();
112
113 /// Gets the FuncDefOp that defines the constrain function in this structure, if present, or `nullptr` otherwise.
114 ::llzk::function::FuncDefOp getConstrainFuncOp();
115
116 /// Gets the FuncDefOp that defines the compute function in this structure, if present, or the product function otherwise.
117 ::llzk::function::FuncDefOp getComputeOrProductFuncOp();
118
119 /// Gets the FuncDefOp that defines the constrain function in this structure, if present, or the product function otherwise.
120 ::llzk::function::FuncDefOp getConstrainOrProductFuncOp();
121
122 /// Returns `true` iff this structure defines compute and constrain functions.
123 bool hasComputeConstrain() { return lookupSymbol(FUNC_NAME_COMPUTE) != nullptr && lookupSymbol(FUNC_NAME_CONSTRAIN) != nullptr; }
124
125 /// Generate header string, in the same format as the assemblyFormat
126 ::std::string getHeaderString();
127
128 /// Return `false` iff `getConstParamsAttr()` returns `nullptr`
129 bool hasConstParamsAttr() { return getProperties().const_params != nullptr; };
130
131 /// Return `true` iff this StructDefOp has a parameter with the given name
132 bool hasParamNamed(::mlir::StringAttr find);
133 inline bool hasParamNamed(::mlir::FlatSymbolRefAttr find) {
134 return hasParamNamed(find.getRootReference());
135 }
136
137 //===------------------------------------------------------------------===//
138 // Utility Methods
139 //===------------------------------------------------------------------===//
140
141 /// Return the full name for this struct from the root module, including
142 /// any surrounding module scopes.
143 ::mlir::SymbolRefAttr getFullyQualifiedName();
144
145 /// Return `true` iff this StructDefOp is named "Main".
146 bool isMainComponent();
147 }];
148
149 let hasRegionVerifier = 1;
150}
151
152def LLZK_FieldDefOp
153 : StructDialectOp<
154 "field", [HasParent<"::llzk::component::StructDefOp">,
155 DeclareOpInterfaceMethods<SymbolUserOpInterface>, Symbol]> {
156 let summary = "struct field definition";
157 let description = [{
158 This operation describes a field in a struct/component.
159
160 Example:
161
162 ```llzk
163 struct.field @f1 : !felt.type
164 struct.field @f2 : !felt.type {llzk.pub}
165 ```
166 }];
167
168 let arguments = (ins SymbolNameAttr:$sym_name, TypeAttrOf<AnyLLZKType>:$type,
169 UnitAttr:$column);
170
171 // Define builders manually to avoid the default ones that have extra
172 // TypeRange parameters that must always be empty.
173 let skipDefaultBuilders = 1;
174 let builders =
175 [OpBuilder<(ins "::mlir::StringAttr":$sym_name, "::mlir::TypeAttr":$type,
176 CArg<"bool", "false">:$isColumn)>,
177 OpBuilder<(ins "::llvm::StringRef":$sym_name, "::mlir::Type":$type,
178 CArg<"bool", "false">:$isColumn)>,
179 OpBuilder<(ins "::mlir::TypeRange":$resultTypes,
180 "::mlir::ValueRange":$operands,
181 "::llvm::ArrayRef<::mlir::NamedAttribute>":$attributes,
182 CArg<"bool", "false">:$isColumn)>,
183 // Simpler version since 'resultTypes' and 'operands' must be empty
184 OpBuilder<
185 (ins "::llvm::ArrayRef<::mlir::NamedAttribute>":$attributes,
186 CArg<"bool", "false">:$isColumn),
187 [{ build($_builder, $_state, {}, {}, attributes, isColumn); }]>];
188
189 let assemblyFormat = [{ $sym_name `:` $type attr-dict }];
190
191 let extraClassDeclaration = [{
192 inline bool hasPublicAttr() { return getOperation()->hasAttr(llzk::PublicAttr::name); }
193 void setPublicAttr(bool newValue = true);
194 }];
195}
196
197class FieldRefOpBase<string mnemonic, list<Trait> traits = []>
198 : StructDialectOp<
199 mnemonic, traits#[DeclareOpInterfaceMethods<FieldRefOpInterface>,
200 DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
201 bit isRead = ?; // read(1) vs write(0) ops
202 let extraClassDeclaration = [{
203 /// Gets the definition for the `field` referenced in this op.
204 inline ::mlir::FailureOr<SymbolLookupResult<FieldDefOp>> getFieldDefOp(::mlir::SymbolTableCollection &tables) {
205 return ::llvm::cast<FieldRefOpInterface>(getOperation()).getFieldDefOp(tables);
206 }
207 }];
208 let extraClassDefinition = [{
209 /// Return `true` if the op is a read, `false` if it's a write.
210 bool $cppClass::isRead() {
211 return }]#!if(isRead, "true", "false")#[{;
212 }
213 }];
214}
215
216def LLZK_FieldReadOp
217 : FieldRefOpBase<"readf", [VerifySizesForMultiAffineOps<1>]> {
218 let summary = "read value of a struct field";
219 let description = [{
220 This operation reads the value of a named field in a struct/component.
221
222 The value can be read from the signals table, in which case it can be
223 offset by a constant value. A negative value represents reading a value
224 backwards and a positive value represents reading a value forward.
225 Only fields marked as columns can be read in this manner.
226 }];
227 let isRead = 1;
228
229 // See `VerifySizesForMultiAffineOps` for more explanation of these arguments.
230 let arguments = (ins LLZK_StructType:$component,
231 FlatSymbolRefAttr:$field_name,
232 OptionalAttr<AnyAttrOf<[SymbolRefAttr, IndexAttr,
233 AffineMapAttr]>>:$tableOffset,
234 // List of AffineMap operand groups where each group provides the
235 // arguments to instantiate the next (left-to-right) AffineMap used in
236 // `tableOffset`.
237 VariadicOfVariadic<Index, "mapOpGroupSizes">:$mapOperands,
238 // Within each group in '$mapOperands', denotes the number of values that
239 // are AffineMap "dimensional" arguments with the remaining values being
240 // AffineMap "symbolic" arguments.
241 DefaultValuedAttr<DenseI32ArrayAttr, "{}">:$numDimsPerMap,
242 // Denotes the size of each variadic group in '$mapOperands'.
243 DenseI32ArrayAttr:$mapOpGroupSizes);
244 let results = (outs AnyLLZKType:$val);
245
246 // Define builders manually so inference of operand layout attributes is not
247 // circumvented.
248 let skipDefaultBuilders = 1;
249 let builders =
250 [OpBuilder<(ins "::mlir::Type":$resultType, "::mlir::Value":$component,
251 "::mlir::StringAttr":$field)>,
252 OpBuilder<(ins "::mlir::Type":$resultType, "::mlir::Value":$component,
253 "::mlir::StringAttr":$field, "::mlir::Attribute":$dist,
254 "::mlir::ValueRange":$mapOperands,
255 "std::optional<int32_t>":$numDims)>,
256 OpBuilder<(ins "::mlir::Type":$resultType, "::mlir::Value":$component,
257 "::mlir::StringAttr":$field,
258 "::mlir::SymbolRefAttr":$dist),
259 [{
260 build($_builder, $_state, resultType, component, field, dist, ::mlir::ValueRange(), std::nullopt);
261 }]>,
262 OpBuilder<(ins "::mlir::Type":$resultType, "::mlir::Value":$component,
263 "::mlir::StringAttr":$field, "::mlir::IntegerAttr":$dist),
264 [{
265 build($_builder, $_state, resultType, component, field, dist, ::mlir::ValueRange(), std::nullopt);
266 }]>,
267 OpBuilder<(ins "::mlir::TypeRange":$resultTypes,
268 "::mlir::ValueRange":$operands,
269 "::mlir::ArrayRef<::mlir::NamedAttribute>":$attrs)>];
270
271 let assemblyFormat = [{
272 $component `[` $field_name `]`
273 ( `{` custom<MultiDimAndSymbolList>($mapOperands, $numDimsPerMap)^ `}` )?
274 `:` type($component) `,` type($val)
275 attr-dict
276 }];
277
278 let hasVerifier = 1;
279}
280
281def LLZK_FieldWriteOp : FieldRefOpBase<"writef", [WitnessGen]> {
282 let summary = "write value to a struct field";
283 let description = [{
284 This operation writes a value to a named field in a struct/component.
285 }];
286 let isRead = 0;
287
288 let arguments = (ins LLZK_StructType:$component,
289 FlatSymbolRefAttr:$field_name, AnyLLZKType:$val);
290
291 let assemblyFormat = [{
292 $component `[` $field_name `]` `=` $val `:` type($component) `,` type($val) attr-dict
293 }];
294}
295
296def LLZK_CreateStructOp
297 : StructDialectOp<"new", [DeclareOpInterfaceMethods<
298 OpAsmOpInterface, ["getAsmResultNames"]>,
299 DeclareOpInterfaceMethods<SymbolUserOpInterface>,
300 WitnessGen,
301]> {
302 let summary = "create a new struct";
303 let description = [{
304 This operation creates a new, uninitialized instance of a struct.
305
306 Example:
307
308 ```llzk
309 %self = struct.new : !struct.type<@Reg>
310 ```
311 }];
312
313 let results = (outs LLZK_StructType:$result);
314
315 let assemblyFormat = [{ `:` type($result) attr-dict }];
316}
317
318#endif // LLZK_STRUCT_OPS