This is an automated email from the ASF dual-hosted git repository.

kou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/main by this push:
     new d428ef4682 GH-37834: [Gandiva] Migrate to new LLVM PassManager API 
(#37867)
d428ef4682 is described below

commit d428ef4682d3a9ce4cfc2b1ab4653deeafd92a3e
Author: Yue <[email protected]>
AuthorDate: Tue Oct 3 15:21:45 2023 +0800

    GH-37834: [Gandiva] Migrate to new LLVM PassManager API (#37867)
    
    ### Rationale for this change
    In https://github.com/apache/arrow/issues/37834, to support LLVM 17, we 
need to migrate to use the new LLVM PassManager API.
    
    ### What changes are included in this PR?
    
     This PR tries to migrate the legacy PassManager to the new PassManager.
    
    ### Are these changes tested?
    It should be covered by existing unit tests. But more performance tests may 
be needed to verify this change.
    
    ### Are there any user-facing changes?
    No
    
    * Closes: #37834
    
    Lead-authored-by: Yue Ni <[email protected]>
    Co-authored-by: Sutou Kouhei <[email protected]>
    Co-authored-by: Sutou Kouhei <[email protected]>
    Signed-off-by: Sutou Kouhei <[email protected]>
---
 cpp/CMakeLists.txt                  |   1 +
 cpp/cmake_modules/FindLLVMAlt.cmake |  24 ++++---
 cpp/src/gandiva/CMakeLists.txt      |   2 -
 cpp/src/gandiva/engine.cc           | 130 +++++++++++++++++++++++++++---------
 4 files changed, 115 insertions(+), 42 deletions(-)

diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt
index f2906b960e..f0acab0389 100644
--- a/cpp/CMakeLists.txt
+++ b/cpp/CMakeLists.txt
@@ -152,6 +152,7 @@ set(ARROW_DOC_DIR "share/doc/${PROJECT_NAME}")
 set(BUILD_SUPPORT_DIR "${CMAKE_SOURCE_DIR}/build-support")
 
 set(ARROW_LLVM_VERSIONS
+    "17.0"
     "16.0"
     "15.0"
     "14.0"
diff --git a/cpp/cmake_modules/FindLLVMAlt.cmake 
b/cpp/cmake_modules/FindLLVMAlt.cmake
index e980f53fd3..69f680824b 100644
--- a/cpp/cmake_modules/FindLLVMAlt.cmake
+++ b/cpp/cmake_modules/FindLLVMAlt.cmake
@@ -86,16 +86,20 @@ if(LLVM_FOUND)
     target_link_libraries(LLVM::LLVM_LIBS INTERFACE LLVM)
   else()
     # Find the libraries that correspond to the LLVM components
-    llvm_map_components_to_libnames(LLVM_LIBS
-                                    core
-                                    mcjit
-                                    native
-                                    ipo
-                                    bitreader
-                                    target
-                                    linker
-                                    analysis
-                                    debuginfodwarf)
+    set(LLVM_TARGET_COMPONENTS
+        analysis
+        bitreader
+        core
+        debuginfodwarf
+        ipo
+        linker
+        mcjit
+        native
+        target)
+    if(LLVM_VERSION_MAJOR GREATER_EQUAL 14)
+      list(APPEND LLVM_TARGET_COMPONENTS passes)
+    endif()
+    llvm_map_components_to_libnames(LLVM_LIBS ${LLVM_TARGET_COMPONENTS})
     target_link_libraries(LLVM::LLVM_LIBS INTERFACE ${LLVM_LIBS})
 
     if(TARGET LLVMSupport AND NOT ARROW_ZSTD_USE_SHARED)
diff --git a/cpp/src/gandiva/CMakeLists.txt b/cpp/src/gandiva/CMakeLists.txt
index db260b5acc..d2810c39f7 100644
--- a/cpp/src/gandiva/CMakeLists.txt
+++ b/cpp/src/gandiva/CMakeLists.txt
@@ -31,8 +31,6 @@ if(ARROW_WITH_ZSTD AND "${zstd_SOURCE}" STREQUAL "SYSTEM")
   provide_find_module(zstdAlt "Gandiva")
 endif()
 
-add_definitions(-DGANDIVA_LLVM_VERSION=${LLVM_VERSION_MAJOR})
-
 # Set the path where the bitcode file generated, see precompiled/CMakeLists.txt
 set(GANDIVA_PRECOMPILED_BC_PATH "${CMAKE_CURRENT_BINARY_DIR}/irhelpers.bc")
 set(GANDIVA_PRECOMPILED_CC_PATH 
"${CMAKE_CURRENT_BINARY_DIR}/precompiled_bitcode.cc")
diff --git a/cpp/src/gandiva/engine.cc b/cpp/src/gandiva/engine.cc
index 7d75793a3e..b6c78da89d 100644
--- a/cpp/src/gandiva/engine.cc
+++ b/cpp/src/gandiva/engine.cc
@@ -53,18 +53,33 @@
 #include <llvm/IR/LegacyPassManager.h>
 #include <llvm/IR/Verifier.h>
 #include <llvm/Linker/Linker.h>
+#if LLVM_VERSION_MAJOR >= 17
+#include <llvm/TargetParser/SubtargetFeature.h>
+#else
 #include <llvm/MC/SubtargetFeature.h>
+#endif
+#include <llvm/Passes/PassBuilder.h>
 #include <llvm/Support/DynamicLibrary.h>
 #include <llvm/Support/Host.h>
+#include <llvm/Transforms/IPO/GlobalDCE.h>
+#include <llvm/Transforms/IPO/Internalize.h>
 #if LLVM_VERSION_MAJOR >= 14
+#include <llvm/IR/PassManager.h>
 #include <llvm/MC/TargetRegistry.h>
+#include <llvm/Passes/PassPlugin.h>
+#include <llvm/Transforms/IPO/GlobalOpt.h>
+#include <llvm/Transforms/Scalar/NewGVN.h>
+#include <llvm/Transforms/Scalar/SimplifyCFG.h>
+#include <llvm/Transforms/Utils/Mem2Reg.h>
+#include <llvm/Transforms/Vectorize/LoopVectorize.h>
+#include <llvm/Transforms/Vectorize/SLPVectorizer.h>
 #else
 #include <llvm/Support/TargetRegistry.h>
+#include <llvm/Transforms/IPO/PassManagerBuilder.h>
 #endif
 #include <llvm/Support/TargetSelect.h>
 #include <llvm/Support/raw_ostream.h>
 #include <llvm/Transforms/IPO.h>
-#include <llvm/Transforms/IPO/PassManagerBuilder.h>
 #include <llvm/Transforms/InstCombine/InstCombine.h>
 #include <llvm/Transforms/Scalar.h>
 #include <llvm/Transforms/Scalar/GVN.h>
@@ -268,49 +283,104 @@ Status Engine::LoadPreCompiledIR() {
 // a pass for dead code elimination.
 Status Engine::RemoveUnusedFunctions() {
   // Setup an optimiser pipeline
-  std::unique_ptr<llvm::legacy::PassManager> pass_manager(
-      new llvm::legacy::PassManager());
+  llvm::PassBuilder pass_builder;
+  llvm::ModuleAnalysisManager module_am;
+
+  pass_builder.registerModuleAnalyses(module_am);
+  llvm::ModulePassManager module_pm;
 
   std::unordered_set<std::string> used_functions;
   used_functions.insert(functions_to_compile_.begin(), 
functions_to_compile_.end());
 
-  pass_manager->add(
-      llvm::createInternalizePass([&used_functions](const llvm::GlobalValue& 
func) {
-        return (used_functions.find(func.getName().str()) != 
used_functions.end());
+  module_pm.addPass(
+      llvm::InternalizePass([&used_functions](const llvm::GlobalValue& 
variable) -> bool {
+        return used_functions.find(variable.getName().str()) != 
used_functions.end();
       }));
-  pass_manager->add(llvm::createGlobalDCEPass());
-  pass_manager->run(*module_);
+  module_pm.addPass(llvm::GlobalDCEPass());
+
+  module_pm.run(*module_, module_am);
   return Status::OK();
 }
 
+// several passes requiring LLVM 14+ that are not available in the legacy pass 
manager
+#if LLVM_VERSION_MAJOR >= 14
+static void OptimizeModuleWithNewPassManager(llvm::Module& module,
+                                             llvm::TargetIRAnalysis 
target_analysis) {
+  // Setup an optimiser pipeline
+  llvm::PassBuilder pass_builder;
+  llvm::LoopAnalysisManager loop_am;
+  llvm::FunctionAnalysisManager function_am;
+  llvm::CGSCCAnalysisManager cgscc_am;
+  llvm::ModuleAnalysisManager module_am;
+
+  function_am.registerPass([&] { return target_analysis; });
+
+  // Register required analysis managers
+  pass_builder.registerModuleAnalyses(module_am);
+  pass_builder.registerCGSCCAnalyses(cgscc_am);
+  pass_builder.registerFunctionAnalyses(function_am);
+  pass_builder.registerLoopAnalyses(loop_am);
+  pass_builder.crossRegisterProxies(loop_am, function_am, cgscc_am, module_am);
+
+  pass_builder.registerPipelineStartEPCallback([&](llvm::ModulePassManager& 
module_pm,
+                                                   llvm::OptimizationLevel 
Level) {
+    module_pm.addPass(llvm::ModuleInlinerPass());
+
+    llvm::FunctionPassManager function_pm;
+    function_pm.addPass(llvm::InstCombinePass());
+    function_pm.addPass(llvm::PromotePass());
+    function_pm.addPass(llvm::GVNPass());
+    function_pm.addPass(llvm::NewGVNPass());
+    function_pm.addPass(llvm::SimplifyCFGPass());
+    function_pm.addPass(llvm::LoopVectorizePass());
+    function_pm.addPass(llvm::SLPVectorizerPass());
+    
module_pm.addPass(llvm::createModuleToFunctionPassAdaptor(std::move(function_pm)));
+
+    module_pm.addPass(llvm::GlobalOptPass());
+  });
+
+  pass_builder.buildPerModuleDefaultPipeline(llvm::OptimizationLevel::O3)
+      .run(module, module_am);
+}
+#else
+static void OptimizeModuleWithLegacyPassManager(llvm::Module& module,
+                                                llvm::TargetIRAnalysis 
target_analysis) {
+  std::unique_ptr<llvm::legacy::PassManager> pass_manager(
+      new llvm::legacy::PassManager());
+
+  
pass_manager->add(llvm::createTargetTransformInfoWrapperPass(target_analysis));
+  pass_manager->add(llvm::createFunctionInliningPass());
+  pass_manager->add(llvm::createInstructionCombiningPass());
+  pass_manager->add(llvm::createPromoteMemoryToRegisterPass());
+  pass_manager->add(llvm::createGVNPass());
+  pass_manager->add(llvm::createNewGVNPass());
+  pass_manager->add(llvm::createCFGSimplificationPass());
+  pass_manager->add(llvm::createLoopVectorizePass());
+  pass_manager->add(llvm::createSLPVectorizerPass());
+  pass_manager->add(llvm::createGlobalOptimizerPass());
+
+  // run the optimiser
+  llvm::PassManagerBuilder pass_builder;
+  pass_builder.OptLevel = 3;
+  pass_builder.populateModulePassManager(*pass_manager);
+  pass_manager->run(module);
+}
+#endif
+
 // Optimise and compile the module.
 Status Engine::FinalizeModule() {
   if (!cached_) {
     ARROW_RETURN_NOT_OK(RemoveUnusedFunctions());
 
     if (optimize_) {
-      // misc passes to allow for inlining, vectorization, ..
-      std::unique_ptr<llvm::legacy::PassManager> pass_manager(
-          new llvm::legacy::PassManager());
-
-      llvm::TargetIRAnalysis target_analysis =
-          execution_engine_->getTargetMachine()->getTargetIRAnalysis();
-      
pass_manager->add(llvm::createTargetTransformInfoWrapperPass(target_analysis));
-      pass_manager->add(llvm::createFunctionInliningPass());
-      pass_manager->add(llvm::createInstructionCombiningPass());
-      pass_manager->add(llvm::createPromoteMemoryToRegisterPass());
-      pass_manager->add(llvm::createGVNPass());
-      pass_manager->add(llvm::createNewGVNPass());
-      pass_manager->add(llvm::createCFGSimplificationPass());
-      pass_manager->add(llvm::createLoopVectorizePass());
-      pass_manager->add(llvm::createSLPVectorizerPass());
-      pass_manager->add(llvm::createGlobalOptimizerPass());
-
-      // run the optimiser
-      llvm::PassManagerBuilder pass_builder;
-      pass_builder.OptLevel = 3;
-      pass_builder.populateModulePassManager(*pass_manager);
-      pass_manager->run(*module_);
+      auto target_analysis = 
execution_engine_->getTargetMachine()->getTargetIRAnalysis();
+
+// misc passes to allow for inlining, vectorization, ..
+#if LLVM_VERSION_MAJOR >= 14
+      OptimizeModuleWithNewPassManager(*module_, target_analysis);
+#else
+      OptimizeModuleWithLegacyPassManager(*module_, target_analysis);
+#endif
     }
 
     ARROW_RETURN_IF(llvm::verifyModule(*module_, &llvm::errs()),

Reply via email to