diff --git a/cmake/graph-compiler.cmake b/cmake/graph-compiler.cmake index 5aa50c06102533..e33f01125f756c 100644 --- a/cmake/graph-compiler.cmake +++ b/cmake/graph-compiler.cmake @@ -27,3 +27,5 @@ if (NOT DEFINED GRAPH_COMPILER_LIBS) ) set_property(GLOBAL PROPERTY GRAPH_COMPILER_LIBS ${GRAPH_COMPILER_LIBS}) endif () + +get_target_property(GRAPH_COMPILER_INCLUDES GcInterface INTERFACE_INCLUDE_DIRECTORIES) diff --git a/src/common/transformations/CMakeLists.txt b/src/common/transformations/CMakeLists.txt index eb00f434d42dd7..e3191943b4b545 100644 --- a/src/common/transformations/CMakeLists.txt +++ b/src/common/transformations/CMakeLists.txt @@ -36,13 +36,13 @@ target_link_libraries(${TARGET_NAME}_obj PRIVATE openvino::reference openvino::itt openvino::core::dev - ${GRAPH_COMPILER_LIBS} openvino::shape_inference) target_include_directories(${TARGET_NAME}_obj PRIVATE "${PUBLIC_HEADERS_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/src" "${MLIR_INCLUDE_DIRS}" - "${LLVM_INCLUDE_DIRS}") + "${LLVM_INCLUDE_DIRS}" + "${GRAPH_COMPILER_INCLUDES}") add_tpp_mlir_includes(${TARGET_NAME}_obj) diff --git a/src/common/transformations/src/transformations/mlir/convert.cpp b/src/common/transformations/src/transformations/mlir/convert.cpp index db2f5f07cf5b87..00550c9903ac83 100644 --- a/src/common/transformations/src/transformations/mlir/convert.cpp +++ b/src/common/transformations/src/transformations/mlir/convert.cpp @@ -63,7 +63,6 @@ #include "gc/ExecutionEngine/Driver/Driver.h" #endif - #ifdef TPP_MLIR // If TPP is available #include "TPP/Dialect/Check/CheckDialect.h" #include "TPP/Dialect/Perf/PerfDialect.h" @@ -193,7 +192,7 @@ mlir::OwningOpRef ngraph_to_mlir(MLIRContext* context, // This pass converts a group of nodes into a single MLIROp -NodePtr ngraph_to_mlir_op(MLIRContext* context, SubgraphPtr subgraph, bool tpp_mlir_enabled) { +NodePtr ngraph_to_mlir_op(MLIRContext* context, SubgraphPtr subgraph, MlirMode mode) { mlir::OwningOpRef module = ngraph_to_mlir(context, subgraph->inputs, subgraph->nodes, subgraph->outputs); const auto& inputs = subgraph->inputs; @@ -237,7 +236,7 @@ NodePtr ngraph_to_mlir_op(MLIRContext* context, SubgraphPtr subgraph, bool tpp_m } return std::make_shared( subgraph->inputs, - std::make_shared(std::move(module), tpp_mlir_enabled), + std::make_shared(std::move(module), mode), output_types, output_map ); @@ -258,18 +257,18 @@ void replace_subgraph(SubgraphPtr subgraph, NodePtr node) { class Partitioner : public ov::pass::ModelPass { MLIRContext* context; - bool tpp_mlir_enabled; + MlirMode mode; public: OPENVINO_RTTI("Partitioner"); - Partitioner(MLIRContext* context, bool tpp_mlir_enabled) : + Partitioner(MLIRContext* context, MlirMode mode) : context(context), - tpp_mlir_enabled(tpp_mlir_enabled) + mode(mode) {} bool run_on_model(const std::shared_ptr& model) override { SubgraphTracker tracker([this](SubgraphPtr subgraph) { - auto mlir_op = ngraph_to_mlir_op(context, subgraph, tpp_mlir_enabled); + auto mlir_op = ngraph_to_mlir_op(context, subgraph, mode); replace_subgraph(subgraph, mlir_op); OPENVINO_MLIR_DEBUG_PRINT("Created MLIR op: " << mlir_op << "\n"); } @@ -283,7 +282,7 @@ class Partitioner : public ov::pass::ModelPass { }; -void injectMLIR(std::shared_ptr model, MLIRContext* context, bool tpp_mlir_enabled) { +void injectMLIR(std::shared_ptr model, MLIRContext* context, MlirMode mode) { ov::pass::Manager manager; using namespace ov::op; manager.set_per_pass_validation(false); @@ -294,7 +293,7 @@ void injectMLIR(std::shared_ptr model, MLIRContext* context, bool tpp manager.register_pass>(); manager.register_pass(); manager.register_pass(); - manager.register_pass(context, tpp_mlir_enabled); + manager.register_pass(context, mode); manager.run_passes(model); model->validate_nodes_and_infer_types(); } @@ -305,60 +304,57 @@ void loadDialects(MLIRContext* context) { context->loadDialect(); } -#ifdef GRAPH_COMPILER -MLIRContext* get_shared_mlir_context(bool ignore) { - static MLIRContext* context = []() { - OPENVINO_MLIR_DEBUG_PRINT("[ DEBUG ] Using GraphCompiler\n"); - static MLIRContext context(gc::initCompilerAndGetDialects()); - loadDialects(&context); - return &context; - }(); - return context; -} -#else -MLIRContext* get_shared_mlir_context(bool tpp_mlir_enabled_current) { +MLIRContext* get_shared_mlir_context(MlirMode mode) { // Gives MLIRContext instance shared for entire OV process and initialized once upon the initial request // FIXME: Bind with OpenVINO lifetime in the sutable class instead of dirty tricking with static lifetime static std::shared_ptr context; - static bool tpp_mlir_enabled = tpp_mlir_enabled_current; + static bool current_mode = mode; - if(context) { - if(tpp_mlir_enabled_current != tpp_mlir_enabled) { - OPENVINO_MLIR_DEBUG_PRINT("[ DEBUG ] Switched TPP mode, reinitialize MLIR context\n"); - tpp_mlir_enabled = tpp_mlir_enabled_current; - context.reset(); + if (context) { + if (current_mode != mode) { + OPENVINO_MLIR_DEBUG_PRINT("[ DEBUG ] Switching MLIR mode to: "); + current_mode = mode; + } else { + return context.get(); } + } else { + OPENVINO_MLIR_DEBUG_PRINT("[ DEBUG ] MLIR mode: "); } - if (!context) { - +#ifdef GRAPH_COMPILER + if (mode == MLIR_MODE_GC) { + OPENVINO_MLIR_DEBUG_PRINT("GC\n"); + context = std::make_shared(gc::initCompilerAndGetDialects()); + } else { +#endif // Initialize the LLVM machinery llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); - - OPENVINO_MLIR_DEBUG_PRINT("[ DEBUG ] Using TPP_MLIR: "); - if(tpp_mlir_enabled) { - OPENVINO_MLIR_DEBUG_PRINT("YES\n"); +#ifdef TPP_MLIR + if (mode == MLIR_MODE_TPP) { + OPENVINO_MLIR_DEBUG_PRINT("TPP\n"); // Initialize GPU-related LLVM machinery - #ifdef TPP_MLIR - tpp::initializeGpuTargets(); - #endif + tpp::initializeGpuTargets(); } else { - OPENVINO_MLIR_DEBUG_PRINT("NO\n"); - } +#endif + assert(mode == MLIR_MODE_DEFAULT); + OPENVINO_MLIR_DEBUG_PRINT("DEFAULT\n"); +#ifdef TPP_MLIR + } +#endif // Add the following to include *all* MLIR Core dialects, or selectively // include what you need like above. You only need to register dialects that // will be *parsed* by the tool, not the one generated DialectRegistry registry; - if(tpp_mlir_enabled) { - #ifdef TPP_MLIR - registry.insert(); - registry.insert(); - registry.insert(); - #endif +#ifdef TPP_MLIR + if (mode == MLIR_MODE_TPP) { + registry.insert(); + registry.insert(); + registry.insert(); } +#endif registerAllDialects(registry); registerAllExtensions(registry); @@ -367,30 +363,57 @@ MLIRContext* get_shared_mlir_context(bool tpp_mlir_enabled_current) { mlir::tensor::registerTransformDialectExtension(registry); context = std::make_shared(registry); - loadDialects(context.get()); + +#ifdef GRAPH_COMPILER } +#endif + loadDialects(context.get()); return context.get(); } -#endif } // namespace void ov::pass::transformMLIR(std::shared_ptr model) { if(util::getenv_bool("OV_MLIR", true)) { - bool tpp_mlir_default = - #ifdef TPP_MLIR - true; - #else - false; - #endif - bool tpp_mlir_enabled = util::getenv_bool("OV_MLIR_TPP", tpp_mlir_default); - #ifndef TPP_MLIR - OPENVINO_ASSERT(!tpp_mlir_enabled, + const char *default_mode = +#ifdef TPP_MLIR + "TPP"; +#elif defined(GRAPH_COMPILER) + "GC"; +#else + "DEFAULT"; +#endif + auto mode_str = util::getenv_string("OV_MLIR_MODE"); + + if (mode_str == "") { + mode_str = default_mode; + } else { + // Convert to uppercase + std::transform(mode_str.begin(), mode_str.end(), mode_str.begin(), ::toupper); + } + + MlirMode mode; + + if (mode_str == "TPP") { +#ifndef TPP_MLIR + OPENVINO_ASSERT(false, "[ ERROR ] OpenVINO wasn't compiled with TPP_MLIR support, " - "but OV_MLIR_TPP environment variable is set to enable it."); - #endif + "but OV_MLIR_MODE environment variable is set to TPP."); +#endif + mode = MLIR_MODE_TPP; + } else if (mode_str == "GC") { +#ifndef GRAPH_COMPILER + OPENVINO_ASSERT(false, + "[ ERROR ] OpenVINO wasn't compiled with GRAPH_COMPILER support, " + "but OV_MLIR_MODE environment variable is set to GC."); +#endif + mode = MLIR_MODE_GC; + } else { + OPENVINO_ASSERT(mode_str == "DEFAULT"); + mode = MLIR_MODE_DEFAULT; + } - injectMLIR(model, get_shared_mlir_context(tpp_mlir_enabled), tpp_mlir_enabled); + injectMLIR(model, get_shared_mlir_context(mode), mode); } } diff --git a/src/common/transformations/src/transformations/mlir/mlir_op.cpp b/src/common/transformations/src/transformations/mlir/mlir_op.cpp index 9215064aa8b920..8484f502f69c3a 100644 --- a/src/common/transformations/src/transformations/mlir/mlir_op.cpp +++ b/src/common/transformations/src/transformations/mlir/mlir_op.cpp @@ -56,7 +56,9 @@ #ifdef TPP_MLIR // If TPP is available #include "TPP/PassBundles.h" #include "TPP/Passes.h" -#elif defined(GRAPH_COMPILER) +#endif + +#ifdef GRAPH_COMPILER #include "gc/Transforms/Passes.h" #endif @@ -67,78 +69,82 @@ using namespace mlir; using NodePtr = std::shared_ptr; using SymbolPtr = std::shared_ptr; -void prepareMLIRKernelWithoutWrapper(mlir::OwningOpRef& module, bool tpp_mlir_enabled) { +void prepareMLIRKernelWithoutWrapper(mlir::OwningOpRef& module, ov::mlir::MlirMode mode) { PassManager pm(module->getContext()); -#ifdef GRAPH_COMPILER - gc::populateCPUPipeline(pm); -#else - if(tpp_mlir_enabled) { - #ifdef TPP_MLIR + switch (mode) { +#ifdef TPP_MLIR + case ov::mlir::MLIR_MODE_TPP: tpp::DefaultPipelineOptions defPipelineOpts; pm.addPass(tpp::createDefaultPipeline(defPipelineOpts)); - #endif - } else { - // Cleanup before bufferization. - // Simplifies IR to allow better bufferization. - pm.addNestedPass(createCanonicalizerPass()); - pm.addNestedPass(createCSEPass()); - - // Remove empty tensors to avoid converting them into temporary buffers. - pm.addPass(bufferization::createEmptyTensorEliminationPass()); - - pm.addPass(bufferization::createOneShotBufferizePass()); - pm.addNestedPass(bufferization::createFinalizingBufferizePass()); - - // Cleanup after bufferization - possibly remove redundant copies. - pm.addNestedPass(createCanonicalizerPass()); - pm.addNestedPass(createCSEPass()); - - // Deallocation pipeline to avoid memory leaks from created temporary buffers. - pm.addPass(memref::createExpandReallocPass(/*emitDeallocs=*/false)); - pm.addPass(createCanonicalizerPass()); - bufferization::DeallocationOptions deallocOpts; - deallocOpts.privateFuncDynamicOwnership = false; - pm.addPass(bufferization::createOwnershipBasedBufferDeallocationPass(deallocOpts)); - pm.addPass(createCanonicalizerPass()); - pm.addPass(bufferization::createBufferDeallocationSimplificationPass()); - pm.addPass(bufferization::createLowerDeallocationsPass()); - pm.addPass(createCSEPass()); - pm.addPass(createCanonicalizerPass()); - - // Blanket-convert any remaining high-level vector ops to loops if any remain. - pm.addNestedPass(createConvertVectorToSCFPass()); - // pm.addNestedPass(createLinalgGeneralizeNamedOpsPass()); - // Blanket-convert any remaining linalg ops to loops if any remain. - pm.addNestedPass(createConvertLinalgToLoopsPass()); - // Blanket-convert any remaining affine ops if any remain. - pm.addPass(createLowerAffinePass()); - // Convert SCF to CF (always needed). - pm.addPass(createConvertSCFToCFPass()); - // Sprinkle some cleanups. - pm.addPass(createCanonicalizerPass()); - pm.addPass(createCSEPass()); - // Blanket-convert any remaining linalg ops to LLVM if any remain. - // pm.addPass(createConvertLinalgToLLVMPass()); // no such pass - // Convert vector to LLVM (always needed). - pm.addPass(createConvertVectorToLLVMPass()); - // Convert Math to LLVM (always needed). - pm.addNestedPass(createConvertMathToLLVMPass()); - // Expand complicated MemRef operations before lowering them. - pm.addPass(memref::createExpandStridedMetadataPass()); - // The expansion may create affine expressions. Get rid of them. - pm.addPass(createLowerAffinePass()); - // Convert MemRef to LLVM (always needed). - // pm.addPass(memref::createExpandOpsPass()); - pm.addPass(createFinalizeMemRefToLLVMConversionPass()); - // Convert Func to LLVM (always needed). - pm.addPass(createConvertFuncToLLVMPass()); - // Convert Index to LLVM (always needed). - pm.addPass(createConvertIndexToLLVMPass()); - // Convert remaining unrealized_casts (always needed). - pm.addPass(createReconcileUnrealizedCastsPass()); - } + break; +#endif +#ifdef GRAPH_COMPILER + case ov::mlir::MLIR_MODE_GC: + gc::populateCPUPipeline(pm); + break; #endif + default: + assert(ov::mlir::MLIR_MODE_DEFAULT); + // Cleanup before bufferization. + // Simplifies IR to allow better bufferization. + pm.addNestedPass(createCanonicalizerPass()); + pm.addNestedPass(createCSEPass()); + + // Remove empty tensors to avoid converting them into temporary buffers. + pm.addPass(bufferization::createEmptyTensorEliminationPass()); + + pm.addPass(bufferization::createOneShotBufferizePass()); + pm.addNestedPass(bufferization::createFinalizingBufferizePass()); + + // Cleanup after bufferization - possibly remove redundant copies. + pm.addNestedPass(createCanonicalizerPass()); + pm.addNestedPass(createCSEPass()); + + // Deallocation pipeline to avoid memory leaks from created temporary buffers. + pm.addPass(memref::createExpandReallocPass(/*emitDeallocs=*/false)); + pm.addPass(createCanonicalizerPass()); + bufferization::DeallocationOptions deallocOpts; + deallocOpts.privateFuncDynamicOwnership = false; + pm.addPass(bufferization::createOwnershipBasedBufferDeallocationPass(deallocOpts)); + pm.addPass(createCanonicalizerPass()); + pm.addPass(bufferization::createBufferDeallocationSimplificationPass()); + pm.addPass(bufferization::createLowerDeallocationsPass()); + pm.addPass(createCSEPass()); + pm.addPass(createCanonicalizerPass()); + + // Blanket-convert any remaining high-level vector ops to loops if any remain. + pm.addNestedPass(createConvertVectorToSCFPass()); + // pm.addNestedPass(createLinalgGeneralizeNamedOpsPass()); + // Blanket-convert any remaining linalg ops to loops if any remain. + pm.addNestedPass(createConvertLinalgToLoopsPass()); + // Blanket-convert any remaining affine ops if any remain. + pm.addPass(createLowerAffinePass()); + // Convert SCF to CF (always needed). + pm.addPass(createConvertSCFToCFPass()); + // Sprinkle some cleanups. + pm.addPass(createCanonicalizerPass()); + pm.addPass(createCSEPass()); + // Blanket-convert any remaining linalg ops to LLVM if any remain. + // pm.addPass(createConvertLinalgToLLVMPass()); // no such pass + // Convert vector to LLVM (always needed). + pm.addPass(createConvertVectorToLLVMPass()); + // Convert Math to LLVM (always needed). + pm.addNestedPass(createConvertMathToLLVMPass()); + // Expand complicated MemRef operations before lowering them. + pm.addPass(memref::createExpandStridedMetadataPass()); + // The expansion may create affine expressions. Get rid of them. + pm.addPass(createLowerAffinePass()); + // Convert MemRef to LLVM (always needed). + // pm.addPass(memref::createExpandOpsPass()); + pm.addPass(createFinalizeMemRefToLLVMConversionPass()); + // Convert Func to LLVM (always needed). + pm.addPass(createConvertFuncToLLVMPass()); + // Convert Index to LLVM (always needed). + pm.addPass(createConvertIndexToLLVMPass()); + // Convert remaining unrealized_casts (always needed). + pm.addPass(createReconcileUnrealizedCastsPass()); + } auto result = pm.run(module.get()); if (failed(result)) { @@ -259,7 +265,7 @@ namespace mlir { using namespace ::mlir; -MLIREvaluate::MLIREvaluate(OwningOpRef _module, bool tpp_mlir_enabled) : +MLIREvaluate::MLIREvaluate(OwningOpRef _module, MlirMode mode) : module(std::move(_module)) { OPENVINO_MLIR_DEBUG_PRINT( @@ -269,7 +275,7 @@ MLIREvaluate::MLIREvaluate(OwningOpRef _module, bool tpp_mlir_en OPENVINO_MLIR_DEBUG_PRINT( "-----------------------------------------\n"); - prepareMLIRKernelWithoutWrapper(module, tpp_mlir_enabled); + prepareMLIRKernelWithoutWrapper(module, mode); OPENVINO_MLIR_DEBUG_PRINT( "[ DEBUG ] Target LLVM:\n" diff --git a/src/common/transformations/src/transformations/mlir/mlir_op.hpp b/src/common/transformations/src/transformations/mlir/mlir_op.hpp index 72fbcc462cd805..a0ffc58713c30e 100644 --- a/src/common/transformations/src/transformations/mlir/mlir_op.hpp +++ b/src/common/transformations/src/transformations/mlir/mlir_op.hpp @@ -23,13 +23,20 @@ using ::mlir::ModuleOp; using ::mlir::ExecutionEngine; using ::mlir::ModuleOp; +enum MlirMode { + MLIR_MODE_TPP, + MLIR_MODE_GC, + MLIR_MODE_DEFAULT, +}; + + class MLIREvaluate { OwningOpRef module; // FIXME: needs to be kept? std::unique_ptr engine; public: - MLIREvaluate(OwningOpRef _module, bool tpp_mlir_enabled); + MLIREvaluate(OwningOpRef _module, MlirMode mode); bool invoke_packed(std::vector& args); };