Skip to content

Commit 1f8ee7e

Browse files
authored
Replace "witness only" with "non native felt op" attribute on felt arith ops (#288)
1 parent 2f145ec commit 1f8ee7e

File tree

33 files changed

+260
-148
lines changed

33 files changed

+260
-148
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
added:
2+
- "Add `function.allow_non_native_field_ops` attribute"
3+
changed:
4+
- "Require `function.allow_non_native_field_ops` attribute on functions that use
5+
non-native field operations, instead of requiring `function.allow_witness` attribute."

include/llzk-c/Dialect/Function.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ LLZK_DECLARE_OP_PREDICATE(FuncDefOp, HasAllowWitnessAttr);
8484
/// Sets the allow_witness attribute in the FuncDefOp operation.
8585
MLIR_CAPI_EXPORTED void llzkFuncDefOpSetAllowWitnessAttr(MlirOperation op, bool value);
8686

87+
/// Returns true if the FuncDefOp has the allow_non_native_field_ops attribute.
88+
LLZK_DECLARE_OP_PREDICATE(FuncDefOp, HasAllowNonNativeFieldOpsAttr);
89+
90+
/// Sets the allow_non_native_field_ops attribute in the FuncDefOp operation.
91+
MLIR_CAPI_EXPORTED void llzkFuncDefOpSetAllowNonNativeFieldOpsAttr(MlirOperation op, bool value);
92+
8793
/// Returns true if the `idx`-th argument has the Pub attribute.
8894
LLZK_DECLARE_NARY_OP_PREDICATE(FuncDefOp, HasArgIsPub, unsigned arg);
8995

include/llzk/Dialect/Bool/IR/Ops.td

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ class BoolUnaryOpBase<string mnemonic, Type resultType, list<Trait> traits = []>
3939
// Boolean operators
4040
//===------------------------------------------------------------------===//
4141

42-
def LLZK_AndBoolOp : BoolBinaryOpBase<"and", I1, [Commutative]> {
42+
def LLZK_AndBoolOp
43+
: BoolBinaryOpBase<"and", I1, [NotFieldNative, Commutative]> {
4344
let summary = "logical AND operator";
4445
let description = [{
4546
This operation computes the logical AND (i.e., conjunction) of two `i1` (i.e., boolean)
@@ -49,7 +50,7 @@ def LLZK_AndBoolOp : BoolBinaryOpBase<"and", I1, [Commutative]> {
4950
}];
5051
}
5152

52-
def LLZK_OrBoolOp : BoolBinaryOpBase<"or", I1, [Commutative]> {
53+
def LLZK_OrBoolOp : BoolBinaryOpBase<"or", I1, [NotFieldNative, Commutative]> {
5354
let summary = "logical OR operator";
5455
let description = [{
5556
This operation computes the logical OR (i.e., disjunction) of two `i1` (i.e., boolean)
@@ -59,7 +60,8 @@ def LLZK_OrBoolOp : BoolBinaryOpBase<"or", I1, [Commutative]> {
5960
}];
6061
}
6162

62-
def LLZK_XorBoolOp : BoolBinaryOpBase<"xor", I1, [Commutative]> {
63+
def LLZK_XorBoolOp
64+
: BoolBinaryOpBase<"xor", I1, [NotFieldNative, Commutative]> {
6365
let summary = "logical XOR operator";
6466
let description = [{
6567
This operation computes the logical XOR (i.e., exclusive disjunction) of two `i1` (i.e., boolean)
@@ -69,7 +71,7 @@ def LLZK_XorBoolOp : BoolBinaryOpBase<"xor", I1, [Commutative]> {
6971
}];
7072
}
7173

72-
def LLZK_NotBoolOp : BoolUnaryOpBase<"not", I1, []> {
74+
def LLZK_NotBoolOp : BoolUnaryOpBase<"not", I1, [NotFieldNative]> {
7375
let summary = "logical NOT operator";
7476
let description = [{
7577
This operation computes the logical NOT (i.e., negation) of an `i1` (i.e., boolean)

include/llzk/Dialect/Felt/IR/Ops.td

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ def LLZK_MulFeltOp : FeltDialectBinaryOp<"mul", LLZK_FeltType, [Commutative]> {
103103
let description = [{}];
104104
}
105105

106-
def LLZK_PowFeltOp : FeltDialectBinaryOp<"pow", LLZK_FeltType, [WitnessGen]> {
106+
def LLZK_PowFeltOp
107+
: FeltDialectBinaryOp<"pow", LLZK_FeltType, [NotFieldNative]> {
107108
let summary = "exponentiation operator for field elements";
108109
let description = [{
109110

@@ -122,7 +123,7 @@ def LLZK_DivFeltOp : FeltDialectBinaryOp<"div", LLZK_FeltType> {
122123
}
123124

124125
def LLZK_UnsignedIntDivFeltOp
125-
: FeltDialectBinaryOp<"uintdiv", LLZK_FeltType, [WitnessGen]> {
126+
: FeltDialectBinaryOp<"uintdiv", LLZK_FeltType, [NotFieldNative]> {
126127
let summary = "unsigned integer division operator for field elements";
127128
let description = [{
128129
Treats the operands as if they were unsigned integers with bitwidth
@@ -131,7 +132,7 @@ def LLZK_UnsignedIntDivFeltOp
131132
}
132133

133134
def LLZK_SignedIntDivFeltOp
134-
: FeltDialectBinaryOp<"sintdiv", LLZK_FeltType, [WitnessGen]> {
135+
: FeltDialectBinaryOp<"sintdiv", LLZK_FeltType, [NotFieldNative]> {
135136
let summary = "signed integer division operator for field elements";
136137
let description = [{
137138
Treats the operands as if they were signed integers with bitwidth
@@ -148,7 +149,7 @@ def LLZK_SignedIntDivFeltOp
148149
}
149150

150151
def LLZK_UnsignedModFeltOp
151-
: FeltDialectBinaryOp<"umod", LLZK_FeltType, [WitnessGen]> {
152+
: FeltDialectBinaryOp<"umod", LLZK_FeltType, [NotFieldNative]> {
152153
let summary =
153154
"unsigned integer modulus/remainder operator for field elements";
154155
let description = [{
@@ -158,7 +159,7 @@ def LLZK_UnsignedModFeltOp
158159
}
159160

160161
def LLZK_SignedModFeltOp
161-
: FeltDialectBinaryOp<"smod", LLZK_FeltType, [WitnessGen]> {
162+
: FeltDialectBinaryOp<"smod", LLZK_FeltType, [NotFieldNative]> {
162163
let summary = "signed integer modulus/remainder operator for field elements";
163164
let description = [{
164165
Computes the remainder that would result from the division operation performed
@@ -171,31 +172,35 @@ def LLZK_NegFeltOp : FeltDialectUnaryOp<"neg", LLZK_FeltType> {
171172
let description = [{}];
172173
}
173174

174-
def LLZK_InvFeltOp : FeltDialectUnaryOp<"inv", LLZK_FeltType, [WitnessGen]> {
175+
def LLZK_InvFeltOp
176+
: FeltDialectUnaryOp<"inv", LLZK_FeltType, [NotFieldNative]> {
175177
let summary = "inverse operator for field elements";
176178
let description = [{}];
177179
}
178180

179181
def LLZK_AndFeltOp
180-
: FeltDialectBinaryOp<"bit_and", LLZK_FeltType, [WitnessGen, Commutative]> {
182+
: FeltDialectBinaryOp<"bit_and",
183+
LLZK_FeltType, [NotFieldNative, Commutative]> {
181184
let summary = "bitwise AND operator for field elements";
182185
let description = [{}];
183186
}
184187

185188
def LLZK_OrFeltOp
186-
: FeltDialectBinaryOp<"bit_or", LLZK_FeltType, [WitnessGen, Commutative]> {
189+
: FeltDialectBinaryOp<"bit_or",
190+
LLZK_FeltType, [NotFieldNative, Commutative]> {
187191
let summary = "bitwise OR operator for field elements";
188192
let description = [{}];
189193
}
190194

191195
def LLZK_XorFeltOp
192-
: FeltDialectBinaryOp<"bit_xor", LLZK_FeltType, [WitnessGen, Commutative]> {
196+
: FeltDialectBinaryOp<"bit_xor",
197+
LLZK_FeltType, [NotFieldNative, Commutative]> {
193198
let summary = "bitwise XOR operator for field elements";
194199
let description = [{}];
195200
}
196201

197202
def LLZK_NotFeltOp
198-
: FeltDialectUnaryOp<"bit_not", LLZK_FeltType, [WitnessGen]> {
203+
: FeltDialectUnaryOp<"bit_not", LLZK_FeltType, [NotFieldNative]> {
199204
let summary = "integer complement (bitwise-not) operator for field elements";
200205
let description = [{
201206
Treats the operand as an integer with a bitwidth equal to the bitwidth
@@ -204,12 +209,14 @@ def LLZK_NotFeltOp
204209
}];
205210
}
206211

207-
def LLZK_ShlFeltOp : FeltDialectBinaryOp<"shl", LLZK_FeltType, [WitnessGen]> {
212+
def LLZK_ShlFeltOp
213+
: FeltDialectBinaryOp<"shl", LLZK_FeltType, [NotFieldNative]> {
208214
let summary = "left shift operator for field elements";
209215
let description = [{}];
210216
}
211217

212-
def LLZK_ShrFeltOp : FeltDialectBinaryOp<"shr", LLZK_FeltType, [WitnessGen]> {
218+
def LLZK_ShrFeltOp
219+
: FeltDialectBinaryOp<"shr", LLZK_FeltType, [NotFieldNative]> {
213220
let summary = "right shift operator for field elements";
214221
let description = [{}];
215222
}

include/llzk/Dialect/Function/IR/Attrs.td

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,31 @@ class FunctionDialectAttr<string name, string attrMnemonic,
2222

2323
def LLZK_AllowConstraintAttr
2424
: FunctionDialectAttr<"AllowConstraint", "allow_constraint"> {
25-
let summary = "Marks functions to allow `ConstraintGen` ops";
25+
let summary =
26+
"Marks functions to allow `ConstraintGen` ops within their body";
2627
let description = [{
2728
A unit attribute that can be attached to a `FuncDefOp` to indicate that ops
28-
marked with `ConstraintGen` (ex: emit ops) are allowed within its body.
29+
marked with `ConstraintGen` (e.g., emit ops) are allowed within its body.
2930
}];
3031
}
3132

3233
def LLZK_AllowWitnessAttr
3334
: FunctionDialectAttr<"AllowWitness", "allow_witness"> {
34-
let summary = "Marks functions to allow `WitnessGen` ops";
35+
let summary = "Marks functions to allow `WitnessGen` ops within their body";
3536
let description = [{
36-
A unit attribute that can be attached to a `FuncDefOp` to indicate that ops
37-
marked with `WitnessGen` (i.e., boolean and bitwise ops) are allowed within its body.
37+
A unit attribute that can be attached to a `FuncDefOp` to indicate that ops marked
38+
with `WitnessGen` (e.g., construct and write ops) are allowed within its body.
39+
}];
40+
}
41+
42+
def LLZK_AllowNonNativeFieldOpsAttr
43+
: FunctionDialectAttr<"AllowNonNativeFieldOps",
44+
"allow_non_native_field_ops"> {
45+
let summary =
46+
"Marks functions to allow `NotFieldNative` ops within their body";
47+
let description = [{
48+
A unit attribute that can be attached to a `FuncDefOp` to indicate that ops marked
49+
with `NotFieldNative` (e.g., boolean and bitwise ops) are allowed within its body.
3850
}];
3951
}
4052

include/llzk/Dialect/Function/IR/OpTraits.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ namespace llzk::function {
1717

1818
mlir::LogicalResult verifyConstraintGenTraitImpl(mlir::Operation *op);
1919
mlir::LogicalResult verifyWitnessGenTraitImpl(mlir::Operation *op);
20+
mlir::LogicalResult verifyNotFieldNativeTraitImpl(mlir::Operation *op);
2021

2122
/// Marker for ops that are specific to constraint generation.
2223
/// Verifies that the surrounding function is marked with the `AllowConstraintAttr`.
@@ -38,4 +39,14 @@ class WitnessGen : public mlir::OpTrait::TraitBase<TypeClass, WitnessGen> {
3839
}
3940
};
4041

42+
/// Marker for ops over `llzk.felt` type operands that are not native to finite field arithmetic.
43+
/// Verifies that the surrounding function is marked with the `AllowNonNativeFieldOpsAttr`.
44+
template <typename TypeClass>
45+
class NotFieldNative : public mlir::OpTrait::TraitBase<TypeClass, NotFieldNative> {
46+
public:
47+
inline static mlir::LogicalResult verifyTrait(mlir::Operation *op) {
48+
return verifyNotFieldNativeTraitImpl(op);
49+
}
50+
};
51+
4152
} // namespace llzk::function

include/llzk/Dialect/Function/IR/OpTraits.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,12 @@ def ConstraintGen : NativeOpTrait<"ConstraintGen">, StructuralOpTrait {
2424
string cppNamespace = "::llzk::function";
2525
}
2626

27+
/// Marker for ops over `llzk.felt` type operands that are not native to finite
28+
/// field arithmetic and thus must be rewritten or folded into a constant after
29+
/// the flattening and unrolling pass. Op classes with this trait are valid only
30+
/// in functions that have the `AllowNonNativeFieldOpsAttr`.
31+
def NotFieldNative : NativeOpTrait<"NotFieldNative">, StructuralOpTrait {
32+
string cppNamespace = "::llzk::function";
33+
}
34+
2735
#endif // LLZK_FUNCTION_TRAITS

include/llzk/Dialect/Function/IR/Ops.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,14 @@ def FuncDefOp
150150
/// Add (resp. remove) the `allow_witness` attribute to (resp. from) the function def.
151151
void setAllowWitnessAttr(bool newValue = true);
152152

153+
/// Return `true` iff the function def has the `allow_non_native_field_ops` attribute.
154+
inline bool hasAllowNonNativeFieldOpsAttr() {
155+
return getOperation()->hasAttr(llzk::function::AllowNonNativeFieldOpsAttr::name);
156+
}
157+
158+
/// Add (resp. remove) the `allow_non_native_field_ops` attribute to (resp. from) the function def.
159+
void setAllowNonNativeFieldOpsAttr(bool newValue = true);
160+
153161
/// Return `true` iff the argument at the given index has `pub` attribute.
154162
bool hasArgPublicAttr(unsigned index);
155163

lib/CAPI/Dialect/Function.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@ void llzkFuncDefOpSetAllowWitnessAttr(MlirOperation op, bool value) {
7979
unwrap_cast<FuncDefOp>(op).setAllowWitnessAttr(value);
8080
}
8181

82+
bool llzkFuncDefOpGetHasAllowNonNativeFieldOpsAttr(MlirOperation op) {
83+
return unwrap_cast<FuncDefOp>(op).hasAllowNonNativeFieldOpsAttr();
84+
}
85+
86+
void llzkFuncDefOpSetAllowNonNativeFieldOpsAttr(MlirOperation op, bool value) {
87+
unwrap_cast<FuncDefOp>(op).setAllowNonNativeFieldOpsAttr(value);
88+
}
89+
8290
bool llzkFuncDefOpGetHasArgIsPub(MlirOperation op, unsigned argNo) {
8391
return unwrap_cast<FuncDefOp>(op).hasArgPublicAttr(argNo);
8492
}

lib/Dialect/Function/IR/OpTraits.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,12 @@ LogicalResult verifyWitnessGenTraitImpl(Operation *op) {
4343
return success();
4444
}
4545

46+
LogicalResult verifyNotFieldNativeTraitImpl(Operation *op) {
47+
if (!parentFuncDefOpHasAttr(op, &FuncDefOp::hasAllowNonNativeFieldOpsAttr)) {
48+
return op->emitOpError() << "only valid within a '" << FuncDefOp::getOperationName()
49+
<< "' with '" << AllowNonNativeFieldOpsAttr::name << "' attribute";
50+
}
51+
return success();
52+
}
53+
4654
} // namespace llzk::function

0 commit comments

Comments
 (0)