Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Frontend clang compilation error: redefinition of 'v2_filled' #1621

Open
asraa opened this issue Mar 25, 2025 · 5 comments
Open

Frontend clang compilation error: redefinition of 'v2_filled' #1621

asraa opened this issue Mar 25, 2025 · 5 comments
Labels
dialect: openfhe Issues related to the openfhe dialect

Comments

@asraa
Copy link
Collaborator

asraa commented Mar 25, 2025

I got a really strange error from the openfhe backend:

Traceback (most recent call last):
  File "/usr/local/google/home/asraa/git/heir/frontend/conditional_test.py", line 11, in test_cond
    @compile(debug=True)
     ^^^^^^^^^^^^^^^^^^^
  File "/usr/local/google/home/asraa/git/heir/frontend/heir/pipeline.py", line 223, in decorator
    return run_pipeline(
           ^^^^^^^^^^^^^
  File "/usr/local/google/home/asraa/git/heir/frontend/heir/pipeline.py", line 159, in run_pipeline
    result = backend.run_backend(
             ^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/google/home/asraa/git/heir/frontend/heir/backends/openfhe/backend.py", line 267, in run_backend
    clang_backend.compile_to_shared_object(
  File "/usr/local/google/home/asraa/git/heir/frontend/heir/backends/util/clang.py", line 102, in compile_to_shared_object
    raise ValueError(message)
ValueError: Error running /usr/lib/llvm-19/bin/clang. stderr was:

/tmp/tmp7em30otb/cond.cpp:49:8: error: redefinition of 'v2_filled_n'
   49 |   auto v2_filled_n = cc->GetCryptoParameters()->GetElementParams()->GetRingDimension() / 2;
      |        ^
/tmp/tmp7em30otb/cond.cpp:16:8: note: previous definition is here
   16 |   auto v2_filled_n = cc->GetCryptoParameters()->GetElementParams()->GetRingDimension() / 2;
      |        ^
/tmp/tmp7em30otb/cond.cpp:50:8: error: redefinition of 'v2_filled'
   50 |   auto v2_filled = v2;
      |        ^
/tmp/tmp7em30otb/cond.cpp:17:8: note: previous definition is here
   17 |   auto v2_filled = v2;
      |        ^
2 errors generated.


options were:

/usr/lib/llvm-19/bin/clang /tmp/tmp7em30otb/cond.cpp -o /tmp/tmp7em30otb/cond.so -O3 -fPIC -shared -std=c++17 -I/usr/local/include/openfhe -I/usr/local/include/openfhe/binfhe -I/usr/local/include/openfhe/core -I/usr/local/include/openfhe/pke -L/usr/local/lib -lOPENFHEbinfhe -lOPENFHEcore -lOPENFHEpke

----------------------------------------------------------------------
Ran 1 test in 4.666s

The code it was trying to compile did use v2_filled twice, but within two separate function scopes: https://gist.github.com/asraa/5d85f3243e97d6732b3385b1b0c76de5

So that makes me think maybe some options or something needs to change with the call to compile?

@asraa
Copy link
Collaborator Author

asraa commented Mar 25, 2025

Hah nevermind they are in the same function scope!! It's just two uses of that value.

I feel like this extra filling code should be done at the openfhe IR level so we can CSE it away instead of the emitter.

@asraa
Copy link
Collaborator Author

asraa commented Mar 25, 2025

Here was the backend MLIR

!Z1073750017_i64 = !mod_arith.int<1073750017 : i64>
!Z65537_i64 = !mod_arith.int<65537 : i64>
!Z67239937_i64 = !mod_arith.int<67239937 : i64>
!cc = !openfhe.crypto_context
!params = !openfhe.cc_params
!pk = !openfhe.public_key
!sk = !openfhe.private_key
#full_crt_packing_encoding = #lwe.full_crt_packing_encoding<scaling_factor = 0>
#key = #lwe.key<>
#modulus_chain_L1_C0 = #lwe.modulus_chain<elements = <67239937 : i64, 1073750017 : i64>, current = 0>
#modulus_chain_L1_C1 = #lwe.modulus_chain<elements = <67239937 : i64, 1073750017 : i64>, current = 1>
!rns_L0 = !rns.rns<!Z67239937_i64>
!rns_L1 = !rns.rns<!Z67239937_i64, !Z1073750017_i64>
#ring_Z65537_i64_1_x1024 = #polynomial.ring<coefficientType = !Z65537_i64, polynomialModulus = <1 + x**1024>>
#ring_rns_L0_1_x1024 = #polynomial.ring<coefficientType = !rns_L0, polynomialModulus = <1 + x**1024>>
#ring_rns_L1_1_x1024 = #polynomial.ring<coefficientType = !rns_L1, polynomialModulus = <1 + x**1024>>
!pt = !lwe.new_lwe_plaintext<application_data = <message_type = i1>, plaintext_space = <ring = #ring_Z65537_i64_1_x1024, encoding = #full_crt_packing_encoding>>
!pt1 = !lwe.new_lwe_plaintext<application_data = <message_type = i64>, plaintext_space = <ring = #ring_Z65537_i64_1_x1024, encoding = #full_crt_packing_encoding>>
#ciphertext_space_L0 = #lwe.ciphertext_space<ring = #ring_rns_L0_1_x1024, encryption_type = lsb>
#ciphertext_space_L1 = #lwe.ciphertext_space<ring = #ring_rns_L1_1_x1024, encryption_type = lsb>
!ct_L0 = !lwe.new_lwe_ciphertext<application_data = <message_type = i64>, plaintext_space = <ring = #ring_Z65537_i64_1_x1024, encoding = #full_crt_packing_encoding>, ciphertext_space = #ciphertext_space_L0, key = #key, modulus_chain = #modulus_chain_L1_C0>
!ct_L1 = !lwe.new_lwe_ciphertext<application_data = <message_type = i1>, plaintext_space = <ring = #ring_Z65537_i64_1_x1024, encoding = #full_crt_packing_encoding>, ciphertext_space = #ciphertext_space_L1, key = #key, modulus_chain = #modulus_chain_L1_C1>
!ct_L1_1 = !lwe.new_lwe_ciphertext<application_data = <message_type = i64>, plaintext_space = <ring = #ring_Z65537_i64_1_x1024, encoding = #full_crt_packing_encoding>, ciphertext_space = #ciphertext_space_L1, key = #key, modulus_chain = #modulus_chain_L1_C1>
module attributes {scheme.bgv} {
  func.func @cond(%cc: !cc, %arg0: i64, %arg1: i64, %ct: !ct_L1) -> !ct_L0 {
    %cst = arith.constant dense<1> : tensor<1024xi64>
    %pt = openfhe.make_packed_plaintext %cc, %cst : (!cc, tensor<1024xi64>) -> !pt
    %ct_0 = openfhe.negate %cc, %ct : (!cc, !ct_L1) -> !ct_L1
    %ct_1 = openfhe.add_plain %cc, %ct_0, %pt : (!cc, !ct_L1, !pt) -> !ct_L1
    %ct_2 = lwe.reinterpret_application_data %ct : !ct_L1 to !ct_L1_1
    %splat = tensor.splat %arg0 : tensor<1024xi64>
    %pt_3 = openfhe.make_packed_plaintext %cc, %splat : (!cc, tensor<1024xi64>) -> !pt1
    %ct_4 = openfhe.mul_plain %cc, %ct_2, %pt_3 : (!cc, !ct_L1_1, !pt1) -> !ct_L1_1
    %ct_5 = lwe.reinterpret_application_data %ct_1 : !ct_L1 to !ct_L1_1
    %splat_6 = tensor.splat %arg1 : tensor<1024xi64>
    %pt_7 = openfhe.make_packed_plaintext %cc, %splat_6 : (!cc, tensor<1024xi64>) -> !pt1
    %ct_8 = openfhe.mul_plain %cc, %ct_5, %pt_7 : (!cc, !ct_L1_1, !pt1) -> !ct_L1_1
    %ct_9 = openfhe.add %cc, %ct_4, %ct_8 : (!cc, !ct_L1_1, !ct_L1_1) -> !ct_L1_1
    %pt_10 = openfhe.make_packed_plaintext %cc, %cst : (!cc, tensor<1024xi64>) -> !pt1
    %ct_11 = openfhe.add_plain %cc, %ct_9, %pt_10 : (!cc, !ct_L1_1, !pt1) -> !ct_L1_1
    %ct_12 = openfhe.mod_reduce %cc, %ct_11 : (!cc, !ct_L1_1) -> !ct_L0
    return %ct_12 : !ct_L0
  }
  func.func @cond__encrypt__arg2(%cc: !cc, %arg0: i1, %pk: !pk) -> !ct_L1 {
    %splat = tensor.splat %arg0 : tensor<1024xi1>
    %0 = arith.extui %splat : tensor<1024xi1> to tensor<1024xi64>
    %pt = openfhe.make_packed_plaintext %cc, %0 : (!cc, tensor<1024xi64>) -> !pt
    %ct = openfhe.encrypt %cc, %pt, %pk : (!cc, !pt, !pk) -> !ct_L1
    return %ct : !ct_L1
  }
  func.func @cond__decrypt__result0(%cc: !cc, %ct: !ct_L0, %sk: !sk) -> i64 {
    %pt = openfhe.decrypt %cc, %ct, %sk : (!cc, !ct_L0, !sk) -> !pt1
    %0 = lwe.rlwe_decode %pt {encoding = #full_crt_packing_encoding, ring = #ring_Z65537_i64_1_x1024} : !pt1 -> i64
    return %0 : i64
  }
  func.func @cond__generate_crypto_context() -> !cc {
    %params = openfhe.gen_params  {encryptionTechniqueExtended = false, evalAddCount = 2 : i64, insecure = false, keySwitchCount = 0 : i64, mulDepth = 1 : i64, plainMod = 65537 : i64} : () -> !params
    %cc = openfhe.gen_context %params {supportFHE = false} : (!params) -> !cc
    return %cc : !cc
  }
  func.func @cond__configure_crypto_context(%cc: !cc, %sk: !sk) -> !cc {
    return %cc : !cc
  }
}

So it seems that the plaintext was generated with two different levels.

@AlexanderViand-Intel
Copy link
Collaborator

AlexanderViand-Intel commented Mar 25, 2025

I feel like this extra filling code should be done at the openfhe IR level so we can CSE it away instead of the emitter.

+1
Beyond CSE/avoiding this bug, I'm interested in hoisting any application data -> plaintext conversion code outside the function (i.e.,rewriting the function to take in pt2 and pt3 instead, and adding make_pt2 and make_pt3 client side functions, and having this stuff happen in the IR rather than in the emitter seems like it'd make that easier :)

@ZenithalHourlyRate
Copy link
Collaborator

v2_filled exists purely out of the need of implicit cyclic repetition assumption. With the layout packing pass making it obvious, such variable should vanish one day.

@ZenithalHourlyRate
Copy link
Collaborator

auto packedName =
getName(op.getValue()) + "_" + getName(op.getPlaintext()) + "_packed";

A workaround is specifying both the pt and target ct in the name to make it unique.

@AlexanderViand-Intel AlexanderViand-Intel added the dialect: openfhe Issues related to the openfhe dialect label Mar 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dialect: openfhe Issues related to the openfhe dialect
Projects
None yet
Development

No branches or pull requests

3 participants