LLZK 3.0.0
An open-source IR for Zero Knowledge (ZK) circuits
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_FUNC_OPS
16#define LLZK_FUNC_OPS
17
18include "llzk/Dialect/Function/IR/Dialect.td"
19include "llzk/Dialect/Verif/IR/OpInterfaces.td"
20include "llzk/Dialect/Shared/OpTraits.td"
21include "llzk/Dialect/Shared/Types.td"
22
23include "mlir/IR/OpAsmInterface.td"
24include "mlir/IR/SymbolInterfaces.td"
25include "mlir/Interfaces/CallInterfaces.td"
26include "mlir/Interfaces/ControlFlowInterfaces.td"
27include "mlir/Interfaces/FunctionInterfaces.td"
28include "mlir/Interfaces/InferTypeOpInterface.td"
29include "mlir/Interfaces/SideEffectInterfaces.td"
30
31class FunctionDialectOp<string mnemonic, list<Trait> traits = []>
32 : Op<FunctionDialect, mnemonic, traits>;
33
34//===----------------------------------------------------------------------===//
35// FuncDefOp
36//===----------------------------------------------------------------------===//
37
38def FuncDefOp
39 : FunctionDialectOp<
40 "def", [ParentOneOf<["::mlir::ModuleOp",
41 "::llzk::component::StructDefOp",
42 "::llzk::polymorphic::TemplateOp"]>,
43 DeclareOpInterfaceMethods<SymbolUserOpInterface>, AffineScope,
44 AutomaticAllocationScope, FunctionOpInterface,
45 IsolatedFromAbove, ContractTarget]> {
46 // NOTE: Cannot have SymbolTable trait because that would cause global
47 // functions without a body to produce "Operations with a 'SymbolTable' must
48 // have exactly one block"
49 let summary = "An operation with a name containing a single `SSACFG` region";
50 let description = [{
51 Operations within the function cannot implicitly capture values defined
52 outside of the function, i.e., functions are `IsolatedFromAbove`. All
53 external references must use function arguments (which are passed by value)
54 or reference external members or globals by symbol name.
55
56 Functions appearing within a `struct.def` have specific semantics and must
57 be named `compute`, `constrain`, or `product`. Functions appearing at the
58 module level (i.e. not within a `struct.def`) have no name restrictions and
59 their body may be elided to denote an external function declaration.
60
61 Modules and `struct.def` ops are not allowed to be nested within functions.
62
63 Function arguments may carry an optional `function.arg_name` attribute to
64 preserve the source-level argument name independently from the printed SSA
65 block argument name. The value must be a non-empty, untyped `StringAttr`,
66 and all attached `function.arg_name` values must be unique within the
67 function. Typed string attributes such as `"x" : i1` are rejected. The
68 attribute is only valid on function arguments.
69 Argument-splitting transforms preserve this metadata by deriving unique
70 names for generated arguments, such as `input[0]` for array elements or
71 `self.member` for struct members.
72
73 Function results may similarly carry an optional `function.res_name`
74 attribute. The value must be a non-empty, untyped `StringAttr`, all attached
75 result names must be unique within the function, and the attribute is only
76 valid on function results.
77
78 Example:
79
80 ```llzk
81 // External function definitions.
82 function.def private @abort()
83 function.def private @scribble(
84 !array.type<5 x !felt.type> {function.arg_name = "input"},
85 !struct.type<@Hello> {function.arg_name = "state"}) -> i1
86
87 // A function that returns its argument twice:
88 function.def @count(%x: !felt.type {function.arg_name = "x"})
89 -> (!felt.type {function.res_name = "first"},
90 !felt.type {function.res_name = "second"}) {
91 function.return %x, %x: !felt.type, !felt.type
92 }
93
94 // Function definition within a component
95 struct.def @NonZero {
96 function.def @compute(%a: !felt.type {function.arg_name = "a"}) { function.return }
97 function.def @constrain(%a: !felt.type {function.arg_name = "a"}) { function.return }
98 }
99 ```
100 }];
101
102 // Duplicated from the pre-defined `func` dialect. We don't store the
103 // visibility attribute but, since we use `function_interface_impl` for
104 // parsing/printing, there is still the requirement that global functions
105 // declared without a body must specify the `private` visibility.
106 // Additionally, the default parsing/printing functions allow attributes on
107 // the arguments, results, and function itself.
108 // ```llzk
109 // // Argument attribute
110 // function.def private @example_fn_arg(%x: i1 {llzk.pub})
111 // function.def private @example_fn_arg_name(%x: i1 {function.arg_name =
112 // "x"})
113 //
114 // // Result attribute
115 // function.def @example_fn_result() -> (i1 {dialectName.attrName = 0 :
116 // i1})
117 //
118 // // Function attribute
119 // function.def @example_fn_attr() attributes {dialectName.attrName =
120 // false}
121 // ```
122 let arguments = (ins SymbolNameAttr:$sym_name,
123 TypeAttrOf<FunctionType>:$function_type,
124 OptionalAttr<DictArrayAttr>:$arg_attrs,
125 OptionalAttr<DictArrayAttr>:$res_attrs);
126 let regions = (region AnyRegion:$body);
127
128 let builders = [OpBuilder<(ins "::llvm::StringRef":$name,
129 "::mlir::FunctionType":$type,
130 CArg<"::llvm::ArrayRef<::mlir::NamedAttribute>", "{}">:$attrs,
131 CArg<"::llvm::ArrayRef<::mlir::DictionaryAttr>", "{}">:$argAttrs)>];
132
133 let extraClassDeclaration = [{
134 static FuncDefOp create(::mlir::Location location, ::llvm::StringRef name, ::mlir::FunctionType type,
135 ::llvm::ArrayRef<::mlir::NamedAttribute> attrs = {});
136 static FuncDefOp create(::mlir::Location location, ::llvm::StringRef name, ::mlir::FunctionType type,
137 ::mlir::Operation::dialect_attr_range attrs);
138 static FuncDefOp create(::mlir::Location location, ::llvm::StringRef name, ::mlir::FunctionType type,
139 ::llvm::ArrayRef<::mlir::NamedAttribute> attrs,
140 ::llvm::ArrayRef<::mlir::DictionaryAttr> argAttrs);
141
142 /// Create a deep copy of this function and all of its blocks, remapping any
143 /// operands that use values outside of the function using the map that is
144 /// provided (leaving them alone if no entry is present). If the mapper
145 /// contains entries for function arguments, these arguments are not
146 /// included in the new function. Replaces references to cloned sub-values
147 /// with the corresponding value that is copied, and adds those mappings to
148 /// the mapper.
149 FuncDefOp clone(::mlir::IRMapping &mapper);
150 FuncDefOp clone();
151
152 /// Clone the internal blocks and attributes from this function into dest.
153 /// Any cloned blocks are appended to the back of dest. This function
154 /// asserts that the attributes of the current function and dest are
155 /// compatible.
156 void cloneInto(FuncDefOp dest, ::mlir::IRMapping &mapper);
157
158 /// Return `true` iff the function def has the `allow_constraint` attribute.
159 inline bool hasAllowConstraintAttr() {
160 return getOperation()->hasAttr(llzk::function::AllowConstraintAttr::name);
161 }
162
163 /// Add (resp. remove) the `allow_constraint` attribute to (resp. from) the function def.
164 void setAllowConstraintAttr(bool newValue = true);
165
166 /// Return `true` iff the function def has the `allow_witness` attribute.
167 inline bool hasAllowWitnessAttr() {
168 return getOperation()->hasAttr(llzk::function::AllowWitnessAttr::name);
169 }
170
171 /// Add (resp. remove) the `allow_witness` attribute to (resp. from) the function def.
172 void setAllowWitnessAttr(bool newValue = true);
173
174 /// Return `true` iff the function def has the `allow_non_native_field_ops` attribute.
175 inline bool hasAllowNonNativeFieldOpsAttr() {
176 return getOperation()->hasAttr(llzk::function::AllowNonNativeFieldOpsAttr::name);
177 }
178
179 /// Add (resp. remove) the `allow_non_native_field_ops` attribute to (resp. from) the function def.
180 void setAllowNonNativeFieldOpsAttr(bool newValue = true);
181
182 /// Return `true` iff the function def has the `allow_verif_ops` attribute.
183 inline bool hasAllowVerifOpsAttr() {
184 return getOperation()->hasAttr(llzk::function::AllowVerifOpsAttr::name);
185 }
186
187 /// Add (resp. remove) the `allow_verif_ops` attribute to (resp. from) the function def.
188 void setAllowVerifOpsAttr(bool newValue = true);
189
190 /// Return `true` iff the argument at the given index has `pub` attribute.
191 bool hasArgPublicAttr(unsigned index);
192
193 /// Return `true` iff the argument at the given index has a `function.arg_name` attribute.
194 bool hasArgName(unsigned index);
195
196 /// Return the `function.arg_name` attribute for the argument at the given index.
197 ::std::optional<::mlir::StringAttr> getArgNameAttr(unsigned index);
198
199 /// Set the `function.arg_name` attribute for the argument at the given index.
200 void setArgNameAttr(unsigned index, const ::mlir::StringAttr &attr);
201
202 /// Set the `function.arg_name` attribute for the argument at the given index from a string.
203 void setArgName(unsigned index, ::llvm::StringRef name);
204
205 /// Return `true` iff the result at the given index has a `function.res_name` attribute.
206 bool hasResName(unsigned index);
207
208 /// Return the `function.res_name` attribute for the result at the given index.
209 ::std::optional<::mlir::StringAttr> getResNameAttr(unsigned index);
210
211 /// Set the `function.res_name` attribute for the result at the given index.
212 void setResNameAttr(unsigned index, const ::mlir::StringAttr &attr);
213
214 /// Set the `function.res_name` attribute for the result at the given index from a string.
215 void setResName(unsigned index, ::llvm::StringRef name);
216
217 /// Required by FunctionOpInterface.
218 /// Returns the region on the current operation that is callable. This may
219 /// return null in the case of an external callable object, e.g. an external
220 /// function.
221 ::mlir::Region *getCallableRegion() { return isExternal() ? nullptr : &getBody(); }
222
223 /// Required by FunctionOpInterface.
224 /// Returns the argument types of this function.
225 ::llvm::ArrayRef<::mlir::Type> getArgumentTypes() { return getFunctionType().getInputs(); }
226
227 /// Required by FunctionOpInterface.
228 /// Returns the result types of this function.
229 ::llvm::ArrayRef<::mlir::Type> getResultTypes() { return getFunctionType().getResults(); }
230
231 /// Required by SymbolOpInterface.
232 bool isDeclaration() { return isExternal(); }
233
234 /// Return the full name for this function from the root module, including
235 /// all surrounding symbol table names (i.e., modules and structs).
236 ::mlir::SymbolRefAttr getFullyQualifiedName(bool requireParent = true);
237
238 /// Return `true` iff the function name is `FUNC_NAME_COMPUTE` (if needed, a check
239 /// that this FuncDefOp is located within a StructDefOp must be done separately).
240 inline bool nameIsCompute() { return FUNC_NAME_COMPUTE == getSymName(); }
241
242 /// Return `true` iff the function name is `FUNC_NAME_CONSTRAIN` (if needed, a
243 /// check that this FuncDefOp is located within a StructDefOp must be done separately).
244 inline bool nameIsConstrain() { return FUNC_NAME_CONSTRAIN == getSymName(); }
245
246 /// Return `true` iff the function name is `FUNC_NAME_PRODUCT` (if needed, a
247 /// check that this FuncDefOp is located within a StructDefOp must be done separately).
248 inline bool nameIsProduct() { return FUNC_NAME_PRODUCT == getSymName(); }
249
250 /// Return `true` iff the function is within a StructDefOp
251 inline bool isInStruct() { return ::llzk::component::isInStruct(*this); }
252
253 /// Return `true` iff the function is within a StructDefOp and named `FUNC_NAME_COMPUTE`.
254 inline bool isStructCompute() { return isInStruct() && nameIsCompute(); }
255
256 /// Return `true` iff the function is within a StructDefOp and named `FUNC_NAME_CONSTRAIN`.
257 inline bool isStructConstrain() { return isInStruct() && nameIsConstrain(); }
258
259 /// Return `true` iff the function is within a StructDefOp and named `FUNC_NAME_PRODUCT`.
260 inline bool isStructProduct() { return isInStruct() && nameIsProduct(); }
261
262 /// Return the "self" value (i.e. the return value) from the function (which must be
263 /// named `FUNC_NAME_COMPUTE`).
264 ::mlir::Value getSelfValueFromCompute();
265
266 /// Return the "self" value (i.e. the first parameter) from the function (which must be
267 /// named `FUNC_NAME_CONSTRAIN`).
268 ::mlir::Value getSelfValueFromConstrain();
269
270 /// Assuming the name is `FUNC_NAME_COMPUTE`, return the single StructType result.
271 ::llzk::component::StructType getSingleResultTypeOfCompute();
272 }];
273
274 let hasCustomAssemblyFormat = 1;
275 let hasVerifier = 1;
276}
277
278//===----------------------------------------------------------------------===//
279// ReturnOp
280//===----------------------------------------------------------------------===//
281
282def ReturnOp
283 : FunctionDialectOp<"return", [HasParent<"::llzk::function::FuncDefOp">,
284 Pure, MemRefsNormalizable, ReturnLike,
285 Terminator]> {
286 let summary = "Function return operation";
287 let description = [{
288 The `function.return` operation represents a return operation within a function.
289 The operation takes variable number of operands and produces no results.
290 The operand number and types must match the signature of the function
291 that contains the operation.
292
293 Example:
294
295 ```llzk
296 function.def @foo() : (!felt.type, index) {
297 ...
298 return %0, %1 : !felt.type, index
299 }
300 ```
301 }];
302
303 let arguments = (ins Variadic<AnyLLZKType>:$operands);
304
305 let builders = [OpBuilder<(ins), [{
306 build($_builder, $_state, std::nullopt);
307 }]>];
308
309 let assemblyFormat = "attr-dict ($operands^ `:` type($operands))?";
310 let hasVerifier = 1;
311}
312
313//===----------------------------------------------------------------------===//
314// CallOp
315//===----------------------------------------------------------------------===//
316
317def CallOp : FunctionDialectOp<
318 "call", [MemRefsNormalizable, AttrSizedOperandSegments,
319 VerifySizesForMultiAffineOps<1>,
320 DeclareOpInterfaceMethods<CallOpInterface>,
321 DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
322 let summary = "call operation";
323 let description = [{
324 The `function.call` operation represents a call to another function. The operands
325 and result types of the call must match the specified function type. The
326 callee is encoded as a symbol reference attribute named "callee" which must
327 be the full path to the target function from the root module (i.e., the module
328 containing the [llzk::LANG_ATTR_NAME] attribute).
329
330 Example:
331 ```llzk
332 // Call a global function defined in the root module.
333 function.call @do_stuff(%0) : (!struct.type<@Bob>) -> ()
334 %1, %2 = function.call @split(%x) : (index) -> (index, index)
335
336 // Call a function within a component
337 %2 = function.call @OtherStruct::@compute(%3, %4) : (index, index) -> !struct.type<@OtherStruct>
338 function.call @OtherStruct::@constrain(%5, %6) : (!struct.type<@OtherStruct>, !felt.type) -> ()
339 ```
340
341 When the return StructType of a `compute()` function uses AffineMapAttr to
342 express struct parameter(s) that depend on a loop variable, the optional
343 instantiation parameter list of this operation must be used to instatiate
344 all AffineMap used as parameters to the StructType.
345
346 Examples:
347 ```llzk
348 #M = affine_map<(i)[] -> (5*i+1)>
349 %r = function.call @A::@compute(%x){(%i)} : (!felt.type) -> !struct.type<@A<[#M]>>
350 ```
351
352 When the call targets a free function within a `poly.template` region, the optional
353 template parameter list can be used to instantiate all `poly.param` symbols within
354 the template. If all `poly.param` symbols are used within the function signature,
355 this can be elided. Otherwise, it is required to instantiate the function. The `?`
356 wildcard can be used for any `poly.param` with a `poly.tvar` type restriction, even
357 those that cannot be inferred from the function signature. The wildcard allows for
358 inference of the type within the function body itself during the flattening pass
359 but may fail if the type cannot be inferred from the function body.
360 }];
361
362 // See `VerifySizesForMultiAffineOps` for more explanation of these arguments.
363 let arguments = (ins
364 // Call target function reference.
365 SymbolRefAttr:$callee,
366 // List of arguments to call the target function.
367 Variadic<AnyLLZKType>:$argOperands,
368 // List of parameters to instantiate all `poly.param` symbols when the
369 // callee is a free function inside a `poly.template` region.
370 OptionalAttr<ArrayAttr>:$templateParams,
371 // List of AffineMap operand groups where each group provides the
372 // arguments to instantiate the next (left-to-right) AffineMap used as a
373 // struct parameter in the result StructType.
374 VariadicOfVariadic<Index, "mapOpGroupSizes">:$mapOperands,
375 // Within each group in '$mapOperands', denotes the number of values that
376 // are AffineMap "dimensional" arguments with the remaining values being
377 // AffineMap "symbolic" arguments.
378 DefaultValuedAttr<DenseI32ArrayAttr, "{}">:$numDimsPerMap,
379 // Denotes the size of each variadic group in '$mapOperands'.
380 DenseI32ArrayAttr:$mapOpGroupSizes);
381 let results = (outs Variadic<AnyLLZKType>);
382
383 let assemblyFormat = [{
384 $callee
385 ( `<` custom<TemplateParams>($templateParams)^ `>` )?
386 `` `(` $argOperands `)`
387 ( `{` custom<MultiDimAndSymbolList>($mapOperands, $numDimsPerMap)^ `}` )?
388 `:` functional-type($argOperands, results)
389 custom<AttrDictWithWarnings>(attr-dict, prop-dict)
390 }];
391
392 let useCustomPropertiesEncoding = 1;
393
394 // NOTE: In CreateArrayOp, the `verify()` function is declared in order to
395 // call `verifyAffineMapInstantiations()`. However, in this op that check must
396 // happen within `verifySymbolUses()` instead because the target FuncDefOp
397 // must be resolved to determine if a target function named
398 // "compute"/"constrain" is defined within a StructDefOp or within a ModuleOp
399 // because the verification differs for those cases.
400
401 // Define builders manually so inference of operand layout attributes is not
402 // circumvented.
403 let skipDefaultBuilders = 1;
404 let builders =
405 [OpBuilder<(ins "::mlir::TypeRange":$resultTypes,
406 "::mlir::SymbolRefAttr":$callee,
407 CArg<"::mlir::ValueRange", "{}">:$argOperands,
408 CArg<"::llvm::ArrayRef<::mlir::Attribute>", "{}">:$templateParams)>,
409 OpBuilder<(ins "::mlir::TypeRange":$resultTypes,
410 "::mlir::SymbolRefAttr":$callee,
411 "::llvm::ArrayRef<::mlir::ValueRange>":$mapOperands,
412 "::mlir::DenseI32ArrayAttr":$numDimsPerMap,
413 CArg<"::mlir::ValueRange", "{}">:$argOperands,
414 CArg<"::llvm::ArrayRef<::mlir::Attribute>", "{}">:$templateParams)>,
415 OpBuilder<(ins "::mlir::TypeRange":$resultTypes,
416 "::mlir::SymbolRefAttr":$callee,
417 "::llvm::ArrayRef<::mlir::ValueRange>":$mapOperands,
418 "::llvm::ArrayRef<int32_t>":$numDimsPerMap,
419 CArg<"::mlir::ValueRange", "{}">:$argOperands,
420 CArg<"::llvm::ArrayRef<::mlir::Attribute>",
421 "{}">:$templateParams),
422 [{
423 build($_builder, $_state, resultTypes, callee, mapOperands,
424 $_builder.getDenseI32ArrayAttr(numDimsPerMap),
425 argOperands, templateParams);
426 }]>,
427 OpBuilder<(ins "::llzk::function::FuncDefOp":$callee,
428 CArg<"::mlir::ValueRange", "{}">:$argOperands,
429 CArg<"::llvm::ArrayRef<::mlir::Attribute>",
430 "{}">:$templateParams),
431 [{
432 build($_builder, $_state, callee.getResultTypes(),
433 callee.getFullyQualifiedName(false),
434 argOperands, templateParams);
435 }]>,
436 OpBuilder<(ins "::llzk::function::FuncDefOp":$callee,
437 "::llvm::ArrayRef<::mlir::ValueRange>":$mapOperands,
438 "::mlir::DenseI32ArrayAttr":$numDimsPerMap,
439 CArg<"::mlir::ValueRange", "{}">:$argOperands,
440 CArg<"::llvm::ArrayRef<::mlir::Attribute>",
441 "{}">:$templateParams),
442 [{
443 build($_builder, $_state, callee.getResultTypes(),
444 callee.getFullyQualifiedName(false), mapOperands, numDimsPerMap,
445 argOperands, templateParams);
446 }]>,
447 OpBuilder<(ins "::llzk::function::FuncDefOp":$callee,
448 "::llvm::ArrayRef<::mlir::ValueRange>":$mapOperands,
449 "::llvm::ArrayRef<int32_t>":$numDimsPerMap,
450 CArg<"::mlir::ValueRange", "{}">:$argOperands,
451 CArg<"::llvm::ArrayRef<::mlir::Attribute>",
452 "{}">:$templateParams),
453 [{
454 build($_builder, $_state, callee, mapOperands,
455 $_builder.getDenseI32ArrayAttr(numDimsPerMap),
456 argOperands, templateParams);
457 }]>];
458
459 let extraClassDeclaration = [{
460 /// Required by CallOpInterface
461 ::mlir::Operation *resolveCallableInTable(::mlir::SymbolTableCollection *symbolTable);
462
463 /// Required by CallOpInterface
464 ::mlir::Operation *resolveCallable();
465
466 /// Return the FunctionType inferred from the arg operands and result types of this CallOp.
467 /// This is not necessarily the same as the callee's FunctionType but should unify with it
468 /// or else IR verification will fail.
469 ::mlir::FunctionType getTypeSignature();
470
471 /// Attempt type unfication between the inferred FunctionType from this CallOp (as LHS) and
472 /// the given FunctionType (as RHS). If successful, return a UnificationMap containing the
473 /// unifications that were made. Otherwise, return failure.
474 ::mlir::FailureOr<UnificationMap> unifyTypeSignature(::mlir::FunctionType other);
475
476 /// Return `true` iff the callee function name is `FUNC_NAME_COMPUTE` (this
477 /// does not check if the callee function is located within a StructDefOp).
478 inline bool calleeIsCompute() {
479 return FUNC_NAME_COMPUTE == getCallee().getLeafReference();
480 }
481
482 /// Return `true` iff the callee function name is `FUNC_NAME_PRODUCT` (this
483 /// does not check if the callee function is located within a StructDefOp).
484 inline bool calleeIsProduct() {
485 return FUNC_NAME_PRODUCT == getCallee().getLeafReference();
486 }
487
488 /// Return `true` iff the callee function can contain witness generation code
489 /// (this does not check if the callee function is located within a StructDefOp)
490 inline bool calleeContainsWitnessGen() {
491 return calleeIsCompute() || calleeIsProduct();
492 }
493
494 /// Return `true` iff the callee function name is `FUNC_NAME_CONSTRAIN` (this
495 /// does not check if the callee function is located within a StructDefOp).
496 inline bool calleeIsConstrain() { return FUNC_NAME_CONSTRAIN == getCallee().getLeafReference(); }
497
498 /// Return `true` iff the callee function name is `FUNC_NAME_COMPUTE` within a StructDefOp.
499 bool calleeIsStructCompute();
500
501 /// Return `true` iff the callee function name is `FUNC_NAME_PRODUCT` within a StructDefOp.
502 bool calleeIsStructProduct();
503
504 /// Return `true` iff the callee function name is `FUNC_NAME_CONSTRAIN` within a StructDefOp.
505 bool calleeIsStructConstrain();
506
507 /// Return `true` iff the callee function is within a StructDefOp.
508 inline bool calleeIsInStruct() {
509 return calleeIsStructCompute() || calleeIsStructConstrain() || calleeIsStructProduct();
510 }
511
512 /// Return the "self" value (i.e. the return value) from the callee function (which must be
513 /// named `FUNC_NAME_COMPUTE`).
514 ::mlir::Value getSelfValueFromCompute();
515
516 /// Return the "self" value (i.e. the first parameter) from the callee function (which must be
517 /// named `FUNC_NAME_CONSTRAIN`).
518 ::mlir::Value getSelfValueFromConstrain();
519
520 /// Resolve and return the target FuncDefOp for this CallOp.
521 ::mlir::FailureOr<::llzk::SymbolLookupResult<::llzk::function::FuncDefOp>>
522 getCalleeTarget(::mlir::SymbolTableCollection &tables);
523
524 /// Assuming the callee is `FUNC_NAME_COMPUTE`, return the single StructType result.
525 ::llzk::component::StructType getSingleResultTypeOfCompute();
526
527 /// Assuming the callee contains witness generation code, return the single StructType result.
528 ::llzk::component::StructType getSingleResultTypeOfWitnessGen();
529
530 /// Allocate consecutive storage of the ValueRange instances in the parameter
531 /// so it can be passed to the builders as an `ArrayRef<ValueRange>`.
532 static ::llvm::SmallVector<::mlir::ValueRange> toVectorOfValueRange(::mlir::OperandRangeRange);
533
534 /// Check type compatibility of the given template parameter value from this `CallOp` against
535 /// the declared type on the given `TemplateParamOp` (if any).
536 ::mlir::LogicalResult verifyTemplateParamCompatibility(
537 ::mlir::Attribute paramFromCallOp, ::llzk::polymorphic::TemplateParamOp targetParam
538 );
539
540 /// Check type compatibility of each template parameter value provided in this `CallOp` against
541 /// the declared type on each `TemplateParamOp` (if any).
542 ///
543 /// Pre-condition assertions:
544 /// - `!isNullOrEmpty(getTemplateParamsAttr())`
545 /// - `getTemplateParamsAttr().size() == llvm::range_size(targetParamDefs)`
546 ::mlir::LogicalResult verifyTemplateParamCompatibility(
547 ::llvm::iterator_range<::mlir::Region::op_iterator<::llzk::polymorphic::TemplateParamOp>> targetParamDefs
548 );
549
550 /// Verify that each template parameter value provided in this `CallOp` is consistent with
551 /// the value inferred for the target `TemplateParamOp` in the given `UnificationMap`. The
552 /// `UnificationMap` is expected to contain the unification results of this `CallOp` against
553 /// the target function type signature.
554 ///
555 /// Pre-condition assertions:
556 /// - `!isNullOrEmpty(getTemplateParamsAttr())`
557 /// - `getTemplateParamsAttr().size() == llvm::range_size(targetParamDefs)`
558 ::mlir::LogicalResult verifyTemplateParamsMatchInferred(
559 ::llvm::iterator_range<::mlir::Region::op_iterator<::llzk::polymorphic::TemplateParamOp>> targetParamDefs,
560 const UnificationMap &unifications
561 );
562 }];
563}
564
565#endif // LLZK_FUNC_OPS