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