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//===----------------------------------------------------------------------===//
9
10#ifndef LLZK_BOOLEAN_OPS
11#define LLZK_BOOLEAN_OPS
12
13include "llzk/Dialect/Bool/IR/Dialect.td"
14include "llzk/Dialect/Bool/IR/Attrs.td"
15include "llzk/Dialect/Felt/IR/Types.td"
16include "llzk/Dialect/Array/IR/Types.td"
17include "llzk/Dialect/Function/IR/OpTraits.td"
18include "llzk/Dialect/Shared/OpsBase.td"
19
20include "mlir/IR/OpAsmInterface.td"
21include "mlir/IR/OpBase.td"
22include "mlir/IR/SymbolInterfaces.td"
23include "mlir/Interfaces/SideEffectInterfaces.td"
24include "mlir/Interfaces/ControlFlowInterfaces.td"
25
26//===------------------------------------------------------------------===//
27// Op Classes
28//===------------------------------------------------------------------===//
29
30class BoolDialectOp<string mnemonic, list<Trait> traits = []>
31 : Op<BoolDialect, mnemonic, traits>;
32
33class BoolBinaryOpBase<string mnemonic, Type resultType,
34 list<Trait> traits = []>
35 : BinaryOpBase<BoolDialect, mnemonic, resultType, traits> {
36 let hasFolder = 1;
37}
38
39class BoolUnaryOpBase<string mnemonic, Type resultType, list<Trait> traits = []>
40 : UnaryOpBase<BoolDialect, mnemonic, resultType, traits> {
41 let hasFolder = 1;
42}
43
44//===------------------------------------------------------------------===//
45// Boolean operators
46//===------------------------------------------------------------------===//
47
48def LLZK_AndBoolOp
49 : BoolBinaryOpBase<"and", I1, [NotFieldNative, Commutative]> {
50 let summary = "logical AND operator";
51 let description = [{
52 This operation computes the logical AND (i.e., conjunction) of two `i1` (i.e., boolean)
53 values as an `i1` value. The result is `1` if the operation is true and `0` otherwise.
54
55 If used in a constraint expression, this operation can be converted to `a*b` on felt operands.
56 }];
57}
58
59def LLZK_OrBoolOp : BoolBinaryOpBase<"or", I1, [NotFieldNative, Commutative]> {
60 let summary = "logical OR operator";
61 let description = [{
62 This operation computes the logical OR (i.e., disjunction) of two `i1` (i.e., boolean)
63 values as an `i1` value. The result is `1` if the operation is true and `0` otherwise.
64
65 If used in a constraint expression, this operation can be converted to `a+b - a*b` on felt operands.
66 }];
67}
68
69def LLZK_XorBoolOp
70 : BoolBinaryOpBase<"xor", I1, [NotFieldNative, Commutative]> {
71 let summary = "logical XOR operator";
72 let description = [{
73 This operation computes the logical XOR (i.e., exclusive disjunction) of two `i1` (i.e., boolean)
74 values as an `i1` value. The result is `1` if the operation is true and `0` otherwise.
75
76 If used in a constraint expression, this operation can be converted to `a+b - 2*a*b` on felt operands.
77 }];
78}
79
80def LLZK_NotBoolOp : BoolUnaryOpBase<"not", I1, [NotFieldNative]> {
81 let summary = "logical NOT operator";
82 let description = [{
83 This operation computes the logical NOT (i.e., negation) of an `i1` (i.e., boolean)
84 value as an `i1` value. The result is `1` if the operation is true and `0` otherwise.
85
86 If used in a constraint expression, this operation can be converted to `1+a - 2*a` on felt operands.
87 }];
88}
89
90//===------------------------------------------------------------------===//
91// Other operators
92//===------------------------------------------------------------------===//
93
94def LLZK_AssertOp
95 : BoolDialectOp<
96 "assert", [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
97 let summary = "assertion operation";
98 let description = [{
99 This operation asserts that a given boolean value is true. Assertions are checked
100 statically when possible. If the condition evaluates to `true`, the assertion is
101 removed. If `false`, an error is reported. Otherwise, the assertion is preserved.
102 All assertions that appear in `constrain()` functions must evaluate statically
103 (i.e., they cannot depend on inputs to the circuit) else an error is reported.
104
105 Assertion without message:
106 ```llzk
107 %1 = bool.cmp lt(%a, %b)
108 bool.assert %1
109 ```
110
111 Assertion with a message:
112 ```llzk
113 %1 = bool.cmp eq(%a, %b)
114 bool.assert %1, "expected equal values"
115 ```
116 }];
117
118 let arguments = (ins I1:$condition, OptionalAttr<StrAttr>:$msg);
119
120 let assemblyFormat = [{ $condition (`,` $msg^)? attr-dict }];
121}
122
123// Match format of Index comparisons (for now)
124def LLZK_CmpOp
125 : NaryOpBase<BoolDialect, "cmp",
126 LLZK_FeltType.builderCall, [Pure, TypesUnify<"lhs", "rhs">]> {
127 let summary = "compare field element values";
128 let description = [{
129 This operation takes two field element values and compares them according to the
130 comparison predicate and returns an `i1`. The following comparisons are supported:
131
132 - `eq`: equal
133 - `ne`: not equal
134 - `lt`: less than
135 - `le`: less than or equal
136 - `gt`: greater than
137 - `ge`: greater than or equal
138
139 The result is `1` if the comparison is true and `0` otherwise.
140
141 The inequality operators (lt, gt, le, ge) for the finite field elements
142 are defined by treating the field elements as integer values:
143 `f1 op f2` iff `int(f1) op int(f2)`
144
145 Example:
146
147 ```llzk
148 // Less than comparison.
149 %0 = bool.cmp lt(%a, %b)
150
151 // Greater than or equal comparison.
152 %1 = bool.cmp ge(%a, %b)
153
154 // Not equal comparison.
155 %2 = bool.cmp ne(%a, %b)
156
157 // Not equal comparison for felts in a specified field
158 %3 = bool.cmp ne(%c, %d) : !felt.type<"babybear">, !felt.type<"babybear">
159 ```
160 }];
161
162 let arguments = (ins LLZK_CmpPredicateAttr:$predicate, LLZK_FeltType:$lhs,
163 LLZK_FeltType:$rhs);
164 let results = (outs I1:$result);
165 let assemblyFormat = [{
166 `` $predicate `(` $lhs `,` $rhs `)`
167 `` custom<InferredOrParsedType>(type($lhs), "true")
168 `` custom<InferredOrParsedType>(type($rhs), "false") attr-dict
169 }];
170 let hasFolder = 1;
171}
172
173class QuantifierOp<string mnemonic, string cond, list<Trait> traits = []>
174 : BoolDialectOp<mnemonic, traits#[NotFieldNative, Pure, SingleBlock]> {
175 let summary = mnemonic#" quantifier operation";
176 let description = [{
177 This operation applies a predicate to each element of the given sort.
178 Returns true iff the predicate is true for }]#cond#[{ of the sort.
179
180 Only LLZK arrays are supported as the sort type at the moment.
181
182 Example:
183 ```
184 %c10 = felt.const 10
185 %0 = array.new %a, %b, %c : !array.type<3 x !felt.type>
186 %1 = bool.}]#mnemonic#[{ %e in %0 !array.type<3 x !felt.type> {
187 %2 = bool.cmp lt(%e, %c10)
188 bool.yield %2
189 }
190 ```
191 }];
192
193 let arguments = (ins LLZK_ArrayType:$sort);
194 let results = (outs I1:$result);
195 let regions = (region SizedRegion<1>:$region);
196
197 let hasCustomAssemblyFormat = 1;
198 let hasVerifier = 1;
199}
200
201def ForAllOp : QuantifierOp<"forall", "all elements"> {}
202
203def ExistsOp : QuantifierOp<"exists", "at least one element"> {}
204
205def YieldOp : BoolDialectOp<"yield", [NotFieldNative, Terminator, ReturnLike,
206 ParentOneOf<["ForAllOp", "ExistsOp"]>]> {
207 let summary = "boolean yield operation";
208 let description = [{
209 This terminator operation yields the boolean value of the predicate inside the body of
210 `bool.forall` and `bool.exists` operations.
211 }];
212
213 let arguments = (ins I1:$value);
214 let assemblyFormat = "$value attr-dict";
215}
216
217#endif // LLZK_BOOLEAN_OPS