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