// Part of the Concrete Compiler Project, under the BSD3 License with Zama // Exceptions. See // https://github.com/zama-ai/concrete-compiler-internal/blob/main/LICENSE.txt // for license information. #ifndef CONCRETELANG_SUPPORT_COMPILER_ENGINE_H #define CONCRETELANG_SUPPORT_COMPILER_ENGINE_H #include #include #include #include #include #include #include #include namespace mlir { namespace concretelang { bool getEmitGPUOption(); /// Compilation context that acts as the root owner of LLVM and MLIR /// data structures directly and indirectly referenced by artefacts /// produced by the `CompilerEngine`. class CompilationContext { public: CompilationContext(); ~CompilationContext(); mlir::MLIRContext *getMLIRContext(); llvm::LLVMContext *getLLVMContext(); static std::shared_ptr createShared(); protected: mlir::MLIRContext *mlirContext; llvm::LLVMContext *llvmContext; }; /// Compilation options allows to configure the compilation pipeline. struct CompilationOptions { llvm::Optional v0FHEConstraints; llvm::Optional v0Parameter; /// largeIntegerParameter force the compiler engine to lower FHE.eint using /// the large integers strategy with the given parameters. llvm::Optional largeIntegerParameter; bool verifyDiagnostics; bool autoParallelize; bool loopParallelize; bool batchConcreteOps; bool dataflowParallelize; bool optimizeConcrete; /// use GPU during execution by generating GPU operations if possible bool emitGPUOps; llvm::Optional> fhelinalgTileSizes; llvm::Optional clientParametersFuncName; optimizer::Config optimizerConfig; CompilationOptions() : v0FHEConstraints(llvm::None), verifyDiagnostics(false), autoParallelize(false), loopParallelize(false), batchConcreteOps(false), dataflowParallelize(false), optimizeConcrete(true), emitGPUOps(false), clientParametersFuncName(llvm::None), optimizerConfig(optimizer::DEFAULT_CONFIG){}; CompilationOptions(std::string funcname) : CompilationOptions() { clientParametersFuncName = funcname; } }; class CompilerEngine { public: /// Result of an invocation of the `CompilerEngine` with optional /// fields for the results produced by different stages. class CompilationResult { public: CompilationResult(std::shared_ptr compilationContext = CompilationContext::createShared()) : compilationContext(compilationContext) {} llvm::Optional> mlirModuleRef; llvm::Optional clientParameters; llvm::Optional feedback; std::unique_ptr llvmModule; llvm::Optional fheContext; protected: std::shared_ptr compilationContext; }; class Library { std::string outputDirPath; std::vector objectsPath; std::vector clientParametersList; std::vector compilationFeedbackList; /// Path to the runtime library. Will be linked to the output library if set std::string runtimeLibraryPath; bool cleanUp; public: /// Create a library instance on which you can add compilation results. /// Then you can emit a library file with the given path. /// cleanUp at false keeps intermediate .obj files for later use. Library(std::string outputDirPath, std::string runtimeLibraryPath = "", bool cleanUp = true) : outputDirPath(outputDirPath), runtimeLibraryPath(runtimeLibraryPath), cleanUp(cleanUp) {} /// Add a compilation result to the library llvm::Expected addCompilation(CompilationResult &compilation); /// Emit the library artifacts with the previously added compilation result llvm::Error emitArtifacts(bool sharedLib, bool staticLib, bool clientParameters, bool compilationFeedback, bool cppHeader); /// After a shared library has been emitted, its path is here std::string sharedLibraryPath; /// After a static library has been emitted, its path is here std::string staticLibraryPath; /// Returns the path of the shared library static std::string getSharedLibraryPath(std::string outputDirPath); /// Returns the path of the static library static std::string getStaticLibraryPath(std::string outputDirPath); /// Returns the path of the client parameters static std::string getClientParametersPath(std::string outputDirPath); /// Returns the path of the compilation feedback static std::string getCompilationFeedbackPath(std::string outputDirPath); // For advanced use const static std::string OBJECT_EXT, LINKER, LINKER_SHARED_OPT, AR, AR_STATIC_OPT, DOT_STATIC_LIB_EXT, DOT_SHARED_LIB_EXT; void addExtraObjectFilePath(std::string objectFilePath); llvm::Expected emit(std::string path, std::string dotExt, std::string linker, llvm::Optional> extraArgs = {}); ~Library(); private: /// Emit a shared library with the previously added compilation result llvm::Expected emitStatic(); /// Emit a shared library with the previously added compilation result llvm::Expected emitShared(); /// Emit a json ClientParameters corresponding to library content llvm::Expected emitClientParametersJSON(); /// Emit a json CompilationFeedback corresponding to library content llvm::Expected emitCompilationFeedbackJSON(); /// Emit a client header file for this corresponding to library content llvm::Expected emitCppHeader(); }; /// Specification of the exit stage of the compilation pipeline enum class Target { /// Only read sources and produce corresponding MLIR module ROUND_TRIP, /// Read sources and exit before any lowering FHE, /// Read sources and lower all FHE operations to TFHE /// operations TFHE, /// Read sources and lower all FHE and TFHE operations to Concrete /// operations CONCRETE, /// Read sources and lower all FHE and TFHE operations to Concrete /// operations with all linalg ops replaced by loops CONCRETEWITHLOOPS, /// Read sources and lower all FHE, TFHE and Concrete operations to /// BConcrete operations BCONCRETE, /// Read sources and lower all FHE, TFHE and Concrete /// operations to canonical MLIR dialects. Cryptographic operations /// are lowered to invocations of the concrete library. STD, /// Read sources and lower all FHE, TFHE and Concrete /// operations to operations from the LLVM dialect. Cryptographic /// operations are lowered to invocations of the concrete library. LLVM, /// Same as `LLVM`, but lowers to actual LLVM IR instead of the /// LLVM dialect LLVM_IR, /// Same as `LLVM_IR`, but invokes the LLVM optimization pipeline /// to produce optimized LLVM IR OPTIMIZED_LLVM_IR, /// Same as `OPTIMIZED_LLVM_IR`, but compiles and add an object file to a /// futur library LIBRARY }; CompilerEngine(std::shared_ptr compilationContext) : overrideMaxEintPrecision(), overrideMaxMANP(), compilerOptions(), generateClientParameters( compilerOptions.clientParametersFuncName.hasValue()), enablePass([](mlir::Pass *pass) { return true; }), compilationContext(compilationContext) {} llvm::Expected compile(llvm::StringRef s, Target target, llvm::Optional> lib = {}); llvm::Expected compile(std::unique_ptr buffer, Target target, llvm::Optional> lib = {}); llvm::Expected compile(llvm::SourceMgr &sm, Target target, llvm::Optional> lib = {}); llvm::Expected compile(std::vector inputs, std::string outputDirPath, std::string runtimeLibraryPath = "", bool generateSharedLib = true, bool generateStaticLib = true, bool generateClientParameters = true, bool generateCompilationFeedback = true, bool generateCppHeader = true); /// Compile and emit artifact to the given outputDirPath from an LLVM source /// manager. llvm::Expected compile(llvm::SourceMgr &sm, std::string outputDirPath, std::string runtimeLibraryPath = "", bool generateSharedLib = true, bool generateStaticLib = true, bool generateClientParameters = true, bool generateCompilationFeedback = true, bool generateCppHeader = true); void setCompilationOptions(CompilationOptions &options) { compilerOptions = options; if (options.v0FHEConstraints.hasValue()) { setFHEConstraints(*options.v0FHEConstraints); } if (options.clientParametersFuncName.hasValue()) { setGenerateClientParameters(true); } } void setFHEConstraints(const mlir::concretelang::V0FHEConstraint &c); void setMaxEintPrecision(size_t v); void setMaxMANP(size_t v); void setGenerateClientParameters(bool v); void setEnablePass(std::function enablePass); protected: llvm::Optional overrideMaxEintPrecision; llvm::Optional overrideMaxMANP; CompilationOptions compilerOptions; bool generateClientParameters; std::function enablePass; std::shared_ptr compilationContext; private: llvm::Expected> getConcreteOptimizerDescription(CompilationResult &res); llvm::Error determineFHEParameters(CompilationResult &res); }; } // namespace concretelang } // namespace mlir #endif