diff --git a/compiler/lib/Conversion/LowLFHEToConcreteCAPI/LowLFHEToConcreteCAPI.cpp b/compiler/lib/Conversion/LowLFHEToConcreteCAPI/LowLFHEToConcreteCAPI.cpp index 9a0c6efe7..6f31cece7 100644 --- a/compiler/lib/Conversion/LowLFHEToConcreteCAPI/LowLFHEToConcreteCAPI.cpp +++ b/compiler/lib/Conversion/LowLFHEToConcreteCAPI/LowLFHEToConcreteCAPI.cpp @@ -215,6 +215,407 @@ struct LowLFHEIntToCleartextOpPattern }; }; +struct GlweFromTableOpPattern + : public mlir::OpRewritePattern { + GlweFromTableOpPattern(mlir::MLIRContext *context, + mlir::PatternBenefit benefit = 1) + : mlir::OpRewritePattern( + context, benefit) {} + + mlir::LogicalResult + matchAndRewrite(mlir::zamalang::LowLFHE::GlweFromTable op, + mlir::PatternRewriter &rewriter) const override { + LowLFHEToConcreteCAPITypeConverter typeConverter; + auto errType = + mlir::MemRefType::get({}, mlir::IndexType::get(rewriter.getContext())); + // Insert forward declaration of the alloc_glwe function + { + auto funcType = mlir::FunctionType::get( + rewriter.getContext(), + { + errType, + mlir::IntegerType::get(rewriter.getContext(), 32), + mlir::IntegerType::get(rewriter.getContext(), 32), + }, + {mlir::zamalang::LowLFHE::GlweCiphertextType::get( + rewriter.getContext())}); + if (insertForwardDeclaration(op, rewriter, "allocate_glwe_ciphertext_u64", + funcType) + .failed()) { + return mlir::failure(); + } + } + // Insert forward declaration of the alloc_plaintext_list function + { + auto funcType = mlir::FunctionType::get( + rewriter.getContext(), + {errType, mlir::IntegerType::get(rewriter.getContext(), 32)}, + {mlir::zamalang::LowLFHE::PlaintextListType::get( + rewriter.getContext())}); + if (insertForwardDeclaration(op, rewriter, "allocate_plaintext_list_u64", + funcType) + .failed()) { + return mlir::failure(); + } + } + + // Insert forward declaration of the foregin_pt_list function + { + auto funcType = mlir::FunctionType::get( + rewriter.getContext(), + {errType, + // mlir::UnrankedTensorType::get( + // mlir::IntegerType::get(rewriter.getContext(), 64)), + op->getOperandTypes().front(), + mlir::IntegerType::get(rewriter.getContext(), 64)}, + {mlir::zamalang::LowLFHE::ForeignPlaintextListType::get( + rewriter.getContext())}); + if (insertForwardDeclaration(op, rewriter, "foreign_plaintext_list_u64", + funcType) + .failed()) { + return mlir::failure(); + } + } + + // Insert forward declaration of the fill_plaintext_list function + { + auto funcType = mlir::FunctionType::get( + rewriter.getContext(), + {errType, + mlir::zamalang::LowLFHE::PlaintextListType::get( + rewriter.getContext()), + mlir::zamalang::LowLFHE::ForeignPlaintextListType::get( + rewriter.getContext())}, + {}); + if (insertForwardDeclaration( + op, rewriter, "fill_plaintext_list_with_expansion_u64", funcType) + .failed()) { + return mlir::failure(); + } + } + + // Insert forward declaration of the add_plaintext_list_glwe function + { + auto funcType = mlir::FunctionType::get( + rewriter.getContext(), + {errType, + mlir::zamalang::LowLFHE::GlweCiphertextType::get( + rewriter.getContext()), + mlir::zamalang::LowLFHE::GlweCiphertextType::get( + rewriter.getContext()), + mlir::zamalang::LowLFHE::PlaintextListType::get( + rewriter.getContext())}, + {}); + if (insertForwardDeclaration( + op, rewriter, "add_plaintext_list_glwe_ciphertext_u64", funcType) + .failed()) { + return mlir::failure(); + } + } + auto errOp = rewriter.create(op.getLoc(), errType); + // allocate two glwe to build accumulator + auto glweSizeOp = + rewriter.create(op.getLoc(), op->getAttr("k")); + auto polySizeOp = rewriter.create( + op.getLoc(), op->getAttr("polynomialSize")); + mlir::SmallVector allocGlweOperands{errOp, glweSizeOp, + polySizeOp}; + // first accumulator would replace the op since it's the returned value + auto accumulatorOp = rewriter.replaceOpWithNewOp( + op, "allocate_glwe_ciphertext_u64", + mlir::zamalang::LowLFHE::GlweCiphertextType::get(rewriter.getContext()), + allocGlweOperands); + // second accumulator is just needed to build the actual accumulator + auto _accumulatorOp = rewriter.create( + op.getLoc(), "allocate_glwe_ciphertext_u64", + mlir::zamalang::LowLFHE::GlweCiphertextType::get(rewriter.getContext()), + allocGlweOperands); + // allocate plaintext list + mlir::SmallVector allocPlaintextListOperands{errOp, + polySizeOp}; + auto plaintextListOp = rewriter.create( + op.getLoc(), "allocate_plaintext_list_u64", + mlir::zamalang::LowLFHE::PlaintextListType::get(rewriter.getContext()), + allocPlaintextListOperands); + // create foreign plaintext + auto rankedTensorType = + op->getOperandTypes().front().cast(); + if (rankedTensorType.getRank() != 1) { + llvm::errs() << "table lookup must be of a single dimension"; + return mlir::failure(); + } + auto sizeOp = rewriter.create( + op.getLoc(), rewriter.getIntegerAttr( + mlir::IntegerType::get(rewriter.getContext(), 64), + rankedTensorType.getDimSize(0))); + mlir::SmallVector ForeignPlaintextListOperands{ + errOp, op->getOperand(0), sizeOp}; + auto foreignPlaintextListOp = rewriter.create( + op.getLoc(), "foreign_plaintext_list_u64", + mlir::zamalang::LowLFHE::ForeignPlaintextListType::get( + rewriter.getContext()), + ForeignPlaintextListOperands); + // fill plaintext list + mlir::SmallVector FillPlaintextListOperands{ + errOp, plaintextListOp.getResult(0), + foreignPlaintextListOp.getResult(0)}; + rewriter.create( + op.getLoc(), "fill_plaintext_list_with_expansion_u64", + mlir::TypeRange({}), FillPlaintextListOperands); + // add plaintext list and glwe to build final accumulator for pbs + mlir::SmallVector AddPlaintextListGlweOperands{ + errOp, accumulatorOp.getResult(0), _accumulatorOp.getResult(0), + plaintextListOp.getResult(0)}; + rewriter.create( + op.getLoc(), "add_plaintext_list_glwe_ciphertext_u64", + mlir::TypeRange({}), AddPlaintextListGlweOperands); + return mlir::success(); + }; +}; + +// TODO: +// Parameterization +// Get concrete key +struct LowLFHEBootstrapLweOpPattern + : public mlir::OpRewritePattern { + LowLFHEBootstrapLweOpPattern(mlir::MLIRContext *context, + mlir::PatternBenefit benefit = 1) + : mlir::OpRewritePattern( + context, benefit) {} + + mlir::LogicalResult + matchAndRewrite(mlir::zamalang::LowLFHE::BootstrapLweOp op, + mlir::PatternRewriter &rewriter) const override { + auto errType = + mlir::MemRefType::get({}, mlir::IndexType::get(rewriter.getContext())); + auto lweOperandType = op->getOperandTypes().front(); + // Insert forward declaration of the allocate_bsk_key function + { + auto funcType = mlir::FunctionType::get( + rewriter.getContext(), + { + errType, + // level + mlir::IntegerType::get(rewriter.getContext(), 32), + // baselog + mlir::IntegerType::get(rewriter.getContext(), 32), + // glwe size + mlir::IntegerType::get(rewriter.getContext(), 32), + // lwe size + mlir::IntegerType::get(rewriter.getContext(), 32), + // polynomial size + mlir::IntegerType::get(rewriter.getContext(), 32), + }, + {mlir::zamalang::LowLFHE::LweBootstrapKeyType::get( + rewriter.getContext())}); + if (insertForwardDeclaration(op, rewriter, + "allocate_lwe_bootstrap_key_u64", funcType) + .failed()) { + return mlir::failure(); + } + } + // Insert forward declaration of the allocate_lwe_ct function + { + auto funcType = mlir::FunctionType::get( + rewriter.getContext(), + { + errType, + mlir::IntegerType::get(rewriter.getContext(), 32), + }, + {lweOperandType}); + if (insertForwardDeclaration(op, rewriter, "allocate_lwe_ciphertext_u64", + funcType) + .failed()) { + return mlir::failure(); + } + } + // Insert forward declaration of the bootstrap function + { + auto funcType = mlir::FunctionType::get( + rewriter.getContext(), + { + errType, + mlir::zamalang::LowLFHE::LweBootstrapKeyType::get( + rewriter.getContext()), + lweOperandType, + lweOperandType, + mlir::zamalang::LowLFHE::GlweCiphertextType::get( + rewriter.getContext()), + }, + {}); + if (insertForwardDeclaration(op, rewriter, "bootstrap_lwe_u64", funcType) + .failed()) { + return mlir::failure(); + } + } + + auto errOp = rewriter.create(op.getLoc(), errType); + // allocate the result lwe ciphertext + auto lweSizeOp = rewriter.create( + op.getLoc(), + mlir::IntegerAttr::get( + mlir::IntegerType::get(rewriter.getContext(), 32), -1)); + mlir::SmallVector allocLweCtOperands{errOp, lweSizeOp}; + auto allocateLweCtOp = rewriter.replaceOpWithNewOp( + op, "allocate_lwe_ciphertext_u64", lweOperandType, allocLweCtOperands); + // allocate bsk + auto decompLevelCountOp = rewriter.create( + op.getLoc(), + mlir::IntegerAttr::get( + mlir::IntegerType::get(rewriter.getContext(), 32), -1)); + auto decompBaseLogOp = rewriter.create( + op.getLoc(), + mlir::IntegerAttr::get( + mlir::IntegerType::get(rewriter.getContext(), 32), -1)); + auto glweSizeOp = rewriter.create( + op.getLoc(), + mlir::IntegerAttr::get( + mlir::IntegerType::get(rewriter.getContext(), 32), -1)); + auto polySizeOp = rewriter.create( + op.getLoc(), + mlir::IntegerAttr::get( + mlir::IntegerType::get(rewriter.getContext(), 32), -1)); + mlir::SmallVector allocBskOperands{ + errOp, decompLevelCountOp, decompBaseLogOp, + glweSizeOp, lweSizeOp, polySizeOp}; + auto allocateBskOp = rewriter.create( + op.getLoc(), "allocate_lwe_bootstrap_key_u64", + mlir::zamalang::LowLFHE::LweBootstrapKeyType::get( + rewriter.getContext()), + allocBskOperands); + // bootstrap + mlir::SmallVector bootstrapOperands{ + errOp, allocateBskOp.getResult(0), allocateLweCtOp.getResult(0), + op->getOperand(0), op->getOperand(1)}; + rewriter.create(op.getLoc(), "bootstrap_lwe_u64", + mlir::TypeRange({}), bootstrapOperands); + + return mlir::success(); + }; +}; + +// TODO: +// Parameterization +// Get concrete key +struct LowLFHEKeySwitchLweOpPattern + : public mlir::OpRewritePattern { + LowLFHEKeySwitchLweOpPattern(mlir::MLIRContext *context, + mlir::PatternBenefit benefit = 1) + : mlir::OpRewritePattern( + context, benefit) {} + + mlir::LogicalResult + matchAndRewrite(mlir::zamalang::LowLFHE::KeySwitchLweOp op, + mlir::PatternRewriter &rewriter) const override { + auto errType = + mlir::MemRefType::get({}, mlir::IndexType::get(rewriter.getContext())); + auto lweOperandType = op->getOperandTypes().front(); + // Insert forward declaration of the allocate_bsk_key function + { + auto funcType = mlir::FunctionType::get( + rewriter.getContext(), + { + errType, + // level + mlir::IntegerType::get(rewriter.getContext(), 32), + // baselog + mlir::IntegerType::get(rewriter.getContext(), 32), + // input lwe size + mlir::IntegerType::get(rewriter.getContext(), 32), + // output lwe size + mlir::IntegerType::get(rewriter.getContext(), 32), + }, + {mlir::zamalang::LowLFHE::LweKeySwitchKeyType::get( + rewriter.getContext())}); + if (insertForwardDeclaration(op, rewriter, + "allocate_lwe_keyswitch_key_u64", funcType) + .failed()) { + return mlir::failure(); + } + } + // Insert forward declaration of the allocate_lwe_ct function + { + auto funcType = mlir::FunctionType::get( + rewriter.getContext(), + { + errType, + mlir::IntegerType::get(rewriter.getContext(), 32), + }, + {lweOperandType}); + if (insertForwardDeclaration(op, rewriter, "allocate_lwe_ciphertext_u64", + funcType) + .failed()) { + return mlir::failure(); + } + } + // TODO: build the right type here + auto lweOutputType = lweOperandType; + // Insert forward declaration of the keyswitch function + { + auto funcType = mlir::FunctionType::get( + rewriter.getContext(), + { + errType, + // ksk + mlir::zamalang::LowLFHE::LweKeySwitchKeyType::get( + rewriter.getContext()), + // output ct + lweOutputType, + // input ct + lweOperandType, + }, + {}); + if (insertForwardDeclaration(op, rewriter, "keyswitch_lwe_u64", funcType) + .failed()) { + return mlir::failure(); + } + } + + auto errOp = rewriter.create(op.getLoc(), errType); + // allocate the result lwe ciphertext + auto lweSizeOp = rewriter.create( + op.getLoc(), + mlir::IntegerAttr::get( + mlir::IntegerType::get(rewriter.getContext(), 32), -1)); + mlir::SmallVector allocLweCtOperands{errOp, lweSizeOp}; + auto allocateLweCtOp = rewriter.replaceOpWithNewOp( + op, "allocate_lwe_ciphertext_u64", lweOutputType, allocLweCtOperands); + // allocate ksk + auto decompLevelCountOp = rewriter.create( + op.getLoc(), + mlir::IntegerAttr::get( + mlir::IntegerType::get(rewriter.getContext(), 32), -1)); + auto decompBaseLogOp = rewriter.create( + op.getLoc(), + mlir::IntegerAttr::get( + mlir::IntegerType::get(rewriter.getContext(), 32), -1)); + auto inputLweSizeOp = rewriter.create( + op.getLoc(), + mlir::IntegerAttr::get( + mlir::IntegerType::get(rewriter.getContext(), 32), -1)); + auto outputLweSizeOp = rewriter.create( + op.getLoc(), + mlir::IntegerAttr::get( + mlir::IntegerType::get(rewriter.getContext(), 32), -1)); + mlir::SmallVector allockskOperands{ + errOp, decompLevelCountOp, decompBaseLogOp, inputLweSizeOp, + outputLweSizeOp}; + auto allocateKskOp = rewriter.create( + op.getLoc(), "allocate_lwe_keyswitch_key_u64", + mlir::zamalang::LowLFHE::LweKeySwitchKeyType::get( + rewriter.getContext()), + allockskOperands); + // bootstrap + mlir::SmallVector bootstrapOperands{ + errOp, allocateKskOp.getResult(0), allocateLweCtOp.getResult(0), + op->getOperand(0)}; + rewriter.create(op.getLoc(), "keyswitch_lwe_u64", + mlir::TypeRange({}), bootstrapOperands); + + return mlir::success(); + }; +}; + /// Populate the RewritePatternSet with all patterns that rewrite LowLFHE /// operators to the corresponding function call to the `Concrete C API`. void populateLowLFHEToConcreteCAPICall(mlir::RewritePatternSet &patterns) { @@ -237,6 +638,9 @@ void populateLowLFHEToConcreteCAPICall(mlir::RewritePatternSet &patterns) { patterns.add(patterns.getContext()); patterns.add(patterns.getContext()); patterns.add(patterns.getContext()); + patterns.add(patterns.getContext()); + patterns.add(patterns.getContext()); + patterns.add(patterns.getContext()); } namespace { diff --git a/compiler/tests/Conversion/LowLFHEToConcreteCAPI/bootstrap.mlir b/compiler/tests/Conversion/LowLFHEToConcreteCAPI/bootstrap.mlir new file mode 100644 index 000000000..14e69ff99 --- /dev/null +++ b/compiler/tests/Conversion/LowLFHEToConcreteCAPI/bootstrap.mlir @@ -0,0 +1,21 @@ +// RUN: zamacompiler --passes lowlfhe-to-concrete-c-api %s 2>&1| FileCheck %s + +// CHECK-LABEL: module +// CHECK-NEXT: func private @bootstrap_lwe_u64(memref, !LowLFHE.lwe_bootstrap_key, !LowLFHE.lwe_ciphertext<1024,4>, !LowLFHE.lwe_ciphertext<1024,4>, !LowLFHE.glwe_ciphertext) +// CHECK-NEXT: func private @allocate_lwe_ciphertext_u64(memref, i32) -> !LowLFHE.lwe_ciphertext<1024,4> +// CHECK-NEXT: func private @allocate_lwe_bootstrap_key_u64(memref, i32, i32, i32, i32, i32) -> !LowLFHE.lwe_bootstrap_key +// CHECK-LABEL: func @bootstrap_lwe(%arg0: !LowLFHE.lwe_ciphertext<1024,4>, %arg1: !LowLFHE.glwe_ciphertext) -> !LowLFHE.lwe_ciphertext<1024,4> +func @bootstrap_lwe(%arg0: !LowLFHE.lwe_ciphertext<1024,4>, %arg1: !LowLFHE.glwe_ciphertext) -> !LowLFHE.lwe_ciphertext<1024,4> { + // CHECK-NEXT: %[[V0:.*]] = memref.alloca() : memref + // CHECK-NEXT: %[[C0:.*]] = constant -1 : i32 + // CHECK-NEXT: %[[V1:.*]] = call @allocate_lwe_ciphertext_u64(%[[V0]], %[[C0]]) : (memref, i32) -> !LowLFHE.lwe_ciphertext<1024,4> + // CHECK-NEXT: %[[C1:.*]] = constant -1 : i32 + // CHECK-NEXT: %[[C2:.*]] = constant -1 : i32 + // CHECK-NEXT: %[[C3:.*]] = constant -1 : i32 + // CHECK-NEXT: %[[C4:.*]] = constant -1 : i32 + // CHECK-NEXT: %[[V2:.*]] = call @allocate_lwe_bootstrap_key_u64(%0, %[[C1]], %[[C2]], %[[C3]], %[[C0]], %[[C4]]) : (memref, i32, i32, i32, i32, i32) -> !LowLFHE.lwe_bootstrap_key + // CHECK-NEXT: call @bootstrap_lwe_u64(%[[V0]], %[[V2]], %[[V1]], %arg0, %arg1) : (memref, !LowLFHE.lwe_bootstrap_key, !LowLFHE.lwe_ciphertext<1024,4>, !LowLFHE.lwe_ciphertext<1024,4>, !LowLFHE.glwe_ciphertext) -> () + // CHECK-NEXT: return %[[V1]] : !LowLFHE.lwe_ciphertext<1024,4> + %1 = "LowLFHE.bootstrap_lwe"(%arg0, %arg1) : (!LowLFHE.lwe_ciphertext<1024,4>, !LowLFHE.glwe_ciphertext) -> !LowLFHE.lwe_ciphertext<1024,4> + return %1: !LowLFHE.lwe_ciphertext<1024,4> +} \ No newline at end of file diff --git a/compiler/tests/Conversion/LowLFHEToConcreteCAPI/glwe_from_table.mlir b/compiler/tests/Conversion/LowLFHEToConcreteCAPI/glwe_from_table.mlir new file mode 100644 index 000000000..2b8f7b353 --- /dev/null +++ b/compiler/tests/Conversion/LowLFHEToConcreteCAPI/glwe_from_table.mlir @@ -0,0 +1,24 @@ +// RUN: zamacompiler --passes lowlfhe-to-concrete-c-api %s 2>&1| FileCheck %s + +// CHECK-LABEL: module +// CHECK-NEXT: func private @add_plaintext_list_glwe_ciphertext_u64(memref, !LowLFHE.glwe_ciphertext, !LowLFHE.glwe_ciphertext, !LowLFHE.plaintext_list) +// CHECK-NEXT: func private @fill_plaintext_list_with_expansion_u64(memref, !LowLFHE.plaintext_list, !LowLFHE.foreign_plaintext_list) +// CHECK-NEXT: func private @foreign_plaintext_list_u64(memref, tensor<16xi4>, i64) -> !LowLFHE.foreign_plaintext_list +// CHECK-NEXT: func private @allocate_plaintext_list_u64(memref, i32) -> !LowLFHE.plaintext_list +// CHECK-NEXT: func private @allocate_glwe_ciphertext_u64(memref, i32, i32) -> !LowLFHE.glwe_ciphertext +// CHECK-LABEL: func @glwe_from_table(%arg0: tensor<16xi4>) -> !LowLFHE.glwe_ciphertext +func @glwe_from_table(%arg0: tensor<16xi4>) -> !LowLFHE.glwe_ciphertext { + // CHECK-NEXT: %[[V0:.*]] = memref.alloca() : memref + // CHECK-NEXT: %[[C0:.*]] = constant 1 : i32 + // CHECK-NEXT: %[[C1:.*]] = constant 1024 : i32 + // CHECK-NEXT: %[[V1:.*]] = call @allocate_glwe_ciphertext_u64(%[[V0]], %[[C0]], %[[C1]]) : (memref, i32, i32) -> !LowLFHE.glwe_ciphertext + // CHECK-NEXT: %[[V2:.*]] = call @allocate_glwe_ciphertext_u64(%[[V0]], %[[C0]], %[[C1]]) : (memref, i32, i32) -> !LowLFHE.glwe_ciphertext + // CHECK-NEXT: %[[V3:.*]] = call @allocate_plaintext_list_u64(%[[V0]], %[[C1]]) : (memref, i32) -> !LowLFHE.plaintext_list + // CHECK-NEXT: %[[C2:.*]] = constant 16 : i64 + // CHECK-NEXT: %[[V4:.*]] = call @foreign_plaintext_list_u64(%[[V0]], %arg0, %[[C2]]) : (memref, tensor<16xi4>, i64) -> !LowLFHE.foreign_plaintext_list + // CHECK-NEXT: call @fill_plaintext_list_with_expansion_u64(%[[V0]], %[[V3]], %[[V4]]) : (memref, !LowLFHE.plaintext_list, !LowLFHE.foreign_plaintext_list) -> () + // CHECK-NEXT: call @add_plaintext_list_glwe_ciphertext_u64(%[[V0]], %[[V1]], %[[V2]], %[[V3]]) : (memref, !LowLFHE.glwe_ciphertext, !LowLFHE.glwe_ciphertext, !LowLFHE.plaintext_list) -> () + // CHECK-NEXT: return %[[V1]] : !LowLFHE.glwe_ciphertext + %1 = "LowLFHE.glwe_from_table"(%arg0) {k = 1 : i32, polynomialSize = 1024 : i32} : (tensor<16xi4>) -> !LowLFHE.glwe_ciphertext + return %1: !LowLFHE.glwe_ciphertext +} \ No newline at end of file diff --git a/compiler/tests/Conversion/LowLFHEToConcreteCAPI/keyswitch_lwe.mlir b/compiler/tests/Conversion/LowLFHEToConcreteCAPI/keyswitch_lwe.mlir new file mode 100644 index 000000000..f93d03c76 --- /dev/null +++ b/compiler/tests/Conversion/LowLFHEToConcreteCAPI/keyswitch_lwe.mlir @@ -0,0 +1,21 @@ +// RUN: zamacompiler --passes lowlfhe-to-concrete-c-api %s 2>&1| FileCheck %s + +// CHECK-LABEL: module +// CHECK-NEXT: func private @keyswitch_lwe_u64(memref, !LowLFHE.lwe_key_switch_key, !LowLFHE.lwe_ciphertext<1024,4>, !LowLFHE.lwe_ciphertext<1024,4>) +// CHECK-NEXT: func private @allocate_lwe_ciphertext_u64(memref, i32) -> !LowLFHE.lwe_ciphertext<1024,4> +// CHECK-NEXT: func private @allocate_lwe_keyswitch_key_u64(memref, i32, i32, i32, i32) -> !LowLFHE.lwe_key_switch_key +// CHECK-LABEL: func @keyswitch_lwe(%arg0: !LowLFHE.lwe_ciphertext<1024,4>) -> !LowLFHE.lwe_ciphertext<1024,4> +func @keyswitch_lwe(%arg0: !LowLFHE.lwe_ciphertext<1024,4>) -> !LowLFHE.lwe_ciphertext<1024,4> { + // CHECK-NEXT: %[[V0:.*]] = memref.alloca() : memref + // CHECK-NEXT: %[[C0:.*]] = constant -1 : i32 + // CHECK-NEXT: %[[V1:.*]] = call @allocate_lwe_ciphertext_u64(%[[V0]], %[[C0]]) : (memref, i32) -> !LowLFHE.lwe_ciphertext<1024,4> + // CHECK-NEXT: %[[C1:.*]] = constant -1 : i32 + // CHECK-NEXT: %[[C2:.*]] = constant -1 : i32 + // CHECK-NEXT: %[[C3:.*]] = constant -1 : i32 + // CHECK-NEXT: %[[C4:.*]] = constant -1 : i32 + // CHECK-NEXT: %[[V2:.*]] = call @allocate_lwe_keyswitch_key_u64(%0, %[[C1]], %[[C2]], %[[C3]], %[[C4]]) : (memref, i32, i32, i32, i32) -> !LowLFHE.lwe_key_switch_key + // CHECK-NEXT: call @keyswitch_lwe_u64(%[[V0]], %[[V2]], %[[V1]], %arg0) : (memref, !LowLFHE.lwe_key_switch_key, !LowLFHE.lwe_ciphertext<1024,4>, !LowLFHE.lwe_ciphertext<1024,4>) -> () + // CHECK-NEXT: return %[[V1]] : !LowLFHE.lwe_ciphertext<1024,4> + %1 = "LowLFHE.keyswitch_lwe"(%arg0) : (!LowLFHE.lwe_ciphertext<1024,4>) -> !LowLFHE.lwe_ciphertext<1024,4> + return %1: !LowLFHE.lwe_ciphertext<1024,4> +} \ No newline at end of file