Skip to content

Commit 27ee3af

Browse files
j2kuncopybara-github
authored andcommitted
Add cheddar_gpu neg op
Adds pointwise modular negation (cheddar_gpu.neg) and the unary op base class to the cheddar_gpu dialect. PiperOrigin-RevId: 1015875353
1 parent 86d9fc0 commit 27ee3af

6 files changed

Lines changed: 176 additions & 12 deletions

File tree

‎lib/Dialect/CheddarGPU/IR/CheddarGPUConstraints.td‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ def CheddarGPU_PolyBuffer : CheddarGPU_StaticMemRefOfRank<[I32, I64], 2,
2929
class CheddarGPU_FormsMatch<list<string> a>
3030
: AllMatchSameOperatorTrait<a, "$_self", "form">;
3131

32+
class CheddarGPU_FormsAre<list<string> attrs, EnumCase f>
33+
: PredOpTrait<
34+
"{" # !interleave(attrs, ", ") # "} are '" # f.str # "'",
35+
And<!foreach(a, attrs, CPred<"$" # a # " == ::mlir::heir::cheddar_gpu::Form::" # f.symbol>)>>;
36+
3237
//===----------------------------------------------------------------------===//
3338
// Attribute Constraints
3439
//===----------------------------------------------------------------------===//

‎lib/Dialect/CheddarGPU/IR/CheddarGPUOps.td‎

Lines changed: 117 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,34 +22,73 @@ class CheddarGPU_Op<string mnemonic, list<Trait> traits = []>
2222
}];
2323
}
2424

25+
defvar CheddarGPU_UnaryForms = (ins
26+
CheddarGPU_FormAttr:$in_form,
27+
CheddarGPU_FormAttr:$out_form
28+
);
29+
2530
defvar CheddarGPU_BinaryForms = (ins
2631
CheddarGPU_FormAttr:$lhs_form,
2732
CheddarGPU_FormAttr:$rhs_form,
2833
CheddarGPU_FormAttr:$out_form
2934
);
3035

36+
defvar CheddarGPU_UnaryLimbRanges = (ins
37+
OptionalAttr<CheddarGPU_LimbRangeAttr>:$in_limb_range,
38+
OptionalAttr<CheddarGPU_LimbRangeAttr>:$out_limb_range
39+
);
40+
3141
defvar CheddarGPU_BinaryLimbRanges = (ins
3242
OptionalAttr<CheddarGPU_LimbRangeAttr>:$lhs_limb_range,
3343
OptionalAttr<CheddarGPU_LimbRangeAttr>:$rhs_limb_range,
3444
OptionalAttr<CheddarGPU_LimbRangeAttr>:$out_limb_range
3545
);
3646

3747
defvar CheddarGPU_BinaryBuilders = [
38-
OpBuilder<(ins "Value":$out, "Value":$lhs, "Value":$rhs,
39-
"FormAttr":$lhs_form, "FormAttr":$rhs_form, "FormAttr":$out_form,
40-
CArg<"DenseI64ArrayAttr", "{}">:$lhs_limb_range,
41-
CArg<"DenseI64ArrayAttr", "{}">:$rhs_limb_range,
42-
CArg<"DenseI64ArrayAttr", "{}">:$out_limb_range), [{
48+
OpBuilder<(ins "::mlir::Value":$out,
49+
"::mlir::Value":$lhs,
50+
"::mlir::Value":$rhs,
51+
"::mlir::heir::cheddar_gpu::FormAttr":$lhs_form,
52+
"::mlir::heir::cheddar_gpu::FormAttr":$rhs_form,
53+
"::mlir::heir::cheddar_gpu::FormAttr":$out_form,
54+
CArg<"::mlir::DenseI64ArrayAttr", "{}">:$lhs_limb_range,
55+
CArg<"::mlir::DenseI64ArrayAttr", "{}">:$rhs_limb_range,
56+
CArg<"::mlir::DenseI64ArrayAttr", "{}">:$out_limb_range), [{
4357
build($_builder, $_state, out, lhs, rhs, lhs_form, rhs_form, out_form,
44-
lhs_limb_range, rhs_limb_range, out_limb_range, /*num_aux=*/IntegerAttr{});
58+
lhs_limb_range, rhs_limb_range, out_limb_range, /*num_aux=*/::mlir::IntegerAttr{});
4559
}]>,
46-
OpBuilder<(ins "Value":$out, "Value":$lhs, "Value":$rhs,
47-
"Form":$lhs_form, "Form":$rhs_form, "Form":$out_form,
48-
CArg<"DenseI64ArrayAttr", "{}">:$lhs_limb_range,
49-
CArg<"DenseI64ArrayAttr", "{}">:$rhs_limb_range,
50-
CArg<"DenseI64ArrayAttr", "{}">:$out_limb_range), [{
60+
OpBuilder<(ins "::mlir::Value":$out,
61+
"::mlir::Value":$lhs,
62+
"::mlir::Value":$rhs,
63+
"::mlir::heir::cheddar_gpu::Form":$lhs_form,
64+
"::mlir::heir::cheddar_gpu::Form":$rhs_form,
65+
"::mlir::heir::cheddar_gpu::Form":$out_form,
66+
CArg<"::mlir::DenseI64ArrayAttr", "{}">:$lhs_limb_range,
67+
CArg<"::mlir::DenseI64ArrayAttr", "{}">:$rhs_limb_range,
68+
CArg<"::mlir::DenseI64ArrayAttr", "{}">:$out_limb_range), [{
5169
build($_builder, $_state, out, lhs, rhs, lhs_form, rhs_form, out_form,
52-
lhs_limb_range, rhs_limb_range, out_limb_range, /*num_aux=*/IntegerAttr{});
70+
lhs_limb_range, rhs_limb_range, out_limb_range, /*num_aux=*/::mlir::IntegerAttr{});
71+
}]>
72+
];
73+
74+
defvar CheddarGPU_UnaryBuilders = [
75+
OpBuilder<(ins "::mlir::Value":$out,
76+
"::mlir::Value":$in,
77+
"::mlir::heir::cheddar_gpu::FormAttr":$in_form,
78+
"::mlir::heir::cheddar_gpu::FormAttr":$out_form,
79+
CArg<"::mlir::DenseI64ArrayAttr", "{}">:$in_limb_range,
80+
CArg<"::mlir::DenseI64ArrayAttr", "{}">:$out_limb_range), [{
81+
build($_builder, $_state, out, in, in_form, out_form,
82+
in_limb_range, out_limb_range, /*num_aux=*/::mlir::IntegerAttr{});
83+
}]>,
84+
OpBuilder<(ins "::mlir::Value":$out,
85+
"::mlir::Value":$in,
86+
"::mlir::heir::cheddar_gpu::Form":$in_form,
87+
"::mlir::heir::cheddar_gpu::Form":$out_form,
88+
CArg<"::mlir::DenseI64ArrayAttr", "{}">:$in_limb_range,
89+
CArg<"::mlir::DenseI64ArrayAttr", "{}">:$out_limb_range), [{
90+
build($_builder, $_state, out, in, in_form, out_form,
91+
in_limb_range, out_limb_range, /*num_aux=*/::mlir::IntegerAttr{});
5392
}]>
5493
];
5594

@@ -81,6 +120,30 @@ class CheddarGPU_BinaryOpBase<string mnemonic, list<Trait> traits = []>
81120
}];
82121
}
83122

123+
// Unary element-wise operations on single polynomial buffers (neg).
124+
class CheddarGPU_UnaryOpBase<string mnemonic, dag extraAttrs = (ins),
125+
list<OpBuilder> opBuilders = [], list<Trait> traits = []>
126+
: CheddarGPU_Op<mnemonic, !listconcat([
127+
AllTypesMatch<["out", "in"]>,
128+
CheddarGPU_LimbRangesWithin
129+
], traits)> {
130+
let arguments = !con(
131+
(ins
132+
Arg<CheddarGPU_PolyBuffer, "destination buffer", [MemWrite]>:$out,
133+
Arg<CheddarGPU_PolyBuffer, "input polynomial buffer", [MemRead]>:$in
134+
),
135+
CheddarGPU_UnaryForms,
136+
extraAttrs,
137+
CheddarGPU_UnaryLimbRanges,
138+
(ins OptionalAttr<CheddarGPU_NonNegI64Attr>:$num_aux)
139+
);
140+
141+
let builders = opBuilders;
142+
let assemblyFormat = [{
143+
$out `,` $in prop-dict attr-dict `:` type($out)
144+
}];
145+
}
146+
84147
//===----------------------------------------------------------------------===//
85148
// Binary and Unary Element-Wise Operations
86149
//===----------------------------------------------------------------------===//
@@ -99,4 +162,46 @@ def CheddarGPU_AddOp : CheddarGPU_BinaryOpBase<"add", [
99162
}];
100163
}
101164

165+
def CheddarGPU_SubOp : CheddarGPU_BinaryOpBase<"sub", [
166+
CheddarGPU_FormsMatch<["lhs_form", "rhs_form", "out_form"]>]> {
167+
let summary = "Pointwise modular subtraction of two polynomial buffers";
168+
let description = [{
169+
Mirrors Cheddar's `kernel::Sub` and `ElementWiseHandler::Sub` in `ElementWise.cu`.
170+
Computes `out = lhs - rhs mod Q` limb-wise, where the limbs of `Q` are defined
171+
in `CheddarGPU_ParamsAttr`.
172+
173+
Form contract:
174+
- Modular subtraction is valid in both `coeff` and `eval` domain.
175+
- Both operands must have matching form (`lhs_form == rhs_form == out_form`).
176+
}];
177+
}
178+
179+
def CheddarGPU_NegOp : CheddarGPU_UnaryOpBase<"neg", (ins), CheddarGPU_UnaryBuilders, [
180+
CheddarGPU_FormsMatch<["in_form", "out_form"]>]> {
181+
let summary = "Pointwise modular negation of a polynomial buffer";
182+
let description = [{
183+
Mirrors Cheddar's `kernel::Neg` and `ElementWiseHandler::Neg` in `ElementWise.cu`.
184+
Computes `out = -in mod Q` limb-wise, where the limbs of `Q` are defined
185+
in `CheddarGPU_ParamsAttr`.
186+
187+
Form contract:
188+
- Valid in both `coeff` and `eval` domain.
189+
- Preserves representation form (`in_form == out_form`).
190+
}];
191+
}
192+
193+
def CheddarGPU_MulOp : CheddarGPU_BinaryOpBase<"mul", [
194+
CheddarGPU_FormsAre<["lhs_form", "rhs_form", "out_form"], CheddarGPU_Form_Eval>]> {
195+
let summary = "Pointwise Montgomery modular multiplication";
196+
let description = [{
197+
Mirrors Cheddar's `kernel::Mult` and `ElementWiseHandler::Mult` in `ElementWise.cu`.
198+
Computes the Montgomery form multiplication of `lhs` and `rhs` mod `Q`.
199+
200+
Form contract:
201+
- Polynomial multiplication in evaluation domain is pointwise Montgomery multiplication:
202+
`(a * R) * (b * R) * R^-1 = (a * b) * R mod Q`.
203+
- Operands must be in `eval` form (`lhs_form == rhs_form == out_form == eval`).
204+
}];
205+
}
206+
102207
#endif // LIB_DIALECT_CHEDDARGPU_IR_CHEDDARGPU_OPS_TD_

‎lib/Dialect/CheddarGPU/IR/CheddarGPUTraits.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ LogicalResult verifyLimbRangesWithin(Operation* op) {
7373

7474
if (failed(checkRange(0, "out_limb_range"))) return failure();
7575
if (failed(checkRange(1, "lhs_limb_range"))) return failure();
76+
if (failed(checkRange(1, "in_limb_range"))) return failure();
7677
if (failed(checkRange(2, "rhs_limb_range"))) return failure();
7778

7879
if (auto numAuxAttr = op->getAttrOfType<IntegerAttr>("num_aux")) {

‎tests/Dialect/CheddarGPU/IR/binary_ops.mlir‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,26 @@ module attributes {
3131
return
3232
}
3333

34+
// CHECK: @test_sub
35+
func.func @test_sub(%out: memref<4x65536xi32>, %lhs: memref<4x65536xi32>, %rhs: memref<4x65536xi32>) {
36+
// CHECK: cheddar_gpu.sub %{{.*}}, %{{.*}}, %{{.*}} <{{.*}}lhs_form = eval{{.*}}> : memref<4x65536xi32>
37+
cheddar_gpu.sub %out, %lhs, %rhs <{
38+
lhs_form = #cheddar_gpu.form<eval>,
39+
rhs_form = #cheddar_gpu.form<eval>,
40+
out_form = #cheddar_gpu.form<eval>
41+
}> : memref<4x65536xi32>
42+
return
43+
}
44+
45+
// CHECK: @test_mul
46+
func.func @test_mul(%out: memref<4x65536xi32>, %lhs: memref<4x65536xi32>, %rhs: memref<4x65536xi32>) {
47+
// CHECK: cheddar_gpu.mul %{{.*}}, %{{.*}}, %{{.*}} <{{.*}}lhs_form = eval{{.*}}> : memref<4x65536xi32>
48+
cheddar_gpu.mul %out, %lhs, %rhs <{
49+
lhs_form = #cheddar_gpu.form<eval>,
50+
rhs_form = #cheddar_gpu.form<eval>,
51+
out_form = #cheddar_gpu.form<eval>
52+
}> : memref<4x65536xi32>
53+
return
54+
}
55+
3456
}

‎tests/Dialect/CheddarGPU/IR/binary_verifier.mlir‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,15 @@ func.func @test_num_aux_oob(%out: memref<4x65536xi32>, %lhs: memref<4x65536xi32>
7171
}> : memref<4x65536xi32>
7272
return
7373
}
74+
// -----
75+
// Mul with coeff operand (requires eval)
76+
77+
func.func @test_mul_with_coeff(%out: memref<4x65536xi32>, %lhs: memref<4x65536xi32>, %rhs: memref<4x65536xi32>) {
78+
// expected-error @below {{failed to verify that {lhs_form, rhs_form, out_form} are 'eval'}}
79+
cheddar_gpu.mul %out, %lhs, %rhs <{
80+
lhs_form = #cheddar_gpu.form<coeff>,
81+
rhs_form = #cheddar_gpu.form<eval>,
82+
out_form = #cheddar_gpu.form<eval>
83+
}> : memref<4x65536xi32>
84+
return
85+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: heir-opt --verify-roundtrip %s | FileCheck %s
2+
3+
// CHECK: module attributes
4+
// CHECK-SAME: cheddar_gpu.params = #cheddar_gpu.params<word = 32, log_n = 16, ter = [1000], main = [2000, 3000], aux = [4000], level_config = {{.*}}, alpha = 1, dnum = 0>
5+
module attributes {
6+
cheddar_gpu.params = #cheddar_gpu.params<word = 32, log_n = 16, ter = [1000], main = [2000, 3000], aux = [4000], level_config = [[[2 : i32, 1 : i32]]], alpha = 1, dnum = 0>
7+
} {
8+
9+
// CHECK: @test_neg
10+
func.func @test_neg(%out: memref<4x65536xi32>, %in: memref<4x65536xi32>) {
11+
// CHECK: cheddar_gpu.neg %{{.*}}, %{{.*}} <{{.*}}in_form = eval{{.*}}> : memref<4x65536xi32>
12+
cheddar_gpu.neg %out, %in <{
13+
in_form = #cheddar_gpu.form<eval>,
14+
out_form = #cheddar_gpu.form<eval>
15+
}> : memref<4x65536xi32>
16+
return
17+
}
18+
19+
}

0 commit comments

Comments
 (0)