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 2025 Veridise Inc.
6// SPDX-License-Identifier: Apache-2.0
8//===----------------------------------------------------------------------===//
10#ifndef LLZK_POLYMORPHIC_OPS
11#define LLZK_POLYMORPHIC_OPS
13include "llzk/Dialect/Polymorphic/IR/Dialect.td"
14include "llzk/Dialect/Polymorphic/IR/Types.td"
16include "mlir/IR/OpBase.td"
17include "mlir/IR/SymbolInterfaces.td"
18include "mlir/Interfaces/SideEffectInterfaces.td"
20class PolymorphicDialectOp<string mnemonic, list<Trait> traits = []>
21 : Op<PolymorphicDialect, mnemonic, traits>;
24 : PolymorphicDialectOp<
25 "read_const", [DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
26 let summary = "read value of a struct parameter";
28 This operation reads the value from the named constant parameter of
29 the struct/component in which this op appears. The op itself puts
30 some restriction on the type of this value, but leaves it to a later
31 type-checking pass to ensure the struct parameters are instantiated
32 with types matching the uses of the parameter within the struct.
35 let arguments = (ins FlatSymbolRefAttr:$const_name);
36 let results = (outs ConstReadType:$val);
38 let assemblyFormat = [{ $const_name `:` type($val) attr-dict }];
41def LLZK_UnifiableCastOp : PolymorphicDialectOp<"unifiable_cast", [Pure]> {
42 let summary = "cast between two unifiable types";
44 This operation reinterprets a value as a different type with the restriction
45 that the input and output types of the cast are unifiable.
47 Most ops that accept LLZK types accept unifiable types as input and thus there
48 is no need for casting between types. This op is meant to be used in situations where
49 is not possible to modify the given or the target type and they are different but unifiable.
50 For example, inside a conversion pattern the driver may introduce `unrealized_conversion_cast`
51 operations if the types are not equal. This will happen regardless of whether the two types unify.
52 This cast can be introduced instead of the default cast operation to satisfy MLIR's assumptions
57 %0 = some_other_op : !array.type<@N x !felt.type>
58 %1 = unifiable_cast %0 : (!array.type<@N x @felt.type>) -> !array.type<affine_map<()[s0, s1] -> (s0 + s1)> x !felt.type>
62 let arguments = (ins AnyLLZKType:$input);
63 let results = (outs AnyLLZKType:$result);
64 let assemblyFormat = [{
65 $input `:` functional-type($input, results) attr-dict
71def LLZK_ApplyMapOp : PolymorphicDialectOp<"applymap", [Pure]> {
72 let summary = "apply an AffineMap";
74 This operation applies an AffineMap to a list of SSA values, yielding a single
75 SSA value. The number of dimension and symbol arguments must be equal to the
76 respective number of dimensional and symbolic inputs to the AffineMap; the
77 AffineMap has to be one-dimensional, and so this operation always returns one
78 value. The input operands and result all have `index` type.
82 #map10 = affine_map<(d0, d1) -> (d0 floordiv 8 + d1 floordiv 128)>
84 %1 = poly.applymap(%s, %t) #map10
89 %2 = poly.applymap(%42)[%n] affine_map<(i)[s0] -> (i+s0)>
93 let arguments = (ins AffineMapAttr:$map, Variadic<Index>:$mapOperands,
95 let results = (outs Index);
97 // Define builders manually so inference of `numDims` attribute is not
99 let skipDefaultBuilders = 1;
100 let builders = [OpBuilder<(ins "::mlir::AffineMapAttr":$map,
101 CArg<"::mlir::ValueRange", "{}">:$mapOperands),
103 $_state.addOperands(mapOperands);
104 Properties &props = $_state.getOrAddProperties<Properties>();
106 props.setNumDims($_builder.getIntegerAttr($_builder.getIndexType(),
107 map.getAffineMap().getNumDims()));
108 $_state.addTypes($_builder.getIndexType());
110 OpBuilder<(ins "::mlir::AffineMap":$map,
111 CArg<"::mlir::ValueRange", "{}">:$mapOperands),
113 build($_builder, $_state, ::mlir::AffineMapAttr::get(map), mapOperands);
115 OpBuilder<(ins "::mlir::AffineExpr":$expr,
116 CArg<"::mlir::ValueRange", "{}">:$mapOperands),
118 auto map = ::mlir::AffineMap::inferFromExprList({expr}).front();
119 build($_builder, $_state, map, mapOperands);
122 let assemblyFormat = [{
123 custom<DimAndSymbolList>($mapOperands, $numDims) $map attr-dict
128 let extraClassDeclaration = [{
129 /// Returns the affine map to be applied by this operation.
130 ::mlir::AffineMap inline getAffineMap() { return getMap(); }
132 /// Returns the affine value map computed from this operation.
133 ::mlir::affine::AffineValueMap getAffineValueMap() {
134 return ::mlir::affine::AffineValueMap(getAffineMap(), getOperands(), getResult());
137 /// Returns all dimension operands.
138 ::mlir::ValueRange getDimOperands() {
139 return ::mlir::OperandRange{
140 getOperands().begin(),
141 getOperands().begin() + getMap().getNumDims()};
144 /// Returns all symbol operands.
145 ::mlir::ValueRange getSymbolOperands() {
146 return ::mlir::OperandRange{
147 getOperands().begin() + getMap().getNumDims(),
148 getOperands().end()};
153#endif // LLZK_POLYMORPHIC_OPS