diff --git a/compiler/include/concretelang/Conversion/FHEToTFHE/Patterns.h b/compiler/include/concretelang/Conversion/FHEToTFHE/Patterns.h index 56b7aac2a..7fbdc81ce 100644 --- a/compiler/include/concretelang/Conversion/FHEToTFHE/Patterns.h +++ b/compiler/include/concretelang/Conversion/FHEToTFHE/Patterns.h @@ -66,36 +66,6 @@ mlir::Value createGLWEOpFromFHE(mlir::PatternRewriter &rewriter, return op.getODSResults(0).front(); } -mlir::Value createApplyLookupTableGLWEOpFromFHE(mlir::PatternRewriter &rewriter, - mlir::Location loc, - mlir::Value arg0, - mlir::Value arg1, - mlir::OpResult result) { - mlir::SmallVector args{arg0, arg1}; - - auto context = rewriter.getContext(); - auto unset = mlir::IntegerAttr::get(IntegerType::get(context, 32), -1); - mlir::SmallVector attrs{ - mlir::NamedAttribute(mlir::Identifier::get("glweDimension", context), - unset), - mlir::NamedAttribute(mlir::Identifier::get("polynomialSize", context), - unset), - mlir::NamedAttribute(mlir::Identifier::get("levelKS", context), unset), - mlir::NamedAttribute(mlir::Identifier::get("baseLogKS", context), unset), - mlir::NamedAttribute(mlir::Identifier::get("levelBS", context), unset), - mlir::NamedAttribute(mlir::Identifier::get("baseLogBS", context), unset), - mlir::NamedAttribute(mlir::Identifier::get("outputSizeKS", context), - unset), - }; - auto eint = - result.getType().cast(); - mlir::SmallVector resTypes{ - convertTypeEncryptedIntegerToGLWE(rewriter.getContext(), eint)}; - auto op = rewriter.create(loc, resTypes, - args, attrs); - return op.getODSResults(0).front(); -} - } // namespace concretelang } // namespace mlir diff --git a/compiler/include/concretelang/Conversion/FHEToTFHE/Patterns.td b/compiler/include/concretelang/Conversion/FHEToTFHE/Patterns.td index 5583b03ef..cecc5bfaf 100644 --- a/compiler/include/concretelang/Conversion/FHEToTFHE/Patterns.td +++ b/compiler/include/concretelang/Conversion/FHEToTFHE/Patterns.td @@ -41,10 +41,4 @@ def MulEintIntPattern : Pat< (MulEintIntOp:$result $arg0, $arg1), (createMulGLWEIntOp $arg0, $arg1, $result)>; -def createApplyLookupTableGLWEOp : NativeCodeCall<"mlir::concretelang::createApplyLookupTableGLWEOpFromFHE($_builder, $_loc, $0, $1, $2)">; - -def ApplyLookupTableEintPattern : Pat< - (ApplyLookupTableEintOp:$result $arg0, $arg1), - (createApplyLookupTableGLWEOp $arg0, $arg1, $result)>; - #endif diff --git a/compiler/include/concretelang/Conversion/TFHEToConcrete/Patterns.h b/compiler/include/concretelang/Conversion/TFHEToConcrete/Patterns.h index aa3eb4bbd..f05c9db15 100644 --- a/compiler/include/concretelang/Conversion/TFHEToConcrete/Patterns.h +++ b/compiler/include/concretelang/Conversion/TFHEToConcrete/Patterns.h @@ -184,110 +184,6 @@ mlir::Value createMulClearLweCiphertext(mlir::PatternRewriter &rewriter, return op.getODSResults(0).front(); } -// This is the rewritting of the FHE::ApplyLookupTable operation, it will be -// rewritten as 3 new operations: -// - Create the required GLWE ciphertext out of the plain lookup table -// - Keyswitch the input ciphertext to match the input key of the bootstrapping -// - Bootstrap the keyswitched ciphertext with the constructed GLWE ciphertext -// Example: -// from: -// ``` -// "%result = TFHE.apply_lookup_table"(% arg0, % tlu){ -// glweDimension = 1 : i32, -// polynomialSize = 2048 : i32, -// levelKS = 3 : i32, -// baseLogKS = 2 : i32, -// levelBS = 5 : i32, -// baseLogBS = 4 : i32, -// outputSizeKS = 600 : i32 -// } : (!TFHE.glwe<{2048, 1, 64} {4}>, tensor<16xi4>) -// ->(!TFHE.glwe<{2048, 1, 64} {4}>) -// ``` -// to: -// ``` -// % accumulator = -// "Concrete.glwe_from_table"( -// % [[TABLE]]){glweDimension = 1 : i32, p = 4 : i32, polynomialSize = -// 2048 : i32} -// : (tensor<16xi4>) -// ->!Concrete.glwe_ciphertext<2048, 1, 4> -// % keyswitched = "Concrete.keyswitch_lwe"(% arg0){ -// baseLog = 2 : i32, -// level = 3 : i32 -// } : (!Concrete.lwe_ciphertext<2048, 4>) -// ->!Concrete.lwe_ciphertext<600, 4> -// % result = "Concrete.bootstrap_lwe"(% keyswitched, % accumulator){ -// baseLog = 4 : i32, -// glweDimension = 1 : i32, -// level = 5 : i32, -// polynomialSize = 2048 : i32 -// } : (!Concrete.lwe_ciphertext<600, 4>, !Concrete.glwe_ciphertext<2048, 1, 4>) -// ->!Concrete.lwe_ciphertext<2048, 4> -// ``` -mlir::Value createPBS(mlir::PatternRewriter &rewriter, mlir::Location loc, - mlir::Value ct, mlir::Value table, - mlir::IntegerAttr glweDimension, - mlir::IntegerAttr polynomialSize, - mlir::IntegerAttr levelKS, mlir::IntegerAttr baseLogKS, - mlir::IntegerAttr levelBS, mlir::IntegerAttr baseLogBS, - mlir::IntegerAttr outputDimensionKS, - mlir::OpResult result) { - // convert result type - LweCiphertextType lwe_type = - convertTypeToLWE(rewriter.getContext(), result.getType()); - // fill the the table in the GLWE accumulator - mlir::IntegerAttr precision = rewriter.getI32IntegerAttr(lwe_type.getP()); - mlir::Value accumulator = - rewriter - .create( - loc, - Concrete::GlweCiphertextType::get( - rewriter.getContext(), polynomialSize.getInt(), - glweDimension.getInt(), lwe_type.getP()), - table) - .result(); - - // keyswitch - mlir::SmallVector ksArgs{ct}; - mlir::SmallVector ksAttrs{ - mlir::NamedAttribute( - mlir::Identifier::get("level", rewriter.getContext()), levelKS), - mlir::NamedAttribute( - mlir::Identifier::get("baseLog", rewriter.getContext()), baseLogKS), - }; - // convert result type - LweCiphertextType ksOutType = LweCiphertextType::get( - rewriter.getContext(), outputDimensionKS.getInt(), precision.getInt()); - convertTypeToLWE(rewriter.getContext(), result.getType()); - mlir::Value keyswitched = - rewriter - .create(loc, ksOutType, - ksArgs, ksAttrs) - .result(); - - // bootstrap operation - mlir::SmallVector bsArgs{keyswitched, accumulator}; - mlir::SmallVector bsAttrs{ - mlir::NamedAttribute( - mlir::Identifier::get("glweDimension", rewriter.getContext()), - glweDimension), - mlir::NamedAttribute( - mlir::Identifier::get("polynomialSize", rewriter.getContext()), - polynomialSize), - mlir::NamedAttribute( - mlir::Identifier::get("level", rewriter.getContext()), levelBS), - mlir::NamedAttribute( - mlir::Identifier::get("baseLog", rewriter.getContext()), baseLogBS), - }; - mlir::Value bootstrapped = - rewriter - .create(loc, lwe_type, - bsArgs, bsAttrs) - .result(); - - return bootstrapped; -} - } // namespace concretelang } // namespace mlir diff --git a/compiler/include/concretelang/Conversion/TFHEToConcrete/Patterns.td b/compiler/include/concretelang/Conversion/TFHEToConcrete/Patterns.td index 405546534..c597ecb1d 100644 --- a/compiler/include/concretelang/Conversion/TFHEToConcrete/Patterns.td +++ b/compiler/include/concretelang/Conversion/TFHEToConcrete/Patterns.td @@ -42,10 +42,4 @@ def NegGLWEPattern : Pat< (NegGLWEOp:$result $arg0), (createNegLweOp $arg0, $result)>; -def createPBS : NativeCodeCall<"mlir::concretelang::createPBS($_builder, $_loc, $0, $1, $2, $3, $4, $5, $6, $7, $8, $9)">; - -def ApplyLookupTableGLWEPattern : Pat< - (ApplyLookupTable:$result $ct, $table, $glweDimension, $polynomialSize, $levelKS, $baseLogKS, $levelBS, $baseLogBS, $outputDimensionKS), - (createPBS $ct, $table, $glweDimension, $polynomialSize, $levelKS, $baseLogKS, $levelBS, $baseLogBS, $outputDimensionKS, $result)>; - #endif diff --git a/compiler/include/concretelang/Conversion/Utils/GenericOpTypeConversionPattern.h b/compiler/include/concretelang/Conversion/Utils/GenericOpTypeConversionPattern.h index edbe6c8c8..2023f8e04 100644 --- a/compiler/include/concretelang/Conversion/Utils/GenericOpTypeConversionPattern.h +++ b/compiler/include/concretelang/Conversion/Utils/GenericOpTypeConversionPattern.h @@ -68,8 +68,8 @@ struct GenericTypeAndOpConverterPattern : public mlir::OpRewritePattern { resultTypes[i] = converter.convertType(result.getType()); } } - rewriter.replaceOpWithNewOp(oldOp, resultTypes, - oldOp->getOperands()); + rewriter.replaceOpWithNewOp(oldOp, resultTypes, oldOp->getOperands(), + oldOp->getAttrs()); return mlir::success(); } diff --git a/compiler/include/concretelang/Dialect/Concrete/IR/ConcreteOps.td b/compiler/include/concretelang/Dialect/Concrete/IR/ConcreteOps.td index 75665c7fd..baa2adf82 100644 --- a/compiler/include/concretelang/Dialect/Concrete/IR/ConcreteOps.td +++ b/compiler/include/concretelang/Dialect/Concrete/IR/ConcreteOps.td @@ -62,9 +62,7 @@ def GlweFromTable : Concrete_Op<"glwe_from_table"> { def BootstrapLweOp : Concrete_Op<"bootstrap_lwe"> { let summary = "Bootstraps a LWE ciphertext with a GLWE trivial encryption of the lookup table"; - let arguments = (ins - // LweBootstrapKeyType:$bootstrap_key, LweCiphertextType:$input_ciphertext, GlweCiphertextType:$accumulator, I32Attr:$glweDimension, @@ -79,7 +77,6 @@ def KeySwitchLweOp : Concrete_Op<"keyswitch_lwe"> { let summary = "Keyswitches a LWE ciphertext"; let arguments = (ins - // LweKeySwitchKeyType:$keyswitch_key, LweCiphertextType:$ciphertext, I32Attr:$level, I32Attr:$baseLog diff --git a/compiler/include/concretelang/Dialect/TFHE/IR/TFHEOps.td b/compiler/include/concretelang/Dialect/TFHE/IR/TFHEOps.td index cb60fae20..94ef42107 100644 --- a/compiler/include/concretelang/Dialect/TFHE/IR/TFHEOps.td +++ b/compiler/include/concretelang/Dialect/TFHE/IR/TFHEOps.td @@ -88,23 +88,37 @@ def MulGLWEIntOp : TFHE_Op<"mul_glwe_int"> { }]; } +def KeySwitchGLWEOp : TFHE_Op<"keyswitch_glwe"> { + let summary = "Change the encryption parameters of a glwe ciphertext by applying a keyswitch"; + let arguments = (ins + GLWECipherTextType:$ciphertext, + I32Attr:$level, + I32Attr:$baseLog + ); -def ApplyLookupTable : TFHE_Op<"apply_lookup_table"> { - let summary = "Applies a lookup table to a GLWE ciphertext"; + let results = (outs GLWECipherTextType:$result); +} - - let arguments = (ins GLWECipherTextType:$ct, - TensorOf<[AnyInteger]>:$l_cst, - I32Attr:$glweDimension, I32Attr:$polynomialSize, - I32Attr:$levelKS, I32Attr:$baseLogKS, - I32Attr:$levelBS, I32Attr:$baseLogBS, - I32Attr:$outputSizeKS); - let results = (outs GLWECipherTextType); +def GLWEFromTableOp : TFHE_Op<"glwe_from_table"> { + let summary = "Creates a GLWE ciphertext which is the trivial encrytion of a the input table interpreted as a polynomial (to use later in a bootstrap)"; - let verifier = [{ - return ::mlir::concretelang::TFHE::verifyApplyLookupTable(*this); - }]; + let arguments = (ins 1DTensorOf<[I64]>:$table); + let results = (outs GLWECipherTextType:$result); +} + +def BootstrapGLWEOp : TFHE_Op<"bootstrap_glwe"> { + let summary = "Programmable bootstraping of a GLWE ciphertext with a lookup table"; + + let arguments = (ins + GLWECipherTextType:$ciphertext, + GLWECipherTextType:$lookup_table, + I32Attr:$glweDimension, + I32Attr:$polynomialSize, + I32Attr:$level, + I32Attr:$baseLog + ); + let results = (outs GLWECipherTextType: $result); } #endif diff --git a/compiler/lib/Conversion/FHEToTFHE/FHEToTFHE.cpp b/compiler/lib/Conversion/FHEToTFHE/FHEToTFHE.cpp index fb713925d..a01b69243 100644 --- a/compiler/lib/Conversion/FHEToTFHE/FHEToTFHE.cpp +++ b/compiler/lib/Conversion/FHEToTFHE/FHEToTFHE.cpp @@ -18,6 +18,9 @@ #include "concretelang/Dialect/TFHE/IR/TFHEDialect.h" #include "concretelang/Dialect/TFHE/IR/TFHETypes.h" +namespace FHE = mlir::concretelang::FHE; +namespace TFHE = mlir::concretelang::TFHE; + namespace { struct FHEToTFHEPass : public FHEToTFHEBase { void runOnOperation() final; @@ -53,6 +56,58 @@ public: } }; +// This rewrite pattern transforms any instance of `FHE.apply_lookup_table` +// operators. +// +// Example: +// +// ```mlir +// %0 = "FHE.apply_lookup_table"(%ct, %lut): (!FHE.eint<2>, tensor<4xi64>) +// ->(!FHE.eint<2>) +// ``` +// +// becomes: +// +// ```mlir +// %glwe_lut = "TFHE.glwe_from_table"(%lut) +// : (tensor<4xi64>) -> !TFHE.glwe<{_,_,_}{2}> +// %glwe_ks = "TFHE.keyswitch_glwe"(%ct) +// {baseLog = -1 : i32, level = -1 : i32} +// : (!TFHE.glwe<{_,_,_}{2}>) -> !TFHE.glwe<{_,_,_}{2}> +// %0 = "TFHE.bootstrap_glwe"(%glwe_ks, %glwe_lut) +// {baseLog = -1 : i32, glweDimension = -1 : i32, level = -1 : i32, +// polynomialSize = -1 : i32} +// : (!TFHE.glwe<{_,_,_}{2}>, !TFHE.glwe<{_,_,_}{2}>) -> +// !TFHE.glwe<{_,_,_}{2}> +// ``` +struct ApplyLookupTableEintOpPattern + : public mlir::OpRewritePattern { + ApplyLookupTableEintOpPattern(mlir::MLIRContext *context, + mlir::PatternBenefit benefit = 1) + : ::mlir::OpRewritePattern(context, + benefit) {} + + ::mlir::LogicalResult + matchAndRewrite(FHE::ApplyLookupTableEintOp lutOp, + mlir::PatternRewriter &rewriter) const override { + FHEToTFHETypeConverter converter; + auto inputTy = converter.convertType(lutOp.a().getType()) + .cast(); + auto resultTy = converter.convertType(lutOp.getType()); + // %glwe_lut = "TFHE.glwe_from_table"(%lut) + auto glweLut = rewriter.create(lutOp.getLoc(), + inputTy, lutOp.lut()); + // %glwe_ks = "TFHE.keyswitch_glwe"(%ct) + auto glweKs = rewriter.create( + lutOp.getLoc(), inputTy, lutOp.a(), -1, -1); + // %0 = "TFHE.bootstrap_glwe"(%glwe_ks, %glwe_lut) + rewriter.replaceOpWithNewOp(lutOp, resultTy, glweKs, + glweLut, -1, -1, -1, -1); + + return ::mlir::success(); + }; +}; + void FHEToTFHEPass::runOnOperation() { auto op = this->getOperation(); @@ -85,6 +140,7 @@ void FHEToTFHEPass::runOnOperation() { mlir::OwningRewritePatternList patterns(&getContext()); populateWithGeneratedFHEToTFHE(patterns); + patterns.add(&getContext()); patterns.add>( &getContext(), converter); diff --git a/compiler/lib/Conversion/TFHEGlobalParametrization/TFHEGlobalParametrization.cpp b/compiler/lib/Conversion/TFHEGlobalParametrization/TFHEGlobalParametrization.cpp index 7f9d1af32..cb406bea2 100644 --- a/compiler/lib/Conversion/TFHEGlobalParametrization/TFHEGlobalParametrization.cpp +++ b/compiler/lib/Conversion/TFHEGlobalParametrization/TFHEGlobalParametrization.cpp @@ -15,6 +15,8 @@ #include "concretelang/Dialect/TFHE/IR/TFHETypes.h" #include "concretelang/Support/Constants.h" +namespace TFHE = mlir::concretelang::TFHE; + namespace { struct TFHEGlobalParametrizationPass : public TFHEGlobalParametrizationBase { @@ -89,91 +91,114 @@ private: mlir::TypeConverter &typeConverter; }; -struct TFHEApplyLookupTableParametrizationPattern - : public mlir::OpRewritePattern< - mlir::concretelang::TFHE::ApplyLookupTable> { - TFHEApplyLookupTableParametrizationPattern( - mlir::MLIRContext *context, mlir::TypeConverter &typeConverter, - mlir::concretelang::V0Parameter &v0Parameter, - mlir::PatternBenefit benefit = - mlir::concretelang::DEFAULT_PATTERN_BENEFIT) - : mlir::OpRewritePattern( - context, benefit), - typeConverter(typeConverter), v0Parameter(v0Parameter) {} +struct KeySwitchGLWEOpPattern + : public mlir::OpRewritePattern { + KeySwitchGLWEOpPattern(mlir::MLIRContext *context, + mlir::TypeConverter &converter, + mlir::concretelang::V0FHEContext &fheContext, + mlir::PatternBenefit benefit = + mlir::concretelang::DEFAULT_PATTERN_BENEFIT) + : mlir::OpRewritePattern(context, benefit), + converter(converter), fheContext(fheContext) {} mlir::LogicalResult - matchAndRewrite(mlir::concretelang::TFHE::ApplyLookupTable op, + matchAndRewrite(TFHE::KeySwitchGLWEOp ksOp, mlir::PatternRewriter &rewriter) const override { mlir::SmallVector newResultTypes; - if (typeConverter.convertTypes(op->getResultTypes(), newResultTypes) - .failed()) { - return mlir::failure(); - } - - mlir::SmallVector newAttributes{ - mlir::NamedAttribute( - rewriter.getIdentifier("glweDimension"), - rewriter.getI32IntegerAttr(v0Parameter.glweDimension)), - mlir::NamedAttribute( - rewriter.getIdentifier("polynomialSize"), - // TODO remove the shift when we have true polynomial size - rewriter.getI32IntegerAttr(1 << v0Parameter.logPolynomialSize)), - mlir::NamedAttribute(rewriter.getIdentifier("levelKS"), - rewriter.getI32IntegerAttr(v0Parameter.ksLevel)), - mlir::NamedAttribute(rewriter.getIdentifier("baseLogKS"), - rewriter.getI32IntegerAttr(v0Parameter.ksLogBase)), - mlir::NamedAttribute(rewriter.getIdentifier("levelBS"), - rewriter.getI32IntegerAttr(v0Parameter.brLevel)), - mlir::NamedAttribute(rewriter.getIdentifier("baseLogBS"), - rewriter.getI32IntegerAttr(v0Parameter.brLogBase)), - mlir::NamedAttribute(rewriter.getIdentifier("outputSizeKS"), - rewriter.getI32IntegerAttr(v0Parameter.nSmall)), - }; - - rewriter.replaceOpWithNewOp( - op, newResultTypes, op->getOperands(), newAttributes); - + auto inputTy = ksOp.ciphertext().getType().cast(); + auto outputTy = rewriter.getType( + fheContext.parameter.glweDimension, fheContext.parameter.nSmall, 64, + inputTy.getP()); + rewriter.replaceOpWithNewOp( + ksOp, outputTy, ksOp.ciphertext(), fheContext.parameter.ksLevel, + fheContext.parameter.ksLogBase); return mlir::success(); }; private: - mlir::TypeConverter &typeConverter; - mlir::concretelang::V0Parameter &v0Parameter; + mlir::TypeConverter &converter; + mlir::concretelang::V0FHEContext &fheContext; }; -struct TFHEApplyLookupTablePaddingPattern - : public mlir::OpRewritePattern< - mlir::concretelang::TFHE::ApplyLookupTable> { - TFHEApplyLookupTablePaddingPattern( - mlir::MLIRContext *context, - mlir::PatternBenefit benefit = - mlir::concretelang::DEFAULT_PATTERN_BENEFIT) - : mlir::OpRewritePattern( - context, benefit) {} +struct BootstrapGLWEOpPattern + : public mlir::OpRewritePattern { + BootstrapGLWEOpPattern(mlir::MLIRContext *context, + mlir::TypeConverter &converter, + mlir::concretelang::V0FHEContext &fheContext, + mlir::PatternBenefit benefit = + mlir::concretelang::DEFAULT_PATTERN_BENEFIT) + : mlir::OpRewritePattern(context, benefit), + converter(converter), fheContext(fheContext) {} mlir::LogicalResult - matchAndRewrite(mlir::concretelang::TFHE::ApplyLookupTable op, + matchAndRewrite(TFHE::BootstrapGLWEOp bsOp, mlir::PatternRewriter &rewriter) const override { - auto glweInType = op.getOperandTypes()[0] - .cast(); - auto tabulatedLambdaType = - op.l_cst().getType().cast(); + rewriter.replaceOpWithNewOp( + bsOp, converter.convertType(bsOp.result().getType()), bsOp.ciphertext(), + bsOp.lookup_table(), fheContext.parameter.glweDimension, + 1 << fheContext.parameter.logPolynomialSize, + fheContext.parameter.brLevel, fheContext.parameter.brLogBase); + return mlir::success(); + }; - auto expectedSize = 1 << glweInType.getP(); - if (tabulatedLambdaType.getShape()[0] < expectedSize) { +private: + mlir::TypeConverter &converter; + mlir::concretelang::V0FHEContext &fheContext; +}; + +// This rewrite pattern transforms any instance of `TFHE.glwe_from_table` by +// parametrize GLWE return type and pad the table if the precision has been +// changed. +// +// Example: +// +// ```mlir +// %lut = arith.constant dense<[0, 1, 2, 3]> : tensor<4xi64> +// %0 = "TFHE.glwe_from_table" (%lut) : (tensor<4xi64>) -> +// !TFHE.glwe<{_,_,_}{2}> +// ``` +// +// becomes: +// +// ```mlir +// %lut = arith.constant dense<[0, 1, 2, 3, 0, 1, 2, 3]> : tensor<8xi64> +// %0 = "TFHE.glwe_from_table" (%lut) : (tensor<8xi64>) -> +// !TFHE.glwe<{_,_,_}{3}> +// ``` +struct GLWEFromTablePattern + : public mlir::OpRewritePattern { + GLWEFromTablePattern(mlir::MLIRContext *context, + mlir::TypeConverter &converter, + mlir::concretelang::V0FHEContext &fheContext, + mlir::PatternBenefit benefit = + mlir::concretelang::DEFAULT_PATTERN_BENEFIT) + : mlir::OpRewritePattern(context, benefit), + converter(converter), fheContext(fheContext) {} + + mlir::LogicalResult + matchAndRewrite(TFHE::GLWEFromTableOp glweOp, + mlir::PatternRewriter &rewriter) const override { + auto newTy = converter.convertType(glweOp.getType()) + .cast(); + + auto lutOp = glweOp.table(); + auto tableTy = lutOp.getType().cast(); + + auto expectedSize = 1 << newTy.getP(); + if (tableTy.getShape()[0] < expectedSize) { + // Create a new padded lookup table auto constantOp = mlir::dyn_cast_or_null( - op.l_cst().getDefiningOp()); + lutOp.getDefiningOp()); if (constantOp == nullptr) { - op.emitError() << "padding for non-constant operator is NYI"; + glweOp.emitError() << "padding for non-constant operator is NYI"; return mlir::failure(); } mlir::DenseIntElementsAttr denseVals = constantOp->getAttrOfType("value"); if (denseVals == nullptr) { - op.emitError() << "value should be dense"; + constantOp.emitError() << "value should be dense"; return mlir::failure(); } - // Create the new constant dense op with padding auto integerSize = 64; llvm::SmallVector rawNewDenseVals( expectedSize, llvm::APInt(integerSize, 0)); @@ -187,19 +212,17 @@ struct TFHEApplyLookupTablePaddingPattern {expectedSize}, rewriter.getIntegerType(integerSize)); auto newDenseVals = mlir::DenseIntElementsAttr::get(newDenseValsType, rawNewDenseVals); - auto newConstantOp = rewriter.create( - constantOp.getLoc(), newDenseVals); - // Replace the apply_lookup_table with the new constant - mlir::SmallVector newResultTypes{op.getType()}; - llvm::SmallVector newOperands{op.ct(), newConstantOp}; - llvm::ArrayRef newAttrs = op->getAttrs(); - rewriter.replaceOpWithNewOp( - op, newResultTypes, newOperands, newAttrs); - return mlir::success(); + // Replace the lutOp by the new padded lookup table + lutOp = rewriter.create(constantOp.getLoc(), + newDenseVals); } - + rewriter.replaceOpWithNewOp(glweOp, newTy, lutOp); return mlir::success(); }; + +private: + mlir::TypeConverter &converter; + mlir::concretelang::V0FHEContext &fheContext; }; template @@ -212,44 +235,6 @@ void populateWithTFHEOpTypeConversionPattern( [&](Op op) { return typeConverter.isLegal(op->getResultTypes()); }); } -void populateWithTFHEApplyLookupTableParametrizationPattern( - mlir::RewritePatternSet &patterns, mlir::ConversionTarget &target, - mlir::TypeConverter &typeConverter, - mlir::concretelang::V0Parameter &v0Parameter) { - patterns.add( - patterns.getContext(), typeConverter, v0Parameter); - target.addDynamicallyLegalOp( - [&](mlir::concretelang::TFHE::ApplyLookupTable op) { - if (op.glweDimension() != v0Parameter.glweDimension || - // TODO remove the shift when we have true polynomial size - op.polynomialSize() != - ((uint32_t)1 << v0Parameter.logPolynomialSize) || - op.levelKS() != v0Parameter.ksLevel || - op.baseLogKS() != v0Parameter.ksLogBase || - op.levelBS() != v0Parameter.brLevel || - op.baseLogBS() != v0Parameter.brLogBase) { - return false; - } - return typeConverter.isLegal(op->getResultTypes()); - }); -} - -void populateWithTFHEApplyLookupTablePaddingPattern( - mlir::RewritePatternSet &patterns, mlir::ConversionTarget &target) { - patterns.add(patterns.getContext()); - target.addLegalOp(); - target.addDynamicallyLegalOp( - [&](mlir::concretelang::TFHE::ApplyLookupTable op) { - auto glweInType = - op.getOperandTypes()[0] - .cast(); - auto tabulatedLambdaType = - op.getOperandTypes()[1].cast(); - - return tabulatedLambdaType.getShape()[0] == 1 << glweInType.getP(); - }); -} - /// Populate the RewritePatternSet with all patterns that rewrite Concrete /// operators to the corresponding function call to the `Concrete C API`. void populateWithTFHEOpTypeConversionPatterns( @@ -271,8 +256,6 @@ void populateWithTFHEOpTypeConversionPatterns( patterns, target, typeConverter); populateWithTFHEOpTypeConversionPattern< mlir::concretelang::TFHE::MulGLWEIntOp>(patterns, target, typeConverter); - populateWithTFHEApplyLookupTableParametrizationPattern( - patterns, target, typeConverter, v0Parameter); } void TFHEGlobalParametrizationPass::runOnOperation() { @@ -292,6 +275,24 @@ void TFHEGlobalParametrizationPass::runOnOperation() { }); mlir::populateFuncOpTypeConversionPattern(patterns, converter); + // Parametrize keyswitch bootstrap + patterns.add(&getContext(), converter, fheContext); + target.addDynamicallyLegalOp( + [&](TFHE::GLWEFromTableOp op) { + return converter.isLegal(op->getResultTypes()); + }); + target.addLegalOp(); + patterns.add(&getContext(), converter, fheContext); + target.addDynamicallyLegalOp( + [&](TFHE::KeySwitchGLWEOp op) { + return op.level() != (uint32_t)-1 && op.baseLog() != (uint32_t)-1; + }); + patterns.add(&getContext(), converter, fheContext); + target.addDynamicallyLegalOp( + [&](TFHE::BootstrapGLWEOp op) { + return converter.isLegal(op->getResultTypes()); + }); + // Add all patterns to convert TFHE types populateWithTFHEOpTypeConversionPatterns(patterns, target, converter, fheContext.parameter); @@ -320,20 +321,6 @@ void TFHEGlobalParametrizationPass::runOnOperation() { this->signalPassFailure(); } } - - // Pad lookup table - { - mlir::ConversionTarget target(getContext()); - mlir::OwningRewritePatternList patterns(&getContext()); - - populateWithTFHEApplyLookupTablePaddingPattern(patterns, target); - - // Apply conversion - if (mlir::applyPartialConversion(op, target, std::move(patterns)) - .failed()) { - this->signalPassFailure(); - } - } } namespace mlir { diff --git a/compiler/lib/Conversion/TFHEToConcrete/TFHEToConcrete.cpp b/compiler/lib/Conversion/TFHEToConcrete/TFHEToConcrete.cpp index fa72a5def..e299c8975 100644 --- a/compiler/lib/Conversion/TFHEToConcrete/TFHEToConcrete.cpp +++ b/compiler/lib/Conversion/TFHEToConcrete/TFHEToConcrete.cpp @@ -18,6 +18,9 @@ #include "concretelang/Dialect/TFHE/IR/TFHEDialect.h" #include "concretelang/Dialect/TFHE/IR/TFHETypes.h" +namespace TFHE = mlir::concretelang::TFHE; +namespace Concrete = mlir::concretelang::Concrete; + namespace { struct TFHEToConcretePass : public TFHEToConcreteBase { void runOnOperation() final; @@ -50,6 +53,26 @@ public: } }; +struct GLWEFromTableOpPattern + : public mlir::OpRewritePattern { + GLWEFromTableOpPattern(mlir::MLIRContext *context, + mlir::PatternBenefit benefit = 1) + : ::mlir::OpRewritePattern(context, benefit) {} + + ::mlir::LogicalResult + matchAndRewrite(TFHE::GLWEFromTableOp glweOp, + mlir::PatternRewriter &rewriter) const override { + auto oldTy = glweOp.getType().cast(); + auto newTy = rewriter.getType( + oldTy.getDimension(), oldTy.getPolynomialSize(), oldTy.getP()); + + rewriter.replaceOpWithNewOp(glweOp, newTy, + glweOp.table()); + + return ::mlir::success(); + }; +}; + void TFHEToConcretePass::runOnOperation() { auto op = this->getOperation(); @@ -84,6 +107,13 @@ void TFHEToConcretePass::runOnOperation() { patterns.add>(&getContext(), converter); + patterns.add(&getContext()); + patterns.add>(&getContext(), + converter); + patterns.add>(&getContext(), + converter); patterns.add>( &getContext(), converter); diff --git a/compiler/lib/Dialect/TFHE/IR/TFHEOps.cpp b/compiler/lib/Dialect/TFHE/IR/TFHEOps.cpp index e9973aadd..64214e0b0 100644 --- a/compiler/lib/Dialect/TFHE/IR/TFHEOps.cpp +++ b/compiler/lib/Dialect/TFHE/IR/TFHEOps.cpp @@ -141,28 +141,6 @@ mlir::LogicalResult verifyUnaryGLWEOperator(Operator &op) { return mlir::success(); } -/// verifyApplyLookupTable verify the GLWE parameters follow the rules: -/// - The l_cst argument must be a memref of one dimension of size 2^p -/// - The lookup table contains integer values of the same width of the output -mlir::LogicalResult verifyApplyLookupTable(ApplyLookupTable &op) { - auto ct = op.ct().getType().cast(); - auto l_cst = op.l_cst().getType().cast(); - - // Check the shape of l_cst argument - auto width = ct.getP(); - auto expectedSize = 1 << width; - mlir::SmallVector expectedShape{expectedSize}; - if (!l_cst.hasStaticShape(expectedShape)) { - FHE::emitErrorBadLutSize(op, "l_cst", "ct", expectedSize, width); - return mlir::failure(); - } - if (!l_cst.getElementType().isInteger(64)) { - op.emitOpError() << "should have the i64 constant"; - return mlir::failure(); - } - return mlir::success(); -} - } // namespace TFHE } // namespace concretelang } // namespace mlir diff --git a/compiler/tests/Conversion/FHELinalgToLinalg/FHELinalgToLinalg/apply_multi_lut_to_linalg.mlir b/compiler/tests/Conversion/FHELinalgToLinalg/FHELinalgToLinalg/apply_multi_lut_to_linalg.mlir index c9c1c0ade..6f4e97b81 100644 --- a/compiler/tests/Conversion/FHELinalgToLinalg/FHELinalgToLinalg/apply_multi_lut_to_linalg.mlir +++ b/compiler/tests/Conversion/FHELinalgToLinalg/FHELinalgToLinalg/apply_multi_lut_to_linalg.mlir @@ -1,23 +1,24 @@ -// RUN: concretecompiler %s --action=dump-tfhe 2>&1 | FileCheck %s +// RUN: concretecompiler %s --action=dump-tfhe --passes fhe-tensor-ops-to-linalg 2>&1 | FileCheck %s -//CHECK-LABEL: #map0 = affine_map<(d0, d1) -> (d0, d1)> +//CHECK: #map0 = affine_map<(d0, d1) -> (d0, d1)> //CHECK-NEXT: #map1 = affine_map<(d0, d1) -> (d0, d1, 0)> //CHECK-NEXT: #map2 = affine_map<(d0, d1) -> (d0, d1, 1)> //CHECK-NEXT: #map3 = affine_map<(d0, d1) -> (d0, d1, 2)> //CHECK-NEXT: #map4 = affine_map<(d0, d1) -> (d0, d1, 3)> //CHECK-NEXT: module { -//CHECK-NEXT: func @multi_lut(%arg0: tensor<4x4x!TFHE.glwe<{_,_,_}{2}>>, %arg1: tensor<4x4x4xi64>) -> tensor<4x4x!TFHE.glwe<{_,_,_}{2}>> { -//CHECK-NEXT: %[[V0:.*]] = linalg.init_tensor [4, 4] : tensor<4x4x!TFHE.glwe<{_,_,_}{2}>> -//CHECK-NEXT: %[[V1:.*]] = linalg.generic {indexing_maps = [#map0, #map1, #map2, #map3, #map4, #map0], iterator_types = ["parallel", "parallel"]} ins(%arg0, %arg1, %arg1, %arg1, %arg1 : tensor<4x4x!TFHE.glwe<{_,_,_}{2}>>, tensor<4x4x4xi64>, tensor<4x4x4xi64>, tensor<4x4x4xi64>, tensor<4x4x4xi64>) outs(%[[V0]] : tensor<4x4x!TFHE.glwe<{_,_,_}{2}>>) { -//CHECK-NEXT: ^bb0(%arg2: !TFHE.glwe<{_,_,_}{2}>, %arg3: i64, %arg4: i64, %arg5: i64, %arg6: i64, %arg7: !TFHE.glwe<{_,_,_}{2}>): // no predecessors -//CHECK-NEXT: %[[V2:.*]] = tensor.from_elements %arg3, %arg4, %arg5, %arg6 : tensor<4xi64> -//CHECK-NEXT: %[[V3:.*]] = "TFHE.apply_lookup_table"(%arg2, %[[V2]]) {baseLogBS = -1 : i32, baseLogKS = -1 : i32, glweDimension = -1 : i32, levelBS = -1 : i32, levelKS = -1 : i32, outputSizeKS = -1 : i32, polynomialSize = -1 : i32} : (!TFHE.glwe<{_,_,_}{2}>, tensor<4xi64>) -> !TFHE.glwe<{_,_,_}{2}> -//CHECK-NEXT: linalg.yield %[[V3]] : !TFHE.glwe<{_,_,_}{2}> -//CHECK-NEXT: } -> tensor<4x4x!TFHE.glwe<{_,_,_}{2}>> -//CHECK-NEXT: return %[[V1]] : tensor<4x4x!TFHE.glwe<{_,_,_}{2}>> +//CHECK-NEXT: func @multi_lut(%[[A0:.*]]: tensor<4x4x!FHE.eint<2>>, %[[A1:.*]]: tensor<4x4x4xi64>) -> tensor<4x4x!FHE.eint<2>> { +//CHECK-NEXT: %[[V0:.*]] = linalg.init_tensor [4, 4] : tensor<4x4x!FHE.eint<2>> +//CHECK-NEXT: %[[V1:.*]] = linalg.generic {indexing_maps = [#map0, #map1, #map2, #map3, #map4, #map0], iterator_types = ["parallel", "parallel"]} ins(%[[A0]], %[[A1]], %[[A1]], %[[A1]], %[[A1]] : tensor<4x4x!FHE.eint<2>>, tensor<4x4x4xi64>, tensor<4x4x4xi64>, tensor<4x4x4xi64>, tensor<4x4x4xi64>) outs(%[[V0]] : tensor<4x4x!FHE.eint<2>>) { +//CHECK-NEXT: ^bb0(%[[A2:.*]]: !FHE.eint<2>, %[[A3:.*]]: i64, %[[A4:.*]]: i64, %[[A5:.*]]: i64, %[[A6:.*]]: i64, %[[A7:.*]]: !FHE.eint<2>): // no predecessors +//CHECK-NEXT: %[[V2:.*]] = tensor.from_elements %[[A3]], %[[A4]], %[[A5]], %[[A6]] : tensor<4xi64> +//CHECK-NEXT: %[[V3:.*]] = "FHE.apply_lookup_table"(%[[A2]], %[[V2]]) : (!FHE.eint<2>, tensor<4xi64>) -> !FHE.eint<2> +//CHECK-NEXT: linalg.yield %[[V3]] : !FHE.eint<2> +//CHECK-NEXT: } -> tensor<4x4x!FHE.eint<2>> +//CHECK-NEXT: return %[[V1]] : tensor<4x4x!FHE.eint<2>> //CHECK-NEXT: } //CHECK-NEXT: } + func @multi_lut(%arg0: tensor<4x4x!FHE.eint<2>>, %arg1: tensor<4x4x4xi64>) -> tensor<4x4x!FHE.eint<2>> { - %1 = "FHELinalg.apply_multi_lookup_table"(%arg0, %arg1): (tensor<4x4x!FHE.eint<2>>, tensor<4x4x4xi64>) -> tensor<4x4x!FHE.eint<2>> - return %1: tensor<4x4x!FHE.eint<2>> + %0 = "FHELinalg.apply_multi_lookup_table"(%arg0, %arg1): (tensor<4x4x!FHE.eint<2>>, tensor<4x4x4xi64>) -> tensor<4x4x!FHE.eint<2>> + return %0: tensor<4x4x!FHE.eint<2>> } \ No newline at end of file diff --git a/compiler/tests/Conversion/FHELinalgToLinalg/FHELinalgToLinalg/apply_multi_lut_to_linalg_broadcast.mlir b/compiler/tests/Conversion/FHELinalgToLinalg/FHELinalgToLinalg/apply_multi_lut_to_linalg_broadcast.mlir index ec42085c1..68d5457a1 100644 --- a/compiler/tests/Conversion/FHELinalgToLinalg/FHELinalgToLinalg/apply_multi_lut_to_linalg_broadcast.mlir +++ b/compiler/tests/Conversion/FHELinalgToLinalg/FHELinalgToLinalg/apply_multi_lut_to_linalg_broadcast.mlir @@ -1,22 +1,23 @@ -// RUN: concretecompiler %s --action=dump-tfhe 2>&1 | FileCheck %s +// RUN: concretecompiler %s --action=dump-tfhe --passes fhe-tensor-ops-to-linalg 2>&1 | FileCheck %s -//CHECK-LABEL: #map0 = affine_map<(d0, d1) -> (d0, d1)> +//CHECK: #map0 = affine_map<(d0, d1) -> (d0, d1)> //CHECK-NEXT: #map1 = affine_map<(d0, d1) -> (d1, 0)> //CHECK-NEXT: #map2 = affine_map<(d0, d1) -> (d1, 1)> //CHECK-NEXT: #map3 = affine_map<(d0, d1) -> (d1, 2)> //CHECK-NEXT: #map4 = affine_map<(d0, d1) -> (d1, 3)> //CHECK-NEXT: module { -//CHECK-NEXT: func @multi_lut(%arg0: tensor<4x3x!TFHE.glwe<{_,_,_}{2}>>, %arg1: tensor<3x4xi64>) -> tensor<4x3x!TFHE.glwe<{_,_,_}{2}>> { -//CHECK-NEXT: %[[V0:.*]] = linalg.init_tensor [4, 3] : tensor<4x3x!TFHE.glwe<{_,_,_}{2}>> -//CHECK-NEXT: %[[V1:.*]] = linalg.generic {indexing_maps = [#map0, #map1, #map2, #map3, #map4, #map0], iterator_types = ["parallel", "parallel"]} ins(%arg0, %arg1, %arg1, %arg1, %arg1 : tensor<4x3x!TFHE.glwe<{_,_,_}{2}>>, tensor<3x4xi64>, tensor<3x4xi64>, tensor<3x4xi64>, tensor<3x4xi64>) outs(%[[V0]] : tensor<4x3x!TFHE.glwe<{_,_,_}{2}>>) { -//CHECK-NEXT: ^bb0(%arg2: !TFHE.glwe<{_,_,_}{2}>, %arg3: i64, %arg4: i64, %arg5: i64, %arg6: i64, %arg7: !TFHE.glwe<{_,_,_}{2}>): // no predecessors -//CHECK-NEXT: %[[V2:.*]] = tensor.from_elements %arg3, %arg4, %arg5, %arg6 : tensor<4xi64> -//CHECK-NEXT: %[[V3:.*]] = "TFHE.apply_lookup_table"(%arg2, %[[V2]]) {baseLogBS = -1 : i32, baseLogKS = -1 : i32, glweDimension = -1 : i32, levelBS = -1 : i32, levelKS = -1 : i32, outputSizeKS = -1 : i32, polynomialSize = -1 : i32} : (!TFHE.glwe<{_,_,_}{2}>, tensor<4xi64>) -> !TFHE.glwe<{_,_,_}{2}> -//CHECK-NEXT: linalg.yield %[[V3]] : !TFHE.glwe<{_,_,_}{2}> -//CHECK-NEXT: } -> tensor<4x3x!TFHE.glwe<{_,_,_}{2}>> -//CHECK-NEXT: return %[[V1]] : tensor<4x3x!TFHE.glwe<{_,_,_}{2}>> +//CHECK-NEXT: func @multi_lut(%[[A0:.*]]: tensor<4x3x!FHE.eint<2>>, %[[A1:.*]]: tensor<3x4xi64>) -> tensor<4x3x!FHE.eint<2>> { +//CHECK-NEXT: %[[V0:.*]] = linalg.init_tensor [4, 3] : tensor<4x3x!FHE.eint<2>> +//CHECK-NEXT: %[[V1:.*]] = linalg.generic {indexing_maps = [#map0, #map1, #map2, #map3, #map4, #map0], iterator_types = ["parallel", "parallel"]} ins(%[[A0]], %[[A1]], %[[A1]], %[[A1]], %[[A1]] : tensor<4x3x!FHE.eint<2>>, tensor<3x4xi64>, tensor<3x4xi64>, tensor<3x4xi64>, tensor<3x4xi64>) outs(%[[V0]] : tensor<4x3x!FHE.eint<2>>) { +//CHECK-NEXT: ^bb0(%[[A2:.*]]: !FHE.eint<2>, %[[A3:.*]]: i64, %[[A4:.*]]: i64, %[[A5:.*]]: i64, %[[A6:.*]]: i64, %[[A7:.*]]: !FHE.eint<2>): // no predecessors +//CHECK-NEXT: %[[V2:.*]] = tensor.from_elements %[[A3]], %[[A4]], %[[A5]], %[[A6]] : tensor<4xi64> +//CHECK-NEXT: %[[V3:.*]] = "FHE.apply_lookup_table"(%[[A2]], %[[V2]]) : (!FHE.eint<2>, tensor<4xi64>) -> !FHE.eint<2> +//CHECK-NEXT: linalg.yield %[[V3]] : !FHE.eint<2> +//CHECK-NEXT: } -> tensor<4x3x!FHE.eint<2>> +//CHECK-NEXT: return %[[V1]] : tensor<4x3x!FHE.eint<2>> //CHECK-NEXT: } //CHECK-NEXT: } + func @multi_lut(%arg0: tensor<4x3x!FHE.eint<2>>, %arg1: tensor<3x4xi64>) -> tensor<4x3x!FHE.eint<2>> { %1 = "FHELinalg.apply_multi_lookup_table"(%arg0, %arg1): (tensor<4x3x!FHE.eint<2>>, tensor<3x4xi64>) -> tensor<4x3x!FHE.eint<2>> return %1: tensor<4x3x!FHE.eint<2>> diff --git a/compiler/tests/Conversion/FHEToTFHE/FHEToTFHE/apply_univariate.mlir b/compiler/tests/Conversion/FHEToTFHE/FHEToTFHE/apply_univariate.mlir index 6183171c5..fc4fe88d3 100644 --- a/compiler/tests/Conversion/FHEToTFHE/FHEToTFHE/apply_univariate.mlir +++ b/compiler/tests/Conversion/FHEToTFHE/FHEToTFHE/apply_univariate.mlir @@ -1,10 +1,11 @@ // RUN: concretecompiler %s --passes fhe-to-tfhe --action=dump-tfhe 2>&1| FileCheck %s -// CHECK-LABEL: func @apply_lookup_table(%arg0: !TFHE.glwe<{_,_,_}{2}>, %arg1: tensor<4xi64>) -> !TFHE.glwe<{_,_,_}{2}> -func @apply_lookup_table(%arg0: !FHE.eint<2>, %arg1: tensor<4xi64>) -> !FHE.eint<2> { - // CHECK-NEXT: %[[V1:.*]] = "TFHE.apply_lookup_table"(%arg0, %arg1) {baseLogBS = -1 : i32, baseLogKS = -1 : i32, glweDimension = -1 : i32, levelBS = -1 : i32, levelKS = -1 : i32, outputSizeKS = -1 : i32, polynomialSize = -1 : i32} : (!TFHE.glwe<{_,_,_}{2}>, tensor<4xi64>) -> !TFHE.glwe<{_,_,_}{2}> - // CHECK-NEXT: return %[[V1]] : !TFHE.glwe<{_,_,_}{2}> - - %1 = "FHE.apply_lookup_table"(%arg0, %arg1): (!FHE.eint<2>, tensor<4xi64>) -> (!FHE.eint<2>) - return %1: !FHE.eint<2> -} +// CHECK: func @apply_lookup_table(%[[A0:.*]]: !TFHE.glwe<{_,_,_}{2}>, %[[LUT:.*]]: tensor<4xi64>) -> !TFHE.glwe<{_,_,_}{3}> { +// CHECK-NEXT: %[[V0:.*]] = "TFHE.glwe_from_table"(%[[LUT]]) : (tensor<4xi64>) -> !TFHE.glwe<{_,_,_}{2}> +// CHECK-NEXT: %[[V1:.*]] = "TFHE.keyswitch_glwe"(%[[A0]]) {baseLog = -1 : i32, level = -1 : i32} : (!TFHE.glwe<{_,_,_}{2}>) -> !TFHE.glwe<{_,_,_}{2}> +// CHECK-NEXT: %[[V2:.*]] = "TFHE.bootstrap_glwe"(%[[V1]], %[[V0]]) {baseLog = -1 : i32, glweDimension = -1 : i32, level = -1 : i32, polynomialSize = -1 : i32} : (!TFHE.glwe<{_,_,_}{2}>, !TFHE.glwe<{_,_,_}{2}>) -> !TFHE.glwe<{_,_,_}{3}> +// CHECK-NEXT: return %[[V2]] : !TFHE.glwe<{_,_,_}{3}> +func @apply_lookup_table(%arg0: !FHE.eint<2>, %arg1: tensor<4xi64>) -> !FHE.eint<3> { + %1 = "FHE.apply_lookup_table"(%arg0, %arg1): (!FHE.eint<2>, tensor<4xi64>) -> (!FHE.eint<3>) + return %1: !FHE.eint<3> +} \ No newline at end of file diff --git a/compiler/tests/Conversion/FHEToTFHE/FHEToTFHE/apply_univariate_cst.mlir b/compiler/tests/Conversion/FHEToTFHE/FHEToTFHE/apply_univariate_cst.mlir index 9726240e1..0625a2032 100644 --- a/compiler/tests/Conversion/FHEToTFHE/FHEToTFHE/apply_univariate_cst.mlir +++ b/compiler/tests/Conversion/FHEToTFHE/FHEToTFHE/apply_univariate_cst.mlir @@ -1,10 +1,13 @@ // RUN: concretecompiler %s --passes fhe-to-tfhe --action=dump-tfhe 2>&1| FileCheck %s -// CHECK-LABEL: func @apply_lookup_table_cst(%arg0: !TFHE.glwe<{_,_,_}{7}>) -> !TFHE.glwe<{_,_,_}{7}> +//CHECK: func @apply_lookup_table_cst(%[[A0:.*]]: !TFHE.glwe<{_,_,_}{7}>) -> !TFHE.glwe<{_,_,_}{7}> { +//CHECK-NEXT: %cst = arith.constant dense<"0x00000000000000000100000000000000020000000000000003000000000000000400000000000000050000000000000006000000000000000700000000000000080000000000000009000000000000000A000000000000000B000000000000000C000000000000000D000000000000000E000000000000000F0000000000000010000000000000001100000000000000120000000000000013000000000000001400000000000000150000000000000016000000000000001700000000000000180000000000000019000000000000001A000000000000001B000000000000001C000000000000001D000000000000001E000000000000001F0000000000000020000000000000002100000000000000220000000000000023000000000000002400000000000000250000000000000026000000000000002700000000000000280000000000000029000000000000002A000000000000002B000000000000002C000000000000002D000000000000002E000000000000002F0000000000000030000000000000003100000000000000320000000000000033000000000000003400000000000000350000000000000036000000000000003700000000000000380000000000000039000000000000003A000000000000003B000000000000003C000000000000003D000000000000003E000000000000003F0000000000000040000000000000004100000000000000420000000000000043000000000000004400000000000000450000000000000046000000000000004700000000000000480000000000000049000000000000004A000000000000004B000000000000004C000000000000004D000000000000004E000000000000004F0000000000000050000000000000005100000000000000520000000000000053000000000000005400000000000000550000000000000056000000000000005700000000000000580000000000000059000000000000005A000000000000005B000000000000005C000000000000005D000000000000005E000000000000005F0000000000000060000000000000006100000000000000620000000000000063000000000000006400000000000000650000000000000066000000000000006700000000000000680000000000000069000000000000006A000000000000006B000000000000006C000000000000006D000000000000006E000000000000006F0000000000000070000000000000007100000000000000720000000000000073000000000000007400000000000000750000000000000076000000000000007700000000000000780000000000000079000000000000007A000000000000007B000000000000007C000000000000007D000000000000007E000000000000007F00000000000000"> : tensor<128xi64> +//CHECK-NEXT: %[[V0:.*]] = "TFHE.glwe_from_table"(%cst) : (tensor<128xi64>) -> !TFHE.glwe<{_,_,_}{7}> +//CHECK-NEXT: %[[V1:.*]] = "TFHE.keyswitch_glwe"(%[[A0]]) {baseLog = -1 : i32, level = -1 : i32} : (!TFHE.glwe<{_,_,_}{7}>) -> !TFHE.glwe<{_,_,_}{7}> +//CHECK-NEXT: %[[V2:.*]] = "TFHE.bootstrap_glwe"(%[[V1]], %[[V0]]) {baseLog = -1 : i32, glweDimension = -1 : i32, level = -1 : i32, polynomialSize = -1 : i32} : (!TFHE.glwe<{_,_,_}{7}>, !TFHE.glwe<{_,_,_}{7}>) -> !TFHE.glwe<{_,_,_}{7}> +//CHECK-NEXT: return %[[V2]] : !TFHE.glwe<{_,_,_}{7}> +//CHECK-NEXT: } func @apply_lookup_table_cst(%arg0: !FHE.eint<7>) -> !FHE.eint<7> { - // CHECK-NEXT: %[[TABLE:.*]] = arith.constant dense<"0x00000000000000000100000000000000020000000000000003000000000000000400000000000000050000000000000006000000000000000700000000000000080000000000000009000000000000000A000000000000000B000000000000000C000000000000000D000000000000000E000000000000000F0000000000000010000000000000001100000000000000120000000000000013000000000000001400000000000000150000000000000016000000000000001700000000000000180000000000000019000000000000001A000000000000001B000000000000001C000000000000001D000000000000001E000000000000001F0000000000000020000000000000002100000000000000220000000000000023000000000000002400000000000000250000000000000026000000000000002700000000000000280000000000000029000000000000002A000000000000002B000000000000002C000000000000002D000000000000002E000000000000002F0000000000000030000000000000003100000000000000320000000000000033000000000000003400000000000000350000000000000036000000000000003700000000000000380000000000000039000000000000003A000000000000003B000000000000003C000000000000003D000000000000003E000000000000003F0000000000000040000000000000004100000000000000420000000000000043000000000000004400000000000000450000000000000046000000000000004700000000000000480000000000000049000000000000004A000000000000004B000000000000004C000000000000004D000000000000004E000000000000004F0000000000000050000000000000005100000000000000520000000000000053000000000000005400000000000000550000000000000056000000000000005700000000000000580000000000000059000000000000005A000000000000005B000000000000005C000000000000005D000000000000005E000000000000005F0000000000000060000000000000006100000000000000620000000000000063000000000000006400000000000000650000000000000066000000000000006700000000000000680000000000000069000000000000006A000000000000006B000000000000006C000000000000006D000000000000006E000000000000006F0000000000000070000000000000007100000000000000720000000000000073000000000000007400000000000000750000000000000076000000000000007700000000000000780000000000000079000000000000007A000000000000007B000000000000007C000000000000007D000000000000007E000000000000007F00000000000000"> : tensor<128xi64> - // CHECK-NEXT: %[[V0:.*]] = "TFHE.apply_lookup_table"(%arg0, %[[TABLE]]) {baseLogBS = -1 : i32, baseLogKS = -1 : i32, glweDimension = -1 : i32, levelBS = -1 : i32, levelKS = -1 : i32, outputSizeKS = -1 : i32, polynomialSize = -1 : i32} : (!TFHE.glwe<{_,_,_}{7}>, tensor<128xi64>) -> !TFHE.glwe<{_,_,_}{7}> - // CHECK-NEXT: return %[[V0]] : !TFHE.glwe<{_,_,_}{7}> %tlu = arith.constant dense<[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127]> : tensor<128xi64> %1 = "FHE.apply_lookup_table"(%arg0, %tlu): (!FHE.eint<7>, tensor<128xi64>) -> (!FHE.eint<7>) return %1: !FHE.eint<7> diff --git a/compiler/tests/Conversion/TFHEToConcrete/TFHEToConcrete/apply_lookup_table.mlir b/compiler/tests/Conversion/TFHEToConcrete/TFHEToConcrete/apply_lookup_table.mlir deleted file mode 100644 index 86fbe18f4..000000000 --- a/compiler/tests/Conversion/TFHEToConcrete/TFHEToConcrete/apply_lookup_table.mlir +++ /dev/null @@ -1,11 +0,0 @@ -// RUN: concretecompiler --passes tfhe-to-concrete --action=dump-concrete %s 2>&1| FileCheck %s - -// CHECK-LABEL: func @apply_lookup_table(%arg0: !Concrete.lwe_ciphertext<1024,4>, %arg1: tensor<16xi64>) -> !Concrete.lwe_ciphertext<1024,4> -func @apply_lookup_table(%arg0: !TFHE.glwe<{1024,1,64}{4}>, %arg1: tensor<16xi64>) -> !TFHE.glwe<{1024,1,64}{4}> { - // CHECK-NEXT: %[[V1:.*]] = "Concrete.glwe_from_table"(%arg1) : (tensor<16xi64>) -> !Concrete.glwe_ciphertext<1024,1,4> - // CHECK-NEXT: %[[V2:.*]] = "Concrete.keyswitch_lwe"(%arg0) {baseLog = 2 : i32, level = 3 : i32} : (!Concrete.lwe_ciphertext<1024,4>) -> !Concrete.lwe_ciphertext<600,4> - // CHECK-NEXT: %[[V3:.*]] = "Concrete.bootstrap_lwe"(%[[V2]], %[[V1]]) {baseLog = 4 : i32, glweDimension = 1 : i32, level = 5 : i32, polynomialSize = 1024 : i32} : (!Concrete.lwe_ciphertext<600,4>, !Concrete.glwe_ciphertext<1024,1,4>) -> !Concrete.lwe_ciphertext<1024,4> - // CHECK-NEXT: return %[[V3]] : !Concrete.lwe_ciphertext<1024,4> - %1 = "TFHE.apply_lookup_table"(%arg0, %arg1){glweDimension=1:i32, polynomialSize=1024:i32, levelKS=3:i32, baseLogKS=2:i32, levelBS=5:i32, baseLogBS=4:i32, outputSizeKS=600:i32}: (!TFHE.glwe<{1024,1,64}{4}>, tensor<16xi64>) -> (!TFHE.glwe<{1024,1,64}{4}>) - return %1: !TFHE.glwe<{1024,1,64}{4}> -} diff --git a/compiler/tests/Conversion/TFHEToConcrete/TFHEToConcrete/apply_lookup_table_cst.mlir b/compiler/tests/Conversion/TFHEToConcrete/TFHEToConcrete/apply_lookup_table_cst.mlir deleted file mode 100644 index e61cf92d8..000000000 --- a/compiler/tests/Conversion/TFHEToConcrete/TFHEToConcrete/apply_lookup_table_cst.mlir +++ /dev/null @@ -1,13 +0,0 @@ -// RUN: concretecompiler --passes tfhe-to-concrete --action=dump-concrete %s 2>&1| FileCheck %s - -// CHECK-LABEL: func @apply_lookup_table_cst(%arg0: !Concrete.lwe_ciphertext<2048,4>) -> !Concrete.lwe_ciphertext<2048,4> -func @apply_lookup_table_cst(%arg0: !TFHE.glwe<{2048,1,64}{4}>) -> !TFHE.glwe<{2048,1,64}{4}> { - // CHECK-NEXT: %[[TABLE:.*]] = arith.constant dense<[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]> : tensor<16xi64> - // CHECK-NEXT: %[[V1:.*]] = "Concrete.glwe_from_table"(%[[TABLE]]) : (tensor<16xi64>) -> !Concrete.glwe_ciphertext<2048,1,4> - // CHECK-NEXT: %[[V2:.*]] = "Concrete.keyswitch_lwe"(%arg0) {baseLog = 2 : i32, level = 3 : i32} : (!Concrete.lwe_ciphertext<2048,4>) -> !Concrete.lwe_ciphertext<600,4> - // CHECK-NEXT: %[[V3:.*]] = "Concrete.bootstrap_lwe"(%[[V2]], %[[V1]]) {baseLog = 4 : i32, glweDimension = 1 : i32, level = 5 : i32, polynomialSize = 2048 : i32} : (!Concrete.lwe_ciphertext<600,4>, !Concrete.glwe_ciphertext<2048,1,4>) -> !Concrete.lwe_ciphertext<2048,4> - // CHECK-NEXT: return %[[V3]] : !Concrete.lwe_ciphertext<2048,4> - %tlu = arith.constant dense<[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]> : tensor<16xi64> - %1 = "TFHE.apply_lookup_table"(%arg0, %tlu){glweDimension=1:i32, polynomialSize=2048:i32, levelKS=3:i32, baseLogKS=2:i32, levelBS=5:i32, baseLogBS=4:i32, outputSizeKS=600:i32}: (!TFHE.glwe<{2048,1,64}{4}>, tensor<16xi64>) -> (!TFHE.glwe<{2048,1,64}{4}>) - return %1: !TFHE.glwe<{2048,1,64}{4}> -} diff --git a/compiler/tests/Conversion/TFHEToConcrete/TFHEToConcrete/bootstrap.mlir b/compiler/tests/Conversion/TFHEToConcrete/TFHEToConcrete/bootstrap.mlir new file mode 100644 index 000000000..9918dbcd0 --- /dev/null +++ b/compiler/tests/Conversion/TFHEToConcrete/TFHEToConcrete/bootstrap.mlir @@ -0,0 +1,14 @@ +// RUN: concretecompiler --passes tfhe-to-concrete --action=dump-concrete %s 2>&1| FileCheck %s + +//CHECK: func @bootstrap_lwe(%[[A0:.*]]: !Concrete.lwe_ciphertext<1024,7>) -> !Concrete.lwe_ciphertext<1024,4> { +//CHECK-NEXT: %cst = arith.constant dense<"0x00000000000000000100000000000000020000000000000003000000000000000400000000000000050000000000000006000000000000000700000000000000080000000000000009000000000000000A000000000000000B000000000000000C000000000000000D000000000000000E000000000000000F0000000000000010000000000000001100000000000000120000000000000013000000000000001400000000000000150000000000000016000000000000001700000000000000180000000000000019000000000000001A000000000000001B000000000000001C000000000000001D000000000000001E000000000000001F0000000000000020000000000000002100000000000000220000000000000023000000000000002400000000000000250000000000000026000000000000002700000000000000280000000000000029000000000000002A000000000000002B000000000000002C000000000000002D000000000000002E000000000000002F0000000000000030000000000000003100000000000000320000000000000033000000000000003400000000000000350000000000000036000000000000003700000000000000380000000000000039000000000000003A000000000000003B000000000000003C000000000000003D000000000000003E000000000000003F0000000000000040000000000000004100000000000000420000000000000043000000000000004400000000000000450000000000000046000000000000004700000000000000480000000000000049000000000000004A000000000000004B000000000000004C000000000000004D000000000000004E000000000000004F0000000000000050000000000000005100000000000000520000000000000053000000000000005400000000000000550000000000000056000000000000005700000000000000580000000000000059000000000000005A000000000000005B000000000000005C000000000000005D000000000000005E000000000000005F0000000000000060000000000000006100000000000000620000000000000063000000000000006400000000000000650000000000000066000000000000006700000000000000680000000000000069000000000000006A000000000000006B000000000000006C000000000000006D000000000000006E000000000000006F0000000000000070000000000000007100000000000000720000000000000073000000000000007400000000000000750000000000000076000000000000007700000000000000780000000000000079000000000000007A000000000000007B000000000000007C000000000000007D000000000000007E000000000000007F00000000000000"> : tensor<128xi64> +//CHECK-NEXT: %[[V0:.*]] = "Concrete.glwe_from_table"(%cst) : (tensor<128xi64>) -> !Concrete.glwe_ciphertext<1,1024,7> +//CHECK-NEXT: %[[V1:.*]] = "Concrete.bootstrap_lwe"(%[[A0]], %[[V0]]) {baseLog = 1 : i32, glweDimension = 1 : i32, level = 3 : i32, polynomialSize = 1024 : i32} : (!Concrete.lwe_ciphertext<1024,7>, !Concrete.glwe_ciphertext<1,1024,7>) -> !Concrete.lwe_ciphertext<1024,4> +//CHECK-NEXT: return %[[V1]] : !Concrete.lwe_ciphertext<1024,4> +//CHECK-NEXT: } +func @bootstrap_lwe(%ciphertext: !TFHE.glwe<{1,1024,64}{7}>) -> !TFHE.glwe<{1,1024,64}{4}> { + %cst = arith.constant dense<"0x00000000000000000100000000000000020000000000000003000000000000000400000000000000050000000000000006000000000000000700000000000000080000000000000009000000000000000A000000000000000B000000000000000C000000000000000D000000000000000E000000000000000F0000000000000010000000000000001100000000000000120000000000000013000000000000001400000000000000150000000000000016000000000000001700000000000000180000000000000019000000000000001A000000000000001B000000000000001C000000000000001D000000000000001E000000000000001F0000000000000020000000000000002100000000000000220000000000000023000000000000002400000000000000250000000000000026000000000000002700000000000000280000000000000029000000000000002A000000000000002B000000000000002C000000000000002D000000000000002E000000000000002F0000000000000030000000000000003100000000000000320000000000000033000000000000003400000000000000350000000000000036000000000000003700000000000000380000000000000039000000000000003A000000000000003B000000000000003C000000000000003D000000000000003E000000000000003F0000000000000040000000000000004100000000000000420000000000000043000000000000004400000000000000450000000000000046000000000000004700000000000000480000000000000049000000000000004A000000000000004B000000000000004C000000000000004D000000000000004E000000000000004F0000000000000050000000000000005100000000000000520000000000000053000000000000005400000000000000550000000000000056000000000000005700000000000000580000000000000059000000000000005A000000000000005B000000000000005C000000000000005D000000000000005E000000000000005F0000000000000060000000000000006100000000000000620000000000000063000000000000006400000000000000650000000000000066000000000000006700000000000000680000000000000069000000000000006A000000000000006B000000000000006C000000000000006D000000000000006E000000000000006F0000000000000070000000000000007100000000000000720000000000000073000000000000007400000000000000750000000000000076000000000000007700000000000000780000000000000079000000000000007A000000000000007B000000000000007C000000000000007D000000000000007E000000000000007F00000000000000"> : tensor<128xi64> + %glwe_lut = "TFHE.glwe_from_table"(%cst) : (tensor<128xi64>) -> !TFHE.glwe<{1,1024,64}{7}> + %bootstraped = "TFHE.bootstrap_glwe"(%ciphertext, %glwe_lut) {baseLog = 1 : i32, glweDimension = 1 : i32, level = 3 : i32, polynomialSize = 1024 : i32} : (!TFHE.glwe<{1,1024,64}{7}>, !TFHE.glwe<{1,1024,64}{7}>) -> !TFHE.glwe<{1,1024,64}{4}> + return %bootstraped : !TFHE.glwe<{1,1024,64}{4}> +} diff --git a/compiler/tests/Conversion/TFHEToConcrete/TFHEToConcrete/glwe_from_table.mlir b/compiler/tests/Conversion/TFHEToConcrete/TFHEToConcrete/glwe_from_table.mlir new file mode 100644 index 000000000..d788d56d3 --- /dev/null +++ b/compiler/tests/Conversion/TFHEToConcrete/TFHEToConcrete/glwe_from_table.mlir @@ -0,0 +1,12 @@ +// RUN: concretecompiler --passes tfhe-to-concrete --action=dump-concrete %s 2>&1| FileCheck %s + +//CHECK: func @glwe_from_table() { +//CHECK-NEXT: %[[V0:.*]] = arith.constant dense<"0x00000000000000000100000000000000020000000000000003000000000000000400000000000000050000000000000006000000000000000700000000000000080000000000000009000000000000000A000000000000000B000000000000000C000000000000000D000000000000000E000000000000000F0000000000000010000000000000001100000000000000120000000000000013000000000000001400000000000000150000000000000016000000000000001700000000000000180000000000000019000000000000001A000000000000001B000000000000001C000000000000001D000000000000001E000000000000001F0000000000000020000000000000002100000000000000220000000000000023000000000000002400000000000000250000000000000026000000000000002700000000000000280000000000000029000000000000002A000000000000002B000000000000002C000000000000002D000000000000002E000000000000002F0000000000000030000000000000003100000000000000320000000000000033000000000000003400000000000000350000000000000036000000000000003700000000000000380000000000000039000000000000003A000000000000003B000000000000003C000000000000003D000000000000003E000000000000003F0000000000000040000000000000004100000000000000420000000000000043000000000000004400000000000000450000000000000046000000000000004700000000000000480000000000000049000000000000004A000000000000004B000000000000004C000000000000004D000000000000004E000000000000004F0000000000000050000000000000005100000000000000520000000000000053000000000000005400000000000000550000000000000056000000000000005700000000000000580000000000000059000000000000005A000000000000005B000000000000005C000000000000005D000000000000005E000000000000005F0000000000000060000000000000006100000000000000620000000000000063000000000000006400000000000000650000000000000066000000000000006700000000000000680000000000000069000000000000006A000000000000006B000000000000006C000000000000006D000000000000006E000000000000006F0000000000000070000000000000007100000000000000720000000000000073000000000000007400000000000000750000000000000076000000000000007700000000000000780000000000000079000000000000007A000000000000007B000000000000007C000000000000007D000000000000007E000000000000007F00000000000000"> : tensor<128xi64> +//CHECK-NEXT: %[[V1:.*]] = "Concrete.glwe_from_table"(%[[V0]]) : (tensor<128xi64>) -> !Concrete.glwe_ciphertext<1,1024,7> +//CHECK-NEXT: return +//CHECK-NEXT: } +func @glwe_from_table() { + %cst = arith.constant dense<"0x00000000000000000100000000000000020000000000000003000000000000000400000000000000050000000000000006000000000000000700000000000000080000000000000009000000000000000A000000000000000B000000000000000C000000000000000D000000000000000E000000000000000F0000000000000010000000000000001100000000000000120000000000000013000000000000001400000000000000150000000000000016000000000000001700000000000000180000000000000019000000000000001A000000000000001B000000000000001C000000000000001D000000000000001E000000000000001F0000000000000020000000000000002100000000000000220000000000000023000000000000002400000000000000250000000000000026000000000000002700000000000000280000000000000029000000000000002A000000000000002B000000000000002C000000000000002D000000000000002E000000000000002F0000000000000030000000000000003100000000000000320000000000000033000000000000003400000000000000350000000000000036000000000000003700000000000000380000000000000039000000000000003A000000000000003B000000000000003C000000000000003D000000000000003E000000000000003F0000000000000040000000000000004100000000000000420000000000000043000000000000004400000000000000450000000000000046000000000000004700000000000000480000000000000049000000000000004A000000000000004B000000000000004C000000000000004D000000000000004E000000000000004F0000000000000050000000000000005100000000000000520000000000000053000000000000005400000000000000550000000000000056000000000000005700000000000000580000000000000059000000000000005A000000000000005B000000000000005C000000000000005D000000000000005E000000000000005F0000000000000060000000000000006100000000000000620000000000000063000000000000006400000000000000650000000000000066000000000000006700000000000000680000000000000069000000000000006A000000000000006B000000000000006C000000000000006D000000000000006E000000000000006F0000000000000070000000000000007100000000000000720000000000000073000000000000007400000000000000750000000000000076000000000000007700000000000000780000000000000079000000000000007A000000000000007B000000000000007C000000000000007D000000000000007E000000000000007F00000000000000"> : tensor<128xi64> + %0 = "TFHE.glwe_from_table"(%cst) : (tensor<128xi64>) -> !TFHE.glwe<{1,1024,64}{7}> + return +} diff --git a/compiler/tests/Conversion/TFHEToConcrete/TFHEToConcrete/keyswitch.mlir b/compiler/tests/Conversion/TFHEToConcrete/TFHEToConcrete/keyswitch.mlir new file mode 100644 index 000000000..ff48e7305 --- /dev/null +++ b/compiler/tests/Conversion/TFHEToConcrete/TFHEToConcrete/keyswitch.mlir @@ -0,0 +1,10 @@ +// RUN: concretecompiler --passes tfhe-to-concrete --action=dump-concrete %s 2>&1| FileCheck %s + +// CHECK: func @keyswitch_glwe(%[[A0:.*]]: !Concrete.lwe_ciphertext<1024,2>) -> !Concrete.lwe_ciphertext<567,2> { +// CHECK-NEXT: %[[V0:.*]] = "Concrete.keyswitch_lwe"(%[[A0]]) {baseLog = 3 : i32, level = 2 : i32} : (!Concrete.lwe_ciphertext<1024,2>) -> !Concrete.lwe_ciphertext<567,2> +// CHECK-NEXT: return %[[V0]] : !Concrete.lwe_ciphertext<567,2> +// CHECK-NEXT: } +func @keyswitch_glwe(%arg0: !TFHE.glwe<{1,1024,64}{2}>) -> !TFHE.glwe<{1,567,64}{2}> { + %0 = "TFHE.keyswitch_glwe"(%arg0) {baseLog = 3 : i32, level = 2 : i32} : (!TFHE.glwe<{1,1024,64}{2}>) -> !TFHE.glwe<{1,567,64}{2}> + return %0 : !TFHE.glwe<{1,567,64}{2}> +} diff --git a/compiler/tests/Dialect/FHELinalg/FHELinalg/apply_mapped_lookup_table.mlir b/compiler/tests/Dialect/FHELinalg/FHELinalg/apply_mapped_lookup_table.mlir new file mode 100644 index 000000000..4822f68df --- /dev/null +++ b/compiler/tests/Dialect/FHELinalg/FHELinalg/apply_mapped_lookup_table.mlir @@ -0,0 +1,11 @@ +// RUN: concretecompiler %s --action=roundtrip 2>&1 | FileCheck %s + + +//CHECK: func @mapped_lut(%[[A0:.*]]: tensor<2x3x!FHE.eint<2>>, %[[A1:.*]]: tensor<5x4xi64>, %[[A2:.*]]: tensor<2x3xindex>) -> tensor<2x3x!FHE.eint<2>> { +//CHECK-NEXT: %[[V0:.*]] = "FHELinalg.apply_mapped_lookup_table"(%[[A0]], %[[A1]], %[[A2]]) : (tensor<2x3x!FHE.eint<2>>, tensor<5x4xi64>, tensor<2x3xindex>) -> tensor<2x3x!FHE.eint<2>> +//CHECK-NEXT: return %[[V0]] : tensor<2x3x!FHE.eint<2>> +//CHECK-NEXT: } +func @mapped_lut(%t: tensor<2x3x!FHE.eint<2>>, %luts: tensor<5x4xi64>, %map: tensor<2x3xindex>) -> tensor<2x3x!FHE.eint<2>> { + %0 = "FHELinalg.apply_mapped_lookup_table"(%t, %luts, %map): (tensor<2x3x!FHE.eint<2>>, tensor<5x4xi64>, tensor<2x3xindex>) -> tensor<2x3x!FHE.eint<2>> + return %0: tensor<2x3x!FHE.eint<2>> +} diff --git a/compiler/tests/Dialect/FHELinalg/FHELinalg/apply_mapped_lut_to_linalg.mlir b/compiler/tests/Dialect/FHELinalg/FHELinalg/apply_mapped_lut_to_linalg.mlir deleted file mode 100644 index 92fc77b02..000000000 --- a/compiler/tests/Dialect/FHELinalg/FHELinalg/apply_mapped_lut_to_linalg.mlir +++ /dev/null @@ -1,31 +0,0 @@ -// RUN: concretecompiler %s --action=dump-tfhe 2>&1 | FileCheck %s - - -//CHECK-LABEL: #map = affine_map<(d0, d1) -> (d0, d1)> -//CHECK-NEXT:module { -//CHECK-NEXT: func @mapped_lut(%arg0: tensor<2x3x!TFHE.glwe<{_,_,_}{2}>>, %[[LUTS:.*]]: tensor<5x4xi64>, %arg2: tensor<2x3xindex>) -> tensor<2x3x!TFHE.glwe<{_,_,_}{2}>> { -//CHECK-NEXT: %[[C0:.*]] = arith.constant 0 : index -//CHECK-NEXT: %[[C1:.*]] = arith.constant 1 : index -//CHECK-NEXT: %[[C2:.*]] = arith.constant 2 : index -//CHECK-NEXT: %[[C3:.*]] = arith.constant 3 : index -//CHECK-NEXT: %[[V0:.*]] = linalg.init_tensor [2, 3] : tensor<2x3x!TFHE.glwe<{_,_,_}{2}>> -//CHECK-NEXT: %[[V1:.*]] = linalg.generic {indexing_maps = [#map, #map, #map], iterator_types = ["parallel", "parallel"]} ins(%arg0, %arg2 : tensor<2x3x!TFHE.glwe<{_,_,_}{2}>>, tensor<2x3xindex>) outs(%0 : tensor<2x3x!TFHE.glwe<{_,_,_}{2}>>) { -//CHECK-NEXT: ^bb0(%arg3: !TFHE.glwe<{_,_,_}{2}>, %[[LUTIDX:.*]]: index, %arg5: !TFHE.glwe<{_,_,_}{2}>): // no predecessors -//DISABLED-CHECK-NEXT: %[[V3:.*]] = tensor.extract_slice %arg1[%[[LUTIDX]], 0] [1, 4] [1, 1] : tensor<5x4xi64> to tensor<4xi64> -//WORKAROUND BEGIN -//CHECK-NEXT: %[[E0:.*]] = tensor.extract %[[LUTS]][%[[LUTIDX]], %[[C0]]] : tensor<5x4xi64> -//CHECK-NEXT: %[[E1:.*]] = tensor.extract %[[LUTS]][%[[LUTIDX]], %[[C1]]] : tensor<5x4xi64> -//CHECK-NEXT: %[[E2:.*]] = tensor.extract %[[LUTS]][%[[LUTIDX]], %[[C2]]] : tensor<5x4xi64> -//CHECK-NEXT: %[[E3:.*]] = tensor.extract %[[LUTS]][%[[LUTIDX]], %[[C3]]] : tensor<5x4xi64> -//CHECK-NEXT: %[[LUT:.*]] = tensor.from_elements %[[E0]], %[[E1]], %[[E2]], %[[E3]] : tensor<4xi64> -//WORKAROUND END -//CHECK-NEXT: %[[V4:.*]] = "TFHE.apply_lookup_table"(%arg3, %[[LUT]]) {baseLogBS = -1 : i32, baseLogKS = -1 : i32, glweDimension = -1 : i32, levelBS = -1 : i32, levelKS = -1 : i32, outputSizeKS = -1 : i32, polynomialSize = -1 : i32} : (!TFHE.glwe<{_,_,_}{2}>, tensor<4xi64>) -> !TFHE.glwe<{_,_,_}{2}> -//CHECK-NEXT: linalg.yield %[[V4]] : !TFHE.glwe<{_,_,_}{2}> -//CHECK-NEXT: } -> tensor<2x3x!TFHE.glwe<{_,_,_}{2}>> -//CHECK-NEXT: return %[[V1]] : tensor<2x3x!TFHE.glwe<{_,_,_}{2}>> -//CHECK-NEXT: } -//CHECK-NEXT: } -func @mapped_lut(%t: tensor<2x3x!FHE.eint<2>>, %luts: tensor<5x4xi64>, %map: tensor<2x3xindex>) -> tensor<2x3x!FHE.eint<2>> { - %1 = "FHELinalg.apply_mapped_lookup_table"(%t, %luts, %map): (tensor<2x3x!FHE.eint<2>>, tensor<5x4xi64>, tensor<2x3xindex>) -> tensor<2x3x!FHE.eint<2>> - return %1: tensor<2x3x!FHE.eint<2>> -} diff --git a/compiler/tests/Dialect/FHELinalg/FHELinalg/apply_multi_lookup_table.mlir b/compiler/tests/Dialect/FHELinalg/FHELinalg/apply_multi_lookup_table.mlir new file mode 100644 index 000000000..f5ec272e6 --- /dev/null +++ b/compiler/tests/Dialect/FHELinalg/FHELinalg/apply_multi_lookup_table.mlir @@ -0,0 +1,10 @@ +// RUN: concretecompiler %s --action=roundtrip 2>&1 | FileCheck %s + +//CHECK: func @multi_lut(%[[A0:.*]]: tensor<4x4x!FHE.eint<2>>, %[[A1:.*]]: tensor<4x4x4xi64>) -> tensor<4x4x!FHE.eint<2>> { +//CHECK-NEXT: %[[V0:.*]] = "FHELinalg.apply_multi_lookup_table"(%[[A0]], %[[A1]]) : (tensor<4x4x!FHE.eint<2>>, tensor<4x4x4xi64>) -> tensor<4x4x!FHE.eint<2>> +//CHECK-NEXT: return %[[V0]] : tensor<4x4x!FHE.eint<2>> +//CHECK-NEXT: } +func @multi_lut(%arg0: tensor<4x4x!FHE.eint<2>>, %arg1: tensor<4x4x4xi64>) -> tensor<4x4x!FHE.eint<2>> { + %1 = "FHELinalg.apply_multi_lookup_table"(%arg0, %arg1): (tensor<4x4x!FHE.eint<2>>, tensor<4x4x4xi64>) -> tensor<4x4x!FHE.eint<2>> + return %1: tensor<4x4x!FHE.eint<2>> +} \ No newline at end of file diff --git a/compiler/tests/Dialect/FHELinalg/FHELinalg/apply_multi_lut_broadcast.mlir b/compiler/tests/Dialect/FHELinalg/FHELinalg/apply_multi_lut_broadcast.mlir new file mode 100644 index 000000000..269f9895b --- /dev/null +++ b/compiler/tests/Dialect/FHELinalg/FHELinalg/apply_multi_lut_broadcast.mlir @@ -0,0 +1,10 @@ +// RUN: concretecompiler %s --action=roundtrip 2>&1 | FileCheck %s + +//CHECK: func @multi_lut(%[[A0:.*]]: tensor<4x3x!FHE.eint<2>>, %[[A1:.*]]: tensor<3x4xi64>) -> tensor<4x3x!FHE.eint<2>> { +//CHECK-NEXT: %[[V0:.*]] = "FHELinalg.apply_multi_lookup_table"(%[[A0]], %[[A1]]) : (tensor<4x3x!FHE.eint<2>>, tensor<3x4xi64>) -> tensor<4x3x!FHE.eint<2>> +//CHECK-NEXT: return %[[V0]] : tensor<4x3x!FHE.eint<2>> +//CHECK-NEXT: } +func @multi_lut(%arg0: tensor<4x3x!FHE.eint<2>>, %arg1: tensor<3x4xi64>) -> tensor<4x3x!FHE.eint<2>> { + %1 = "FHELinalg.apply_multi_lookup_table"(%arg0, %arg1): (tensor<4x3x!FHE.eint<2>>, tensor<3x4xi64>) -> tensor<4x3x!FHE.eint<2>> + return %1: tensor<4x3x!FHE.eint<2>> +} \ No newline at end of file diff --git a/compiler/tests/Dialect/FHELinalg/FHELinalg/apply_multi_lut_to_linalg.mlir b/compiler/tests/Dialect/FHELinalg/FHELinalg/apply_multi_lut_to_linalg.mlir deleted file mode 100644 index c9c1c0ade..000000000 --- a/compiler/tests/Dialect/FHELinalg/FHELinalg/apply_multi_lut_to_linalg.mlir +++ /dev/null @@ -1,23 +0,0 @@ -// RUN: concretecompiler %s --action=dump-tfhe 2>&1 | FileCheck %s - -//CHECK-LABEL: #map0 = affine_map<(d0, d1) -> (d0, d1)> -//CHECK-NEXT: #map1 = affine_map<(d0, d1) -> (d0, d1, 0)> -//CHECK-NEXT: #map2 = affine_map<(d0, d1) -> (d0, d1, 1)> -//CHECK-NEXT: #map3 = affine_map<(d0, d1) -> (d0, d1, 2)> -//CHECK-NEXT: #map4 = affine_map<(d0, d1) -> (d0, d1, 3)> -//CHECK-NEXT: module { -//CHECK-NEXT: func @multi_lut(%arg0: tensor<4x4x!TFHE.glwe<{_,_,_}{2}>>, %arg1: tensor<4x4x4xi64>) -> tensor<4x4x!TFHE.glwe<{_,_,_}{2}>> { -//CHECK-NEXT: %[[V0:.*]] = linalg.init_tensor [4, 4] : tensor<4x4x!TFHE.glwe<{_,_,_}{2}>> -//CHECK-NEXT: %[[V1:.*]] = linalg.generic {indexing_maps = [#map0, #map1, #map2, #map3, #map4, #map0], iterator_types = ["parallel", "parallel"]} ins(%arg0, %arg1, %arg1, %arg1, %arg1 : tensor<4x4x!TFHE.glwe<{_,_,_}{2}>>, tensor<4x4x4xi64>, tensor<4x4x4xi64>, tensor<4x4x4xi64>, tensor<4x4x4xi64>) outs(%[[V0]] : tensor<4x4x!TFHE.glwe<{_,_,_}{2}>>) { -//CHECK-NEXT: ^bb0(%arg2: !TFHE.glwe<{_,_,_}{2}>, %arg3: i64, %arg4: i64, %arg5: i64, %arg6: i64, %arg7: !TFHE.glwe<{_,_,_}{2}>): // no predecessors -//CHECK-NEXT: %[[V2:.*]] = tensor.from_elements %arg3, %arg4, %arg5, %arg6 : tensor<4xi64> -//CHECK-NEXT: %[[V3:.*]] = "TFHE.apply_lookup_table"(%arg2, %[[V2]]) {baseLogBS = -1 : i32, baseLogKS = -1 : i32, glweDimension = -1 : i32, levelBS = -1 : i32, levelKS = -1 : i32, outputSizeKS = -1 : i32, polynomialSize = -1 : i32} : (!TFHE.glwe<{_,_,_}{2}>, tensor<4xi64>) -> !TFHE.glwe<{_,_,_}{2}> -//CHECK-NEXT: linalg.yield %[[V3]] : !TFHE.glwe<{_,_,_}{2}> -//CHECK-NEXT: } -> tensor<4x4x!TFHE.glwe<{_,_,_}{2}>> -//CHECK-NEXT: return %[[V1]] : tensor<4x4x!TFHE.glwe<{_,_,_}{2}>> -//CHECK-NEXT: } -//CHECK-NEXT: } -func @multi_lut(%arg0: tensor<4x4x!FHE.eint<2>>, %arg1: tensor<4x4x4xi64>) -> tensor<4x4x!FHE.eint<2>> { - %1 = "FHELinalg.apply_multi_lookup_table"(%arg0, %arg1): (tensor<4x4x!FHE.eint<2>>, tensor<4x4x4xi64>) -> tensor<4x4x!FHE.eint<2>> - return %1: tensor<4x4x!FHE.eint<2>> -} \ No newline at end of file diff --git a/compiler/tests/Dialect/FHELinalg/FHELinalg/apply_multi_lut_to_linalg_broadcast.mlir b/compiler/tests/Dialect/FHELinalg/FHELinalg/apply_multi_lut_to_linalg_broadcast.mlir deleted file mode 100644 index ec42085c1..000000000 --- a/compiler/tests/Dialect/FHELinalg/FHELinalg/apply_multi_lut_to_linalg_broadcast.mlir +++ /dev/null @@ -1,23 +0,0 @@ -// RUN: concretecompiler %s --action=dump-tfhe 2>&1 | FileCheck %s - -//CHECK-LABEL: #map0 = affine_map<(d0, d1) -> (d0, d1)> -//CHECK-NEXT: #map1 = affine_map<(d0, d1) -> (d1, 0)> -//CHECK-NEXT: #map2 = affine_map<(d0, d1) -> (d1, 1)> -//CHECK-NEXT: #map3 = affine_map<(d0, d1) -> (d1, 2)> -//CHECK-NEXT: #map4 = affine_map<(d0, d1) -> (d1, 3)> -//CHECK-NEXT: module { -//CHECK-NEXT: func @multi_lut(%arg0: tensor<4x3x!TFHE.glwe<{_,_,_}{2}>>, %arg1: tensor<3x4xi64>) -> tensor<4x3x!TFHE.glwe<{_,_,_}{2}>> { -//CHECK-NEXT: %[[V0:.*]] = linalg.init_tensor [4, 3] : tensor<4x3x!TFHE.glwe<{_,_,_}{2}>> -//CHECK-NEXT: %[[V1:.*]] = linalg.generic {indexing_maps = [#map0, #map1, #map2, #map3, #map4, #map0], iterator_types = ["parallel", "parallel"]} ins(%arg0, %arg1, %arg1, %arg1, %arg1 : tensor<4x3x!TFHE.glwe<{_,_,_}{2}>>, tensor<3x4xi64>, tensor<3x4xi64>, tensor<3x4xi64>, tensor<3x4xi64>) outs(%[[V0]] : tensor<4x3x!TFHE.glwe<{_,_,_}{2}>>) { -//CHECK-NEXT: ^bb0(%arg2: !TFHE.glwe<{_,_,_}{2}>, %arg3: i64, %arg4: i64, %arg5: i64, %arg6: i64, %arg7: !TFHE.glwe<{_,_,_}{2}>): // no predecessors -//CHECK-NEXT: %[[V2:.*]] = tensor.from_elements %arg3, %arg4, %arg5, %arg6 : tensor<4xi64> -//CHECK-NEXT: %[[V3:.*]] = "TFHE.apply_lookup_table"(%arg2, %[[V2]]) {baseLogBS = -1 : i32, baseLogKS = -1 : i32, glweDimension = -1 : i32, levelBS = -1 : i32, levelKS = -1 : i32, outputSizeKS = -1 : i32, polynomialSize = -1 : i32} : (!TFHE.glwe<{_,_,_}{2}>, tensor<4xi64>) -> !TFHE.glwe<{_,_,_}{2}> -//CHECK-NEXT: linalg.yield %[[V3]] : !TFHE.glwe<{_,_,_}{2}> -//CHECK-NEXT: } -> tensor<4x3x!TFHE.glwe<{_,_,_}{2}>> -//CHECK-NEXT: return %[[V1]] : tensor<4x3x!TFHE.glwe<{_,_,_}{2}>> -//CHECK-NEXT: } -//CHECK-NEXT: } -func @multi_lut(%arg0: tensor<4x3x!FHE.eint<2>>, %arg1: tensor<3x4xi64>) -> tensor<4x3x!FHE.eint<2>> { - %1 = "FHELinalg.apply_multi_lookup_table"(%arg0, %arg1): (tensor<4x3x!FHE.eint<2>>, tensor<3x4xi64>) -> tensor<4x3x!FHE.eint<2>> - return %1: tensor<4x3x!FHE.eint<2>> -} \ No newline at end of file diff --git a/compiler/tests/Dialect/TFHE/TFHE/op_apply_lookup_table.invalid.mlir b/compiler/tests/Dialect/TFHE/TFHE/op_apply_lookup_table.invalid.mlir deleted file mode 100644 index 99ffc022b..000000000 --- a/compiler/tests/Dialect/TFHE/TFHE/op_apply_lookup_table.invalid.mlir +++ /dev/null @@ -1,9 +0,0 @@ -// RUN: concretecompiler --split-input-file --verify-diagnostics --action=roundtrip %s - -// Bad dimension of the lookup table -func @apply_lookup_table(%arg0: !TFHE.glwe<{1024,12,64}{7}>, %arg1: tensor<4xi2>) -> !TFHE.glwe<{512,10,64}{2}> { - // expected-error @+1 {{'TFHE.apply_lookup_table' op : `l_cst` (operand #2) inner dimension should have size 128(=2^7) to match `ct` (operand #1) elements bitwidth (7)}} - %1 = "TFHE.apply_lookup_table"(%arg0, %arg1) {glweDimension = 1 : i32, polynomialSize = 1024 : i32, levelKS = 2 : i32, baseLogKS = -82 : i32, levelBS = 3 : i32, baseLogBS = -83 : i32, outputSizeKS = 600 : i32}: (!TFHE.glwe<{1024,12,64}{7}>, tensor<4xi2>) -> (!TFHE.glwe<{512,10,64}{2}>) - return %1: !TFHE.glwe<{512,10,64}{2}> -} - diff --git a/compiler/tests/Dialect/TFHE/TFHE/op_apply_lookup_table.mlir b/compiler/tests/Dialect/TFHE/TFHE/op_apply_lookup_table.mlir deleted file mode 100644 index 46fba3264..000000000 --- a/compiler/tests/Dialect/TFHE/TFHE/op_apply_lookup_table.mlir +++ /dev/null @@ -1,10 +0,0 @@ -// RUN: concretecompiler --action=roundtrip %s 2>&1| FileCheck %s - -// CHECK-LABEL: func @apply_lookup_table(%arg0: !TFHE.glwe<{1024,12,64}{7}>, %arg1: tensor<128xi64>) -> !TFHE.glwe<{512,10,64}{2}> -func @apply_lookup_table(%arg0: !TFHE.glwe<{1024,12,64}{7}>, %arg1: tensor<128xi64>) -> !TFHE.glwe<{512,10,64}{2}> { - // CHECK-NEXT: %[[V1:.*]] = "TFHE.apply_lookup_table"(%arg0, %arg1) {baseLogBS = -83 : i32, baseLogKS = -82 : i32, glweDimension = 1 : i32, levelBS = 3 : i32, levelKS = 2 : i32, outputSizeKS = 600 : i32, polynomialSize = 1024 : i32} : (!TFHE.glwe<{1024,12,64}{7}>, tensor<128xi64>) -> !TFHE.glwe<{512,10,64}{2}> - // CHECK-NEXT: return %[[V1]] : !TFHE.glwe<{512,10,64}{2}> - - %1 = "TFHE.apply_lookup_table"(%arg0, %arg1) {glweDimension = 1 : i32, polynomialSize = 1024 : i32, levelKS = 2 : i32, baseLogKS = -82 : i32, levelBS = 3 : i32, baseLogBS = -83 : i32, outputSizeKS = 600 : i32} : (!TFHE.glwe<{1024,12,64}{7}>, tensor<128xi64>) -> (!TFHE.glwe<{512,10,64}{2}>) - return %1: !TFHE.glwe<{512,10,64}{2}> -} diff --git a/compiler/tests/Dialect/TFHE/TFHE/ops.mlir b/compiler/tests/Dialect/TFHE/TFHE/ops.mlir new file mode 100644 index 000000000..fc695247c --- /dev/null +++ b/compiler/tests/Dialect/TFHE/TFHE/ops.mlir @@ -0,0 +1,25 @@ +// RUN: concretecompiler --action=roundtrip %s 2>&1| FileCheck %s + +// CHECK: func @keyswitch_glwe(%[[A0:.*]]: !TFHE.glwe<{1,1024,64}{7}>) -> !TFHE.glwe<{1,527,64}{7}> +func @keyswitch_glwe(%arg0: !TFHE.glwe<{1,1024,64}{7}>) -> !TFHE.glwe<{1,527,64}{7}> { + // CHECK-NEXT: %[[V0:.*]] = "TFHE.keyswitch_glwe"(%[[A0]]) {baseLog = 2 : i32, level = 3 : i32} : (!TFHE.glwe<{1,1024,64}{7}>) -> !TFHE.glwe<{1,527,64}{7}> + // CHECK-NEXT: return %[[V0]] : !TFHE.glwe<{1,527,64}{7} + %0 = "TFHE.keyswitch_glwe"(%arg0) {baseLog = 2 : i32, level = 3 : i32} : (!TFHE.glwe<{1,1024,64}{7}>) -> !TFHE.glwe<{1,527,64}{7}> + return %0: !TFHE.glwe<{1,527,64}{7}> +} + +// CHECK: func @bootstrap_glwe(%[[GLWE:.*]]: !TFHE.glwe<{1,527,64}{7}>, %[[LUT:.*]]: !TFHE.glwe<{1,527,64}{7}>) -> !TFHE.glwe<{1,1024,64}{7}> +func @bootstrap_glwe(%glwe: !TFHE.glwe<{1,527,64}{7}>, %lookup_table_glwe: !TFHE.glwe<{1,527,64}{7}>) -> !TFHE.glwe<{1,1024,64}{7}> { + // CHECK-NEXT: %[[V0:.*]] = "TFHE.bootstrap_glwe"(%[[GLWE]], %[[LUT]]) {baseLog = 2 : i32, glweDimension = 1 : i32, level = 3 : i32, polynomialSize = 2048 : i32} : (!TFHE.glwe<{1,527,64}{7}>, !TFHE.glwe<{1,527,64}{7}>) -> !TFHE.glwe<{1,1024,64}{7}> + // CHECK-NEXT: return %[[V0]] : !TFHE.glwe<{1,1024,64}{7}> + %0 = "TFHE.bootstrap_glwe"(%glwe, %lookup_table_glwe) {baseLog = 2 : i32, glweDimension = 1 : i32, level = 3 : i32, polynomialSize = 2048 : i32} : (!TFHE.glwe<{1,527,64}{7}>, !TFHE.glwe<{1,527,64}{7}>) -> !TFHE.glwe<{1,1024,64}{7}> + return %0 : !TFHE.glwe<{1,1024,64}{7}> +} + +// CHECK: func @glwe_from_table(%[[LUT:.*]]: tensor<128xi64>) -> !TFHE.glwe<{1,1024,64}{7}> +func @glwe_from_table(%lookup_table: tensor<128xi64>) -> !TFHE.glwe<{1,1024,64}{7}> { + // CHECK-NEXT: %[[V0:.*]] = "TFHE.glwe_from_table"(%[[LUT]]) : (tensor<128xi64>) -> !TFHE.glwe<{1,1024,64}{7}> + // CHECK-NEXT: return %[[V0]] : !TFHE.glwe<{1,1024,64}{7}> + %0 = "TFHE.glwe_from_table"(%lookup_table) : (tensor<128xi64>) -> !TFHE.glwe<{1,1024,64}{7}> + return %0 : !TFHE.glwe<{1,1024,64}{7}> +}