Skip to content

Commit 51fe193

Browse files
asraacopybara-github
authored andcommitted
level analysis: make levelBudget optional in levelanalysis
This makes the default levelBudget = 40 entirely optional and removes that constraint. In level Analysis, if the level > levelBudget it turns the level invalid. For most of the patterns, we don't want a level to become invalid since we use the level analysis for checking level convergence. The invalid state can trigger patterns into thinking that a loop is non level invariant, and trigger bootstrap insertions. I'm not even sure we need a level budget at all in level analysis, but I wanted to preserve the option. PiperOrigin-RevId: 953514357
1 parent 9253765 commit 51fe193

3 files changed

Lines changed: 76 additions & 3 deletions

File tree

lib/Analysis/LevelAnalysis/LevelAnalysis.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ LogicalResult LevelAnalysis::visitOperation(
128128
};
129129

130130
LevelState resultLevel = deriveResultLevel(op, operands);
131-
if (resultLevel.isInt() && resultLevel.getInt() > levelBudget) {
131+
if (resultLevel.isInt() && levelBudget.has_value() &&
132+
resultLevel.getInt() > levelBudget) {
132133
resultLevel = LevelState(Invalid{});
133134
}
134135
for (auto result : op->getOpResults()) {

lib/Analysis/LevelAnalysis/LevelAnalysis.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,8 @@ class LevelAnalysis
193193
: public dataflow::SparseForwardDataFlowAnalysis<LevelLattice>,
194194
public SecretnessAnalysisDependent<LevelAnalysis> {
195195
public:
196-
LevelAnalysis(DataFlowSolver& solver, int levelBudget = 40)
196+
LevelAnalysis(DataFlowSolver& solver,
197+
std::optional<int> levelBudget = std::nullopt)
197198
: dataflow::SparseForwardDataFlowAnalysis<LevelLattice>(solver),
198199
levelBudget(levelBudget) {}
199200
friend class SecretnessAnalysisDependent<LevelAnalysis>;
@@ -215,7 +216,7 @@ class LevelAnalysis
215216
}
216217

217218
private:
218-
int levelBudget;
219+
std::optional<int> levelBudget;
219220
};
220221

221222
LevelState deriveResultLevel(Operation* op,
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// RUN: heir-opt --secret-insert-mgmt-ckks --debug-only=level-analysis %s 2>&1 | FileCheck %s
2+
3+
// Ensure that bootstrapping is not applied to the secret tensor in the loop.
4+
5+
module attributes {backend.lattigo, scheme.ckks} {
6+
// CHECK: func.func @test_lenet_slice_loop
7+
// CHECK: scf.for
8+
// CHECK-NOT: mgmt.bootstrap
9+
// CHECK: scf.yield
10+
func.func @test_lenet_slice_loop(%ct_input: !secret.secret<tensor<1x8192xf32>>) -> !secret.secret<tensor<12x8192xf32>> {
11+
%c0 = arith.constant 0 : index
12+
%c1 = arith.constant 1 : index
13+
%c12 = arith.constant 12 : index
14+
15+
%res = secret.generic(%ct_input: !secret.secret<tensor<1x8192xf32>>) {
16+
^body(%input: tensor<1x8192xf32>):
17+
%empty = tensor.empty() : tensor<12x8192xf32>
18+
19+
%1 = arith.mulf %input, %input : tensor<1x8192xf32>
20+
%2 = arith.mulf %1, %1 : tensor<1x8192xf32>
21+
%3 = arith.mulf %2, %2 : tensor<1x8192xf32>
22+
%4 = arith.mulf %3, %3 : tensor<1x8192xf32>
23+
%5 = arith.mulf %4, %4 : tensor<1x8192xf32>
24+
%6 = arith.mulf %5, %5 : tensor<1x8192xf32>
25+
%7 = arith.mulf %6, %6 : tensor<1x8192xf32>
26+
%8 = arith.mulf %7, %7 : tensor<1x8192xf32>
27+
%9 = arith.mulf %8, %8 : tensor<1x8192xf32>
28+
%10 = arith.mulf %9, %9 : tensor<1x8192xf32>
29+
%11 = arith.mulf %10, %10 : tensor<1x8192xf32>
30+
%12 = arith.mulf %11, %11 : tensor<1x8192xf32>
31+
%13 = arith.mulf %12, %12 : tensor<1x8192xf32>
32+
%14 = arith.mulf %13, %13 : tensor<1x8192xf32>
33+
%15 = arith.mulf %14, %14 : tensor<1x8192xf32>
34+
%16 = arith.mulf %15, %15 : tensor<1x8192xf32>
35+
%17 = arith.mulf %16, %16 : tensor<1x8192xf32>
36+
%18 = arith.mulf %17, %17 : tensor<1x8192xf32>
37+
%19 = arith.mulf %18, %18 : tensor<1x8192xf32>
38+
%20 = arith.mulf %19, %19 : tensor<1x8192xf32>
39+
%21 = arith.mulf %20, %20 : tensor<1x8192xf32>
40+
%22 = arith.mulf %21, %21 : tensor<1x8192xf32>
41+
%23 = arith.mulf %22, %22 : tensor<1x8192xf32>
42+
%24 = arith.mulf %23, %23 : tensor<1x8192xf32>
43+
%25 = arith.mulf %24, %24 : tensor<1x8192xf32>
44+
%26 = arith.mulf %25, %25 : tensor<1x8192xf32>
45+
%27 = arith.mulf %26, %26 : tensor<1x8192xf32>
46+
%28 = arith.mulf %27, %27 : tensor<1x8192xf32>
47+
%29 = arith.mulf %28, %28 : tensor<1x8192xf32>
48+
%30 = arith.mulf %29, %29 : tensor<1x8192xf32>
49+
%31 = arith.mulf %30, %30 : tensor<1x8192xf32>
50+
%32 = arith.mulf %31, %31 : tensor<1x8192xf32>
51+
%33 = arith.mulf %32, %32 : tensor<1x8192xf32>
52+
%34 = arith.mulf %33, %33 : tensor<1x8192xf32>
53+
%35 = arith.mulf %34, %34 : tensor<1x8192xf32>
54+
%36 = arith.mulf %35, %35 : tensor<1x8192xf32>
55+
%37 = arith.mulf %36, %36 : tensor<1x8192xf32>
56+
%38 = arith.mulf %37, %37 : tensor<1x8192xf32>
57+
%39 = arith.mulf %38, %38 : tensor<1x8192xf32>
58+
%40 = arith.mulf %39, %39 : tensor<1x8192xf32>
59+
%41 = arith.mulf %40, %40 : tensor<1x8192xf32>
60+
61+
%loop = scf.for %idx = %c0 to %c12 step %c1 iter_args(%acc = %empty) -> (tensor<12x8192xf32>) {
62+
%rot = tensor_ext.rotate %41, %idx : tensor<1x8192xf32>, index
63+
%inserted = tensor.insert_slice %rot into %acc[%idx, 0] [1, 8192] [1, 1] : tensor<1x8192xf32> into tensor<12x8192xf32>
64+
scf.yield %inserted : tensor<12x8192xf32>
65+
}
66+
secret.yield %loop : tensor<12x8192xf32>
67+
} -> !secret.secret<tensor<12x8192xf32>>
68+
69+
return %res : !secret.secret<tensor<12x8192xf32>>
70+
}
71+
}

0 commit comments

Comments
 (0)