LLZK 2.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//===----------------------------------------------------------------------===//
9
10#ifndef LLZK_FELT_OPS
11#define LLZK_FELT_OPS
12
13include "llzk/Dialect/Felt/IR/Dialect.td"
14include "llzk/Dialect/Felt/IR/Types.td"
15include "llzk/Dialect/Felt/IR/Attrs.td"
16include "llzk/Dialect/Function/IR/OpTraits.td"
17include "llzk/Dialect/Shared/OpsBase.td"
18include "llzk/Dialect/Felt/IR/OpInterfaces.td"
19
20include "mlir/IR/OpAsmInterface.td"
21include "mlir/IR/OpBase.td"
22include "mlir/IR/SymbolInterfaces.td"
23include "mlir/Interfaces/SideEffectInterfaces.td"
24
25//===------------------------------------------------------------------===//
26// Op Classes
27//===------------------------------------------------------------------===//
28
29class FeltDialectOp<string mnemonic, list<Trait> traits = []>
30 : Op<FeltDialect, mnemonic, traits>;
31
32class FeltDialectBinaryOp<string mnemonic, list<Trait> traits = []>
33 : BinaryOpBase<FeltDialect, mnemonic, LLZK_FeltType,
34 traits#[TypesUnify<"lhs", "rhs">,
35 DeclareOpInterfaceMethods<FeltBinaryOpInterface>,
36 InferTypeOpAdaptorWithIsCompatible]> {
37 // Allow any type to avoid building default felt for the result type, we
38 // employ our own inference below.
39 let results = (outs AnyLLZKType:$result);
40 let hasFolder = 1;
41
42 let extraClassDefinition = [{
43 ::llvm::LogicalResult $cppClass::inferReturnTypes(
44 mlir::MLIRContext *context, std::optional<mlir::Location> loc, Adaptor adaptor,
45 llvm::SmallVectorImpl<mlir::Type> &inferred
46 ) {
47 inferred.resize(1);
48 auto value = adaptor.getLhs();
49 inferred[0] = value ? value.getType() : FeltType::get(context, mlir::StringAttr());
50 return mlir::success();
51 }
52
53 bool $cppClass::isCompatibleReturnTypes(mlir::TypeRange l, mlir::TypeRange r) {
54 return l == r;
55 }
56 }];
57}
58
59class FeltDialectUnaryOp<string mnemonic, list<Trait> traits = []>
60 : UnaryOpBase<FeltDialect, mnemonic, LLZK_FeltType,
61 traits#[InferTypeOpAdaptorWithIsCompatible]> {
62 // Allow any type to avoid building default felt for the result type, we
63 // employ our own inference below.
64 let results = (outs AnyLLZKType:$result);
65 let hasFolder = 1;
66
67 let extraClassDefinition = [{
68 ::llvm::LogicalResult $cppClass::inferReturnTypes(
69 mlir::MLIRContext *context, std::optional<mlir::Location> loc, Adaptor adaptor,
70 llvm::SmallVectorImpl<mlir::Type> &inferred
71 ) {
72 inferred.resize(1);
73 auto value = adaptor.getOperand();
74 inferred[0] = value ? value.getType() : FeltType::get(context, mlir::StringAttr());
75 return mlir::success();
76 }
77
78 bool $cppClass::isCompatibleReturnTypes(mlir::TypeRange l, mlir::TypeRange r) {
79 return l == r;
80 }
81 }];
82}
83
84//===------------------------------------------------------------------===//
85// Constants
86//===------------------------------------------------------------------===//
87
88def LLZK_FeltConstantOp
89 : FeltDialectOp<"const", [ConstantLike, Pure,
90 DeclareOpInterfaceMethods<
91 OpAsmOpInterface, ["getAsmResultNames"]>,
92 TypeUnifyWithResult<"value">,
93 InferTypeOpAdaptorWithIsCompatible]> {
94 let summary = "field element constant";
95 let description = [{
96 This operation produces a felt-typed SSA value holding an integer constant.
97
98 Example:
99
100 ```llzk
101 %0 = felt.const 42
102 %0 = felt.const 99 <"bn254">
103 ```
104 }];
105
106 let arguments = (ins LLZK_FeltConstAttr:$value);
107 let results = (outs AnyLLZKType:$result);
108 let assemblyFormat = [{ $value attr-dict }];
109 let hasFolder = 1;
110}
111
112//===------------------------------------------------------------------===//
113// Operators
114//===------------------------------------------------------------------===//
115
116def LLZK_AddFeltOp : FeltDialectBinaryOp<"add", [Commutative]> {
117 let summary = "addition operator for field elements";
118 let description = [{}];
119}
120
121def LLZK_SubFeltOp : FeltDialectBinaryOp<"sub"> {
122 let summary = "subtraction operator for field elements";
123 let description = [{}];
124}
125
126def LLZK_MulFeltOp : FeltDialectBinaryOp<"mul", [Commutative]> {
127 let summary = "multiplication operator for field elements";
128 let description = [{}];
129}
130
131def LLZK_PowFeltOp : FeltDialectBinaryOp<"pow", [NotFieldNative]> {
132 let summary = "exponentiation operator for field elements";
133 let description = [{
134
135 Raises a field element to the power of an exponent.
136
137 ```llzk
138 %result = felt.pow %base, %exponent
139 ```
140
141 }];
142}
143
144def LLZK_DivFeltOp : FeltDialectBinaryOp<"div"> {
145 let summary = "field-division operator for field elements";
146 let description = [{
147 Performs finite-field division by multiplying the dividend by the
148 multiplicative inverse of the divisor. For a non-zero divisor `b`,
149 `felt.div %a, %b` computes `%a * inv(%b)` modulo the field prime of the result
150 prime field.
151
152 The divisor must be non-zero.
153
154 This is not integer division. Use `felt.uintdiv` or `felt.sintdiv` when the
155 operands should be interpreted as integers.
156 }];
157}
158
159def LLZK_UnsignedIntDivFeltOp
160 : FeltDialectBinaryOp<"uintdiv", [NotFieldNative]> {
161 let summary = "unsigned integer division operator for field elements";
162 let description = [{
163 Treats the operands as if they were unsigned integers with bitwidth
164 equal to that of the prime modulus and performs division rounding towards zero.
165 }];
166}
167
168def LLZK_SignedIntDivFeltOp : FeltDialectBinaryOp<"sintdiv", [NotFieldNative]> {
169 let summary = "signed integer division operator for field elements";
170 let description = [{
171 Treats the operands as if they were signed integers with bitwidth
172 equal to that of the prime modulus (no additional sign bit is added)
173 and performs division rounding towards zero.
174
175 The signed integer representation of felt `f` in prime field with modulus
176 `p` follows the following formula:
177
178 signed_int(f) = f if 0 <= f < p/2 + 1
179 "p/2" here is unsigned integer division rounding towards 0
180 signed_int(f) = f-p if p/2 + 1 <= f < p
181 }];
182}
183
184def LLZK_UnsignedModFeltOp : FeltDialectBinaryOp<"umod", [NotFieldNative]> {
185 let summary =
186 "unsigned integer modulus/remainder operator for field elements";
187 let description = [{
188 Computes the remainder that would result from the division operation performed
189 by `felt.uintdiv`.
190 }];
191}
192
193def LLZK_SignedModFeltOp : FeltDialectBinaryOp<"smod", [NotFieldNative]> {
194 let summary = "signed integer modulus/remainder operator for field elements";
195 let description = [{
196 Computes the remainder that would result from the division operation performed
197 by `felt.sintdiv`.
198 }];
199}
200
201def LLZK_NegFeltOp : FeltDialectUnaryOp<"neg"> {
202 let summary = "negation operator for field elements";
203 let description = [{}];
204}
205
206def LLZK_InvFeltOp : FeltDialectUnaryOp<"inv", [NotFieldNative]> {
207 let summary = "inverse operator for field elements";
208 let description = [{}];
209}
210
211def LLZK_AndFeltOp
212 : FeltDialectBinaryOp<"bit_and", [NotFieldNative, Commutative]> {
213 let summary = "bitwise AND operator for field elements";
214 let description = [{}];
215}
216
217def LLZK_OrFeltOp
218 : FeltDialectBinaryOp<"bit_or", [NotFieldNative, Commutative]> {
219 let summary = "bitwise OR operator for field elements";
220 let description = [{}];
221}
222
223def LLZK_XorFeltOp
224 : FeltDialectBinaryOp<"bit_xor", [NotFieldNative, Commutative]> {
225 let summary = "bitwise XOR operator for field elements";
226 let description = [{}];
227}
228
229def LLZK_NotFeltOp : FeltDialectUnaryOp<"bit_not", [NotFieldNative]> {
230 let summary = "integer complement (bitwise-not) operator for field elements";
231 let description = [{
232 Treats the operand as an integer with a bitwidth equal to the bitwidth
233 of the prime field's modulus and compute the one's complement of the integer.
234 The result is converted back to a field element by applying the prime modulus.
235 }];
236}
237
238def LLZK_ShlFeltOp : FeltDialectBinaryOp<"shl", [NotFieldNative]> {
239 let summary = "left shift operator for field elements";
240 let description = [{}];
241}
242
243def LLZK_ShrFeltOp : FeltDialectBinaryOp<"shr", [NotFieldNative]> {
244 let summary = "right shift operator for field elements";
245 let description = [{}];
246}
247
248#endif // LLZK_FELT_OPS