1//===-- Ops.td ---------------------------------------------*- tablegen -*-===//
3// Part of the LLZK Project, under the Apache License v2.0.
4// See LICENSE.txt for license information.
5// Copyright 2026 Project LLZK
6// SPDX-License-Identifier: Apache-2.0
8//===----------------------------------------------------------------------===//
13include "llzk/Dialect/POD/IR/Dialect.td"
14include "llzk/Dialect/POD/IR/Types.td"
15include "llzk/Dialect/Shared/OpTraits.td"
17include "mlir/IR/OpBase.td"
18include "mlir/IR/OpAsmInterface.td"
19include "mlir/IR/SymbolInterfaces.td"
20include "mlir/Interfaces/SideEffectInterfaces.td"
22class PODDialectOp<string mnemonic, list<Trait> traits = []>
23 : Op<PODDialect, mnemonic, traits>;
26 : PODDialectOp<"new", [Pure, AttrSizedOperandSegments,
27 VerifySizesForMultiAffineOps<1>,
28 DeclareOpInterfaceMethods<
29 OpAsmOpInterface, ["getAsmResultNames"]>]> {
30 let summary = "create a new plain-old-data struct";
32 Creates a new, uninitialized, pod instance. Optionally, the user can pass a list of record names and values
33 that initialize the records of the pod. Partial initialization is allowed. All records without
34 an explicit initialization are initialized with nondeterministic values.
36 If the types of the pod records have affine map parameters the user can pass values for them similar
37 to how `array.new` does it.
39 This operation returns one value of type `PODType` and, if present, the records passed for initialization
40 must form a subset of the records in the type.
45 %0 = pod.new : !pod.type<[]>
47 // Uninitialized/nondeterministic pod instance
48 %0 = pod.new : !pod.type<[@n: !felt.type]>
50 // Initialized pod instance
51 %0 = felt.const_felt 1
52 %1 = pod.new { @n = %0 } : !pod.type<[@n: !felt.type]>
54 // Another one, but with 2 fields
55 %0 = felt.const_felt 1
57 %2 = pod.new { @n = %0, @inv = %1 } : !pod.type<[@n: !felt.type, @inv: !felt.type]>
60 %0 = felt.const_felt 1
61 %1 = pod.new { @n = %0 } : !pod.type<[@n: !felt.type, @inv: !felt.type]>
63 // Affine map args on uninitialized pod instance
64 %0 = arith.constant 1 : index
65 %c = arith.constant 2 : index
66 %1 = pod.new(%0)[%c] : !pod.type<[@a: !array.type<#map, !felt.type>]>
68 // Affine map with initialized records
69 %0 = arith.constant 1 : index
70 %c = arith.constant 2 : index
71 %1 = felt.const_felt 5
72 %2 = pod.new { @f = %1 }(%0)[%c] : !pod.type<[@f: !felt.type, @a: !array.type<#map, !felt.type>]>
77 // Initialization values
78 Variadic<AnyLLZKType>:$initialValues,
79 DefaultValuedAttr<StrArrayAttr, "{}">:$initializedRecords,
80 // Affine map arguments
81 VariadicOfVariadic<Index, "mapOpGroupSizes">:$mapOperands,
82 DefaultValuedAttr<DenseI32ArrayAttr, "{}">:$numDimsPerMap,
83 DenseI32ArrayAttr:$mapOpGroupSizes);
84 let results = (outs LLZK_PODType:$result);
85 let skipDefaultBuilders = 1;
88 (ins CArg<"::llzk::pod::InitializedRecords", "{}">:$initialValues),
90 auto resultType = ::llzk::pod::PodType::fromInitialValues($_builder.getContext(), initialValues);
91 build($_builder, $_state, resultType, initialValues);
93 OpBuilder<(ins "::llzk::pod::PodType":$resultType,
94 CArg<"::llzk::pod::InitializedRecords", "{}">:$initialValues)>,
95 OpBuilder<(ins "::llzk::pod::PodType":$resultType,
96 "::llvm::ArrayRef<::mlir::ValueRange>":$mapOperands,
97 "::mlir::DenseI32ArrayAttr":$numDimsPerMap,
98 CArg<"::llzk::pod::InitializedRecords", "{}">:$initialValues)>,
100 (ins "::llzk::pod::PodType":$resultType,
101 "::llvm::ArrayRef<::mlir::ValueRange>":$mapOperands,
102 "::llvm::ArrayRef<int32_t>":$numDimsPerMap,
103 CArg<"::llzk::pod::InitializedRecords", "{}">:$initialValues),
105 build($_builder, $_state, resultType, mapOperands,
106 $_builder.getDenseI32ArrayAttr(numDimsPerMap), initialValues);
108 let hasCustomAssemblyFormat = 1;
111 let extraClassDeclaration = [{
112 ::mlir::SmallVector<::llzk::pod::RecordValue> getInitializedRecordValues();
116def LLZK_ReadPodOp : PODDialectOp<"read"> {
117 let summary = "reads the contents of a plain-old-data struct record";
119 Reads the current value of a named record from a pod instance.
120 Returns one value of the type of the record.
122 The name of the record must be a valid record name for the pod type and the result
123 type must match the type of the record.
127 %1 = pod.read %0[@sym] : !pod.type<[@sym: !type, ...]>, !type
131 let arguments = (ins Arg<LLZK_PODType, "the pod to read from">:$pod_ref,
132 FlatSymbolRefAttr:$record_name);
133 let results = (outs AnyLLZKType:$result);
134 let assemblyFormat = [{
135 $pod_ref `[` custom<RecordName>($record_name) `]` `:` type($pod_ref) `,` type($result) attr-dict
140def LLZK_WritePodOp : PODDialectOp<"write"> {
141 let summary = "writes content into a plain-old-data struct record";
143 Writes a value into a named record of a pod instance. This operation has no result values.
145 The name of the record must be a valid record name for the pod type and the source
146 value type must match the type of the record.
148 Writing a record that was written or initialized earlier overwrites the previous value.
152 pod.write %0[@sym] = %1 : !pod.type<[@sym: !type, ...]>, !type
156 let arguments = (ins Arg<LLZK_PODType, "the pod to write into">:$pod_ref,
157 FlatSymbolRefAttr:$record_name, AnyLLZKType:$value);
159 let assemblyFormat = [{
160 $pod_ref `[` custom<RecordName>($record_name) `]` `=` $value `:` type($pod_ref) `,` type($value) attr-dict
165#endif // LLZK_POD_OPS