Skip to content

Commit 9ce1990

Browse files
wtd2copybara-github
authored andcommitted
feat: optimize matmul periodic replication by using maximal valid prefix.
Replaces the single-period replication with a dynamically calculated maximal valid prefix (the actual uncorrupted output slots before replication). The replication period is therefore based on the valid prefix. PiperOrigin-RevId: 954675675
1 parent f23b772 commit 9ce1990

10 files changed

Lines changed: 69 additions & 33 deletions

File tree

lib/Kernel/BicyclicDiagonalMatmulFuzzTest.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,11 @@ std::vector<std::vector<int>> runDiagonalMatmul(bool isCtPt,
7474

7575
auto resultLayout = getBicyclicLayoutRelation(
7676
RankedTensorType::get({m, p}, mlir::IndexType::get(&context)), numSlots);
77-
// Restrict the unpacking to the first output period.
77+
// Restrict the unpacking to the reach-derived valid prefix.
78+
int64_t validPrefix = numSlots - period * (steps - 1);
7879
addBounds(resultLayout,
7980
resultLayout.getVarKindOffset(presburger::VarKind::Range) + 1, 0,
80-
m * p - 1);
81+
validPrefix - 1);
8182
return unpackLayoutToMatrix<int>(resultLayout, {resultVec}, {m, p});
8283
}
8384

lib/Kernel/BicyclicMatmulFuzzTest.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,11 @@ std::vector<std::vector<int>> runBicyclicMatmul(const std::vector<int>& vecA,
5555

5656
auto resultLayout = getBicyclicLayoutRelation(
5757
RankedTensorType::get({m, p}, mlir::IndexType::get(&context)), numSlots);
58-
// Restrict the unpacking to the first output period.
58+
// Restrict the unpacking to the reach-derived valid prefix.
59+
int64_t validPrefix = numSlots - (n * p - 1 + m * (n - 1));
5960
addBounds(resultLayout,
6061
resultLayout.getVarKindOffset(presburger::VarKind::Range) + 1, 0,
61-
m * p - 1);
62+
validPrefix - 1);
6263
return unpackLayoutToMatrix<int>(resultLayout, {resultVec}, {m, p});
6364
}
6465

lib/Kernel/TricyclicBatchMatmulFuzzTest.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,11 @@ void tricyclicBatchMatmulMatchesNaive(
6868
RankedTensorType resultType =
6969
RankedTensorType::get({h, m, p}, mlir::IndexType::get(&context));
7070
auto resultLayout = getTricyclicLayoutRelation(resultType, numSlots);
71-
// Restrict the unpacking to the first output period.
71+
// Restrict the unpacking to the reach-derived valid prefix.
72+
int64_t validPrefix = numSlots - (h * n * p - 1 + h * m * (n - 1));
7273
addBounds(resultLayout,
7374
resultLayout.getVarKindOffset(presburger::VarKind::Range) + 1, 0,
74-
h * m * p - 1);
75+
validPrefix - 1);
7576
auto actual =
7677
unpackLayoutTo3DTensor<int>(resultLayout, {actualVec}, {h, m, p});
7778

lib/Transforms/ConvertToCiphertextSemantics/ConvertToCiphertextSemantics.cpp

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -155,16 +155,20 @@ Operation* remapAndExtractResult(ImplicitLocOpBuilder& builder, Value input,
155155
return extractRemap;
156156
}
157157

158-
// Rebuilds the full periodic layout of a kernel's output from its first valid
159-
// period. Assumes the first period is uncorrupted by wrap-around bounds.
160-
Operation* replicateFirstPeriodOfResult(ImplicitLocOpBuilder& b, Value input,
158+
// Rebuilds the full periodic layout of a kernel's output from the valid prefix
159+
// of the periodic pattern. Greedily replicates the valid periodic prefix of the
160+
// layout until the all of the slot count is covered.
161+
Operation* replicateValidPrefixOfResult(ImplicitLocOpBuilder& b, Value input,
161162
LayoutAttr resultLayout,
162-
int64_t period) {
163+
int64_t inputPeriod,
164+
int64_t validPrefix) {
163165
auto ctSemanticType = cast<RankedTensorType>(input.getType());
164166
int64_t numCiphertexts = ctSemanticType.getDimSize(0);
165167
int64_t numSlots = ctSemanticType.getDimSize(1);
166-
IntegerRelation replication =
167-
getPeriodicReplicationRelation(numCiphertexts, numSlots, period);
168+
int64_t actualValidPrefix =
169+
validPrefix > 0 ? (validPrefix / inputPeriod) * inputPeriod : 0;
170+
IntegerRelation replication = getPeriodicReplicationRelation(
171+
numCiphertexts, numSlots, actualValidPrefix);
168172
LayoutAttr replicationMapping =
169173
LayoutAttr::getFromIntegerRelation(b.getContext(), replication);
170174
auto remapOp = tensor_ext::RemapOp::create(b, input, replicationMapping);
@@ -2825,12 +2829,20 @@ struct ConvertLinalgMatmul
28252829
addBias->setAttr(kLayoutAttrName, layoutAttr);
28262830
setMaterializedAttr(addBias);
28272831

2828-
// Rebuild the full periodic output layout from the first period.
2832+
// Rebuild the full periodic output layout from the widest valid
2833+
// period-aligned window. The rotation reach of rotate-and-reduce with
2834+
// `steps` iterations of stride `period` is period * (steps - 1).
28292835
auto dataSemanticResultType =
28302836
cast<RankedTensorType>(op->getResult(0).getType());
2831-
Operation* replicated =
2832-
replicateFirstPeriodOfResult(b, addBias->getResult(0), layoutAttr,
2833-
dataSemanticResultType.getNumElements());
2837+
int64_t reach = period * (steps - 1);
2838+
auto ctSemanticResultType =
2839+
cast<RankedTensorType>(addBias->getResult(0).getType());
2840+
int64_t validPrefix = ctSemanticResultType.getDimSize(1) - reach;
2841+
LLVM_DEBUG(llvm::dbgs() << "Bicyclic diagonal matmul valid prefix: "
2842+
<< validPrefix << "\n");
2843+
Operation* replicated = replicateValidPrefixOfResult(
2844+
b, addBias->getResult(0), layoutAttr,
2845+
dataSemanticResultType.getNumElements(), validPrefix);
28342846
setMaterializedAttr(replicated);
28352847
rewriter.replaceOp(op, replicated);
28362848
}
@@ -2882,12 +2894,23 @@ struct ConvertLinalgMatmul
28822894
addBias->setAttr(kLayoutAttrName, layoutAttr);
28832895
setMaterializedAttr(addBias);
28842896

2885-
// Rebuild the full periodic output layout from the first period.
2897+
// Rebuild the full periodic output layout from the widest valid
2898+
// period-aligned window. For (m x n) * (n x p), the BSGS rotation reach
2899+
// is n * p - 1 + m * (n - 1).
28862900
auto dataSemanticResultType =
28872901
cast<RankedTensorType>(op->getResult(0).getType());
2888-
Operation* replicated =
2889-
replicateFirstPeriodOfResult(b, addBias->getResult(0), layoutAttr,
2890-
dataSemanticResultType.getNumElements());
2902+
int64_t m = lhsType.getDimSize(0);
2903+
int64_t n = lhsType.getDimSize(1);
2904+
int64_t p = rhsType.getDimSize(1);
2905+
int64_t reach = n * p - 1 + m * (n - 1);
2906+
auto ctSemanticResultType =
2907+
cast<RankedTensorType>(addBias->getResult(0).getType());
2908+
int64_t validPrefix = ctSemanticResultType.getDimSize(1) - reach;
2909+
LLVM_DEBUG(llvm::dbgs()
2910+
<< "Bicyclic matmul valid prefix: " << validPrefix << "\n");
2911+
Operation* replicated = replicateValidPrefixOfResult(
2912+
b, addBias->getResult(0), layoutAttr,
2913+
dataSemanticResultType.getNumElements(), validPrefix);
28912914
setMaterializedAttr(replicated);
28922915
rewriter.replaceOp(op, replicated);
28932916
}
@@ -2968,12 +2991,24 @@ struct ConvertLinalgBatchMatmul
29682991
addBias->setAttr(kLayoutAttrName, layoutAttr);
29692992
setMaterializedAttr(addBias);
29702993

2971-
// Rebuild the full periodic output layout from the first period.
2994+
// Rebuild the full periodic output layout from the widest valid
2995+
// period-aligned window. For (h x m x n) * (h x n x p), the BSGS rotation
2996+
// reach is h * n * p - 1 + h * m * (n - 1).
29722997
auto dataSemanticResultType =
29732998
cast<RankedTensorType>(op->getResult(0).getType());
2974-
Operation* replicated =
2975-
replicateFirstPeriodOfResult(b, addBias->getResult(0), layoutAttr,
2976-
dataSemanticResultType.getNumElements());
2999+
int64_t h = lhsType.getShape()[0];
3000+
int64_t m = lhsType.getShape()[1];
3001+
int64_t n = lhsType.getShape()[2];
3002+
int64_t p = rhsType.getShape()[2];
3003+
int64_t reach = h * n * p - 1 + h * m * (n - 1);
3004+
auto ctSemanticResultType =
3005+
cast<RankedTensorType>(addBias->getResult(0).getType());
3006+
int64_t validPrefix = ctSemanticResultType.getDimSize(1) - reach;
3007+
LLVM_DEBUG(llvm::dbgs() << "Tricyclic batch matmul valid prefix: "
3008+
<< validPrefix << "\n");
3009+
Operation* replicated = replicateValidPrefixOfResult(
3010+
b, addBias->getResult(0), layoutAttr,
3011+
dataSemanticResultType.getNumElements(), validPrefix);
29773012
setMaterializedAttr(replicated);
29783013
rewriter.replaceOp(op, replicated);
29793014
}

tests/Examples/openfhe/ckks/batch_matmul/BUILD

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@ package(default_applicable_licenses = ["@heir//:license"])
44

55
openfhe_end_to_end_test(
66
name = "batch_matmul_test",
7-
size = "medium",
87
generated_lib_header = "batch_matmul_lib.h",
98
heir_opt_flags = [
109
"--annotate-module=backend=openfhe scheme=ckks",
11-
"--mlir-to-ckks=min-slot-count=4096 experimental-disable-loop-unroll=true greedy-level-budget=40 first-mod-bits=60 scaling-mod-bits=50 greedy-bootstrap-waterline=20",
10+
"--mlir-to-ckks=min-slot-count=4096 experimental-disable-loop-unroll=true greedy-level-budget=40 first-mod-bits=60 scaling-mod-bits=50",
1211
"--scheme-to-openfhe",
1312
],
1413
mlir_src = "@heir//tests/Examples/common:batch_matmul.mlir",

tests/Examples/openfhe/ckks/bicyclic_matmul/BUILD

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ package(default_applicable_licenses = ["@heir//:license"])
44

55
openfhe_end_to_end_test(
66
name = "bicyclic_matmul_test",
7-
size = "medium",
87
generated_lib_header = "bicyclic_matmul_lib.h",
98
heir_opt_flags = [
109
"--annotate-module=backend=openfhe scheme=ckks",

tests/Examples/openfhe/ckks/bicyclic_matmul_pt/BUILD

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ package(default_applicable_licenses = ["@heir//:license"])
44

55
openfhe_end_to_end_test(
66
name = "bicyclic_matmul_pt_test",
7-
size = "medium",
87
generated_lib_header = "bicyclic_matmul_pt_lib.h",
98
heir_opt_flags = [
109
"--annotate-module=backend=openfhe scheme=ckks",

tests/Transforms/convert_to_ciphertext_semantics/batch_matmul.mlir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#layout2 = #tensor_ext.layout<"{ [i0, i1, i2] -> [ct, slot] : ct = 0 and (399i0 - 210i1 - 190i2 + slot) mod 798 = 0 and 0 <= i0 <= 1 and 0 <= i1 <= 18 and 0 <= i2 <= 20 and 0 <= slot <= 8191 }">
66
#layout3 = #tensor_ext.layout<"{ [i0, i1, i2] -> [ct, slot] : ct = 0 and (-323i0 - 19i1 - i2 + slot) mod 1024 = 0 and 0 <= i0 <= 1 and 0 <= i1 <= 16 and 0 <= i2 <= 8191 - 323i0 - 19i1 and i2 <= 18 and 0 <= slot <= 8191 and 8192*floor((-1024 + 323i0 + 19i1 + i2)/8192) <= -8192 + 323i0 + 19i1 + i2 }">
77
module {
8-
// CHECK: #[[replication:layout[0-9]*]] = #tensor_ext.layout<"{ [i0, i1] -> [ct, slot] : i0 = 0 and ct = 0 and (-i1 + slot) mod 714 = 0 and 0 <= i1 <= 713 and 0 <= slot <= 8191 }">
8+
// CHECK: #[[replication:layout[0-9]*]] = #tensor_ext.layout<"{ [i0, i1] -> [ct, slot] : i0 = 0 and ct = 0 and (-i1 + slot) mod 6426 = 0 and 0 <= i1 <= 6425 and 0 <= slot <= 8191 }">
99
// CHECK: @batch_matmul_secret_secret
1010
// CHECK-NOT: linalg.batch_matmul
1111
// CHECK: tensor_ext.remap

tests/Transforms/convert_to_ciphertext_semantics/matmul.mlir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#layout2 = #tensor_ext.layout<"{ [i0, i1] -> [ct, slot] : ct = 0 and (4i0 + 5i1 + slot) mod 10 = 0 and 0 <= i0 <= 4 and 0 <= i1 <= 1 and 0 <= slot <= 1023 }">
66
#layout3 = #tensor_ext.layout<"{ [i0, i1] -> [ct, slot] : ct = 0 and (-5i0 - i1 + slot) mod 16 = 0 and 0 <= i0 <= 2 and 0 <= i1 <= 1023 - 5i0 and i1 <= 4 and 0 <= slot <= 1023 and 1024*floor((-16 + 5i0 + i1)/1024) <= -1024 + 5i0 + i1 }">
77
module {
8-
// CHECK: #[[replication:layout[0-9]*]] = #tensor_ext.layout<"{ [i0, i1] -> [ct, slot] : i0 = 0 and ct = 0 and (-i1 + slot) mod 6 = 0 and 0 <= i1 <= 5 and 0 <= slot <= 1023 }">
8+
// CHECK: #[[replication:layout[0-9]*]] = #tensor_ext.layout<"{ [i0, i1] -> [ct, slot] : i0 = 0 and ct = 0 and (-i1 + slot) mod 1002 = 0 and 0 <= i1 <= 1001 and 0 <= slot <= 1023 }">
99
// CHECK: @matmul_secret_secret
1010
// CHECK-NOT: linalg.matmul
1111
// CHECK: tensor_ext.remap

tests/Transforms/convert_to_ciphertext_semantics/matmul_pt.mlir

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@
1010
#layout_ct2 = #tensor_ext.layout<"{ [i0, i1] -> [ct, slot] : ct = 0 and (14i0 - 15i1 + slot) mod 35 = 0 and 0 <= i0 <= 4 and 0 <= i1 <= 6 and 0 <= slot <= 63 }">
1111

1212
module {
13-
// CHECK: #[[replication:layout[0-9]*]] = #tensor_ext.layout<"{ [i0, i1] -> [ct, slot] : i0 = 0 and ct = 0 and (-i1 + slot) mod 21 = 0 and 0 <= i1 <= 20 and 0 <= slot <= 1023 }">
13+
// CHECK: #[[replication1:layout[0-9]*]] = #tensor_ext.layout<"{ [i0, i1] -> [ct, slot] : i0 = 0 and ct = 0 and (-i1 + slot) mod 1008 = 0 and 0 <= i1 <= 1007 and 0 <= slot <= 1023 }">
14+
// CHECK: #[[replication2:layout[0-9]*]] = #tensor_ext.layout<"{ [i0, i1] -> [ct, slot] : i0 = 0 and ct = 0 and (-i1 + slot) mod 987 = 0 and 0 <= i1 <= 986 and 0 <= slot <= 1023 }">
1415

1516
// CHECK: @matmul_ctpt
1617
// CHECK-NOT: linalg.matmul
1718
// CHECK: tensor_ext.rotate
1819
// CHECK: arith.mulf
1920
// CHECK: tensor_ext.remap
20-
// CHECK-SAME: permutation = #[[replication]]
21+
// CHECK-SAME: permutation = #[[replication1]]
2122
func.func @matmul_ctpt(%arg0: !secret.secret<tensor<3x5xf32>> {tensor_ext.layout = #layout_ct}, %arg1: tensor<5x7xf32>) -> (!secret.secret<tensor<3x7xf32>> {tensor_ext.layout = #layout_out}) {
2223
%cst = arith.constant dense<0.000000e+00> : tensor<3x7xf32>
2324
%0 = secret.generic(%arg0: !secret.secret<tensor<3x5xf32>> {tensor_ext.layout = #layout_ct}) {
@@ -35,7 +36,7 @@ module {
3536
// CHECK: tensor_ext.rotate
3637
// CHECK: arith.mulf
3738
// CHECK: tensor_ext.remap
38-
// CHECK-SAME: permutation = #[[replication]]
39+
// CHECK-SAME: permutation = #[[replication2]]
3940
func.func @matmul_ptct(%arg0: tensor<3x5xf32>, %arg1: !secret.secret<tensor<5x7xf32>> {tensor_ext.layout = #layout_ct2}) -> (!secret.secret<tensor<3x7xf32>> {tensor_ext.layout = #layout_out}) {
4041
%cst = arith.constant dense<0.000000e+00> : tensor<3x7xf32>
4142
%0 = secret.generic(%arg1: !secret.secret<tensor<5x7xf32>> {tensor_ext.layout = #layout_ct2}) {

0 commit comments

Comments
 (0)