Skip to content

Commit 521c0a9

Browse files
enable OpenMP for OpenFHE & python backend
1 parent 1006b8b commit 521c0a9

File tree

5 files changed

+39
-43
lines changed

5 files changed

+39
-43
lines changed

BUILD.bazel

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ package_group(
2828
# OpenMP
2929
string_flag(
3030
name = "enable_openmp",
31-
# TODO(#1361): re-enable when it's compatible with the Python frontend
32-
build_setting_default = "0",
31+
build_setting_default = "1",
3332
)
3433

3534
config_setting(

docs/content/en/docs/getting_started.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ heir-translate --help
4242

4343
- [Git](https://git-scm.com/)
4444
- A C++ compiler and linker ([clang](https://clang.llvm.org/) and
45-
[lld](https://lld.llvm.org/) or a recent version of `gcc`).
45+
[lld](https://lld.llvm.org/) or a recent version of `gcc`). If you want to run
46+
OpenFHE with parallelism (enabled by default), you'll also need OpenMP.
4647
- Bazel via [bazelisk](https://github.com/bazelbuild/bazelisk). The precise
4748
Bazel version used is in `.bazelversion` in the repository root.
4849

@@ -53,7 +54,7 @@ heir-translate --help
5354
For example, on Ubuntu, these can be installed with
5455

5556
```bash
56-
sudo apt-get update && sudo apt-get install clang lld
57+
sudo apt-get update && sudo apt-get install clang lld libomp-dev
5758
```
5859

5960
You can download the latest Bazelisk release, e.g., for linux-amd64 (see the

lib/Target/OpenFhePke/OpenFhePkeTemplates.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,13 @@ PYBIND11_MODULE({0}, m) {{
109109
)cpp";
110110
// clang-format on
111111

112-
constexpr std::string_view kPybindFunctionTemplate = "m.def(\"{0}\", &{0});";
112+
// Emit a pybind11 binding that releases the GIL for the duration of the C++
113+
// function call. This enables multi-threaded C++ code (e.g. OpenMP parallel
114+
// regions inside OpenFHE) to run concurrently with the Python interpreter.
115+
// The `py::call_guard<py::gil_scoped_release>()` helper ensures the GIL is
116+
// relinquished on entry and re-acquired on exit.
117+
constexpr std::string_view kPybindFunctionTemplate =
118+
"m.def(\"{0}\", &{0}, py::call_guard<py::gil_scoped_release>());";
113119

114120
} // namespace openfhe
115121
} // namespace heir

tests/Emitter/Openfhe/emit_pybind.mlir

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@
2828

2929
// CHECK: PYBIND11_MODULE(_heir_foo, m) {
3030
// CHECK: bind_common(m);
31-
// CHECK: m.def("simple_sum", &simple_sum);
32-
// CHECK: m.def("simple_sum__encrypt", &simple_sum__encrypt);
33-
// CHECK: m.def("simple_sum__decrypt", &simple_sum__decrypt);
31+
// CHECK: m.def("simple_sum", &simple_sum, py::call_guard<py::gil_scoped_release>());
32+
// CHECK: m.def("simple_sum__encrypt", &simple_sum__encrypt, py::call_guard<py::gil_scoped_release>());
33+
// CHECK: m.def("simple_sum__decrypt", &simple_sum__decrypt, py::call_guard<py::gil_scoped_release>());
3434
// CHECK: }
3535

3636
!Z1095233372161_i64_ = !mod_arith.int<1095233372161 : i64>

tests/Regression/issue_1929.mlir

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,6 @@
22
// TODO (#1929): Improve test with better CHECKs
33
// TODO (#1641): enable i32-based tests once CKKS pipeline allows integer types
44

5-
// // CHECK: func.func @secret_loop_index_step
6-
// func.func @secret_loop_index_step(%arg0: i32 {secret.secret}, %arg1: i32 {secret.secret}) -> i32 {
7-
// %c0 = arith.constant 0 : index
8-
// %c1 = arith.constant 1 : index
9-
// %c1_i32 = arith.constant 1 : i32
10-
// %0 = arith.index_cast %arg0 : i32 to index
11-
// // CHECK-NOT: scf.for
12-
// // CHECK-NOT: arith.cmpi
13-
// // CHECK-NOT: math_ext.sign
14-
// // CHECK: polynomial.eval
15-
// %1 = scf.for %arg2 = %c0 to %0 step %c1 iter_args(%arg3 = %c1_i32) -> (i32) {
16-
// %2 = arith.muli %arg3, %arg0 : i32
17-
// scf.yield %2 : i32
18-
// } {upper = 6}
19-
// return %1 : i32
20-
// }
21-
22-
// // When scf.for uses a signless integer step, --convert-secret-for-to-static-for would forget to issue arith.index_cast
23-
// // CHECK: func.func @secret_loop_signless_integer_step
24-
// func.func @secret_loop_signless_integer_step(%arg0: i32 {secret.secret}, %arg1: i32 {secret.secret}) -> i32 {
25-
// %c0_i32 = arith.constant 0 : i32
26-
// %c1_i32 = arith.constant 1 : i32
27-
// // CHECK-NOT: scf.for
28-
// // CHECK-NOT: arith.cmpi
29-
// // CHECK-NOT: math_ext.sign
30-
// // CHECK: polynomial.eval
31-
// %1 = scf.for %arg2 = %c0_i32 to %arg0 step %c1_i32 iter_args(%arg3 = %c1_i32) -> (i32) : i32 {
32-
// %2 = arith.muli %arg3, %arg0 : i32
33-
// scf.yield %2 : i32
34-
// } {upper = 6}
35-
// return %1 : i32
36-
// }
37-
385
// CHECK: func.func @float_secret_loop_index_step
396
func.func @float_secret_loop_index_step(%arg0: f32 {secret.secret}, %arg1: f32 {secret.secret}) -> f32 {
407
%c0 = arith.constant 0 : index
@@ -45,7 +12,7 @@ func.func @float_secret_loop_index_step(%arg0: f32 {secret.secret}, %arg1: f32 {
4512
// CHECK-NOT: scf.for
4613
// CHECK-NOT: arith.cmpi
4714
// CHECK-NOT: math_ext.sign
48-
// CHECK: polynomial.eval
15+
// CHECK-NOT: polynomial.eval
4916
%2 = scf.for %arg2 = %c0 to %1 step %c1 iter_args(%arg3 = %c1_f32) -> (f32) {
5017
%2 = arith.mulf %arg3, %arg0 : f32
5118
scf.yield %2 : f32
@@ -63,10 +30,33 @@ func.func @float_secret_loop_signless_integer_step(%arg0: f32 {secret.secret}, %
6330
// CHECK-NOT: scf.for
6431
// CHECK-NOT: arith.cmpi
6532
// CHECK-NOT: math_ext.sign
66-
// CHECK: polynomial.eval
33+
// CHECK-NOT: polynomial.eval
6734
%1 = scf.for %arg2 = %c0_i32 to %0 step %c1_i32 iter_args(%arg3 = %c1_f32) -> (f32) : i32 {
6835
%2 = arith.mulf %arg3, %arg0 : f32
6936
scf.yield %2 : f32
7037
} {upper = 6}
7138
return %1 : f32
7239
}
40+
41+
// func.func @secret_loop_index_step(%arg0: i32 {secret.secret}, %arg1: i32 {secret.secret}) -> i32 {
42+
// %c0 = arith.constant 0 : index
43+
// %c1 = arith.constant 1 : index
44+
// %c1_i32 = arith.constant 1 : i32
45+
// %0 = arith.index_cast %arg0 : i32 to index
46+
// %1 = scf.for %arg2 = %c0 to %0 step %c1 iter_args(%arg3 = %c1_i32) -> (i32) {
47+
// %2 = arith.muli %arg3, %arg0 : i32
48+
// scf.yield %2 : i32
49+
// } {upper = 6}
50+
// return %1 : i32
51+
// }
52+
53+
// // When scf.for uses a signless integer step, --convert-secret-for-to-static-for would forget to issue arith.index_cast
54+
// func.func @secret_loop_signless_integer_step(%arg0: i32 {secret.secret}, %arg1: i32 {secret.secret}) -> i32 {
55+
// %c0_i32 = arith.constant 0 : i32
56+
// %c1_i32 = arith.constant 1 : i32
57+
// %1 = scf.for %arg2 = %c0_i32 to %arg0 step %c1_i32 iter_args(%arg3 = %c1_i32) -> (i32) : i32 {
58+
// %2 = arith.muli %arg3, %arg0 : i32
59+
// scf.yield %2 : i32
60+
// } {upper = 6}
61+
// return %1 : i32
62+
// }

0 commit comments

Comments
 (0)