diff --git a/src/gallium/auxiliary/gallivm/lp_bld.h b/src/gallium/auxiliary/gallivm/lp_bld.h index fd2a4943f56..24e64fec2bf 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld.h +++ b/src/gallium/auxiliary/gallivm/lp_bld.h @@ -83,19 +83,12 @@ #define LLVMInsertBasicBlock ILLEGAL_LLVM_FUNCTION #define LLVMCreateBuilder ILLEGAL_LLVM_FUNCTION -#if LLVM_VERSION_MAJOR >= 15 -#define GALLIVM_HAVE_CORO 0 -#define GALLIVM_USE_NEW_PASS 1 -#elif LLVM_VERSION_MAJOR >= 8 -#define GALLIVM_HAVE_CORO 1 -#define GALLIVM_USE_NEW_PASS 0 +#if LLVM_VERSION_MAJOR >= 8 +#define GALLIVM_COROUTINES 1 #else -#define GALLIVM_HAVE_CORO 0 -#define GALLIVM_USE_NEW_PASS 0 +#define GALLIVM_COROUTINES 0 #endif -#define GALLIVM_COROUTINES (GALLIVM_HAVE_CORO || GALLIVM_USE_NEW_PASS) - /* LLVM is transitioning to "opaque pointers", and as such deprecates * LLVMBuildGEP, LLVMBuildCall, LLVMBuildLoad, replacing them with * LLVMBuildGEP2, LLVMBuildCall2, LLVMBuildLoad2 respectivelly. diff --git a/src/gallium/auxiliary/gallivm/lp_bld_init.c b/src/gallium/auxiliary/gallivm/lp_bld_init.c index 62d26141175..195cfa7cdc9 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_init.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_init.c @@ -43,18 +43,6 @@ #include #include #include -#if GALLIVM_USE_NEW_PASS == 1 -#include -#elif GALLIVM_HAVE_CORO == 1 -#include -#if LLVM_VERSION_MAJOR >= 7 -#include -#endif -#if LLVM_VERSION_MAJOR <= 8 && (DETECT_ARCH_AARCH64 || DETECT_ARCH_ARM || DETECT_ARCH_S390 || DETECT_ARCH_MIPS64) -#include -#endif -#include -#endif unsigned gallivm_perf = 0; @@ -115,23 +103,6 @@ enum LLVM_CodeGenOpt_Level { static bool create_pass_manager(struct gallivm_state *gallivm) { -#if GALLIVM_USE_NEW_PASS == 0 - assert(!gallivm->passmgr); - assert(gallivm->target); - - gallivm->passmgr = LLVMCreateFunctionPassManagerForModule(gallivm->module); - if (!gallivm->passmgr) - return false; - -#if GALLIVM_HAVE_CORO == 1 - gallivm->cgpassmgr = LLVMCreatePassManager(); -#endif - /* - * TODO: some per module pass manager with IPO passes might be helpful - - * the generated texture functions may benefit from inlining if they are - * simple, or constant propagation into them, etc. - */ - { char *td_str; // New ones from the Module. @@ -140,58 +111,7 @@ create_pass_manager(struct gallivm_state *gallivm) free(td_str); } -#if GALLIVM_HAVE_CORO == 1 -#if LLVM_VERSION_MAJOR <= 8 && (DETECT_ARCH_AARCH64 || DETECT_ARCH_ARM || DETECT_ARCH_S390 || DETECT_ARCH_MIPS64) - LLVMAddArgumentPromotionPass(gallivm->cgpassmgr); - LLVMAddFunctionAttrsPass(gallivm->cgpassmgr); -#endif - LLVMAddCoroEarlyPass(gallivm->cgpassmgr); - LLVMAddCoroSplitPass(gallivm->cgpassmgr); - LLVMAddCoroElidePass(gallivm->cgpassmgr); -#endif - - if ((gallivm_perf & GALLIVM_PERF_NO_OPT) == 0) { - /* - * TODO: Evaluate passes some more - keeping in mind - * both quality of generated code and compile times. - */ - /* - * NOTE: if you change this, don't forget to change the output - * with GALLIVM_DEBUG_DUMP_BC in gallivm_compile_module. - */ - LLVMAddScalarReplAggregatesPass(gallivm->passmgr); - LLVMAddEarlyCSEPass(gallivm->passmgr); - LLVMAddCFGSimplificationPass(gallivm->passmgr); - /* - * FIXME: LICM is potentially quite useful. However, for some - * rather crazy shaders the compile time can reach _hours_ per shader, - * due to licm implying lcssa (since llvm 3.5), which can take forever. - * Even for sane shaders, the cost of licm is rather high (and not just - * due to lcssa, licm itself too), though mostly only in cases when it - * can actually move things, so having to disable it is a pity. - * LLVMAddLICMPass(gallivm->passmgr); - */ - LLVMAddReassociatePass(gallivm->passmgr); - LLVMAddPromoteMemoryToRegisterPass(gallivm->passmgr); -#if LLVM_VERSION_MAJOR <= 11 - LLVMAddConstantPropagationPass(gallivm->passmgr); -#else - LLVMAddInstructionSimplifyPass(gallivm->passmgr); -#endif - LLVMAddInstructionCombiningPass(gallivm->passmgr); - LLVMAddGVNPass(gallivm->passmgr); - } - else { - /* We need at least this pass to prevent the backends to fail in - * unexpected ways. - */ - LLVMAddPromoteMemoryToRegisterPass(gallivm->passmgr); - } -#if GALLIVM_HAVE_CORO == 1 - LLVMAddCoroCleanupPass(gallivm->passmgr); -#endif -#endif - return true; + return lp_passmgr_create(gallivm->module, &gallivm->passmgr); } /** @@ -201,17 +121,7 @@ create_pass_manager(struct gallivm_state *gallivm) void gallivm_free_ir(struct gallivm_state *gallivm) { -#if GALLIVM_USE_NEW_PASS == 0 - if (gallivm->passmgr) { - LLVMDisposePassManager(gallivm->passmgr); - } - -#if GALLIVM_HAVE_CORO == 1 - if (gallivm->cgpassmgr) { - LLVMDisposePassManager(gallivm->cgpassmgr); - } -#endif -#endif + lp_passmgr_dispose(gallivm->passmgr); if (gallivm->engine) { /* This will already destroy any associated module */ @@ -239,12 +149,7 @@ gallivm_free_ir(struct gallivm_state *gallivm) gallivm->target = NULL; gallivm->module = NULL; gallivm->module_name = NULL; -#if GALLIVM_USE_NEW_PASS == 0 -#if GALLIVM_HAVE_CORO == 1 - gallivm->cgpassmgr = NULL; -#endif gallivm->passmgr = NULL; -#endif gallivm->context = NULL; gallivm->builder = NULL; gallivm->cache = NULL; @@ -556,8 +461,6 @@ void lp_init_clock_hook(struct gallivm_state *gallivm) void gallivm_compile_module(struct gallivm_state *gallivm) { - int64_t time_begin = 0; - assert(!gallivm->compiled); if (gallivm->builder) { @@ -592,65 +495,10 @@ gallivm_compile_module(struct gallivm_state *gallivm) "[-mattr=<-mattr option(s)>]"); } - if (gallivm_debug & GALLIVM_DEBUG_PERF) - time_begin = os_time_get(); - -#if GALLIVM_USE_NEW_PASS == 1 - char passes[1024]; - passes[0] = 0; - - /* - * there should be some way to combine these two pass runs but I'm not seeing it, - * at the time of writing. - */ - strcpy(passes, "default"); - - LLVMPassBuilderOptionsRef opts = LLVMCreatePassBuilderOptions(); - LLVMRunPasses(gallivm->module, passes, LLVMGetExecutionEngineTargetMachine(gallivm->engine), opts); - - if (!(gallivm_perf & GALLIVM_PERF_NO_OPT)) -#if LLVM_VERSION_MAJOR >= 18 - strcpy(passes, "sroa,early-cse,simplifycfg,reassociate,mem2reg,instsimplify,instcombine"); -#else - strcpy(passes, "sroa,early-cse,simplifycfg,reassociate,mem2reg,instsimplify,instcombine"); -#endif - else - strcpy(passes, "mem2reg"); - - LLVMRunPasses(gallivm->module, passes, LLVMGetExecutionEngineTargetMachine(gallivm->engine), opts); - LLVMDisposePassBuilderOptions(opts); -#else -#if GALLIVM_HAVE_CORO == 1 - LLVMRunPassManager(gallivm->cgpassmgr, gallivm->module); -#endif - /* Run optimization passes */ - LLVMInitializeFunctionPassManager(gallivm->passmgr); - LLVMValueRef func; - func = LLVMGetFirstFunction(gallivm->module); - while (func) { - if (0) { - debug_printf("optimizing func %s...\n", LLVMGetValueName(func)); - } - - /* Disable frame pointer omission on debug/profile builds */ - /* XXX: And workaround http://llvm.org/PR21435 */ -#if MESA_DEBUG || defined(PROFILE) || DETECT_ARCH_X86 || DETECT_ARCH_X86_64 - LLVMAddTargetDependentFunctionAttr(func, "no-frame-pointer-elim", "true"); - LLVMAddTargetDependentFunctionAttr(func, "no-frame-pointer-elim-non-leaf", "true"); -#endif - - LLVMRunFunctionPassManager(gallivm->passmgr, func); - func = LLVMGetNextFunction(func); - } - LLVMFinalizeFunctionPassManager(gallivm->passmgr); -#endif - if (gallivm_debug & GALLIVM_DEBUG_PERF) { - int64_t time_end = os_time_get(); - int time_msec = (int)((time_end - time_begin) / 1000); - assert(gallivm->module_name); - debug_printf("optimizing module %s took %d msec\n", - gallivm->module_name, time_msec); - } + lp_passmgr_run(gallivm->passmgr, + gallivm->module, + LLVMGetExecutionEngineTargetMachine(gallivm->engine), + gallivm->module_name); /* Setting the module's DataLayout to an empty string will cause the * ExecutionEngine to copy to the DataLayout string from its target machine diff --git a/src/gallium/auxiliary/gallivm/lp_bld_init.h b/src/gallium/auxiliary/gallivm/lp_bld_init.h index f53702f17a1..62ad8a9a60a 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_init.h +++ b/src/gallium/auxiliary/gallivm/lp_bld_init.h @@ -33,6 +33,7 @@ #include "util/compiler.h" #include "util/u_pointer.h" // for func_pointer #include "lp_bld.h" +#include "lp_bld_passmgr.h" #include #ifdef __cplusplus @@ -46,12 +47,7 @@ struct gallivm_state LLVMModuleRef module; LLVMExecutionEngineRef engine; LLVMTargetDataRef target; -#if GALLIVM_USE_NEW_PASS == 0 - LLVMPassManagerRef passmgr; -#if GALLIVM_HAVE_CORO == 1 - LLVMPassManagerRef cgpassmgr; -#endif -#endif + struct lp_passmgr *passmgr; LLVMContextRef context; LLVMBuilderRef builder; LLVMMCJITMemoryManagerRef memorymgr; diff --git a/src/gallium/auxiliary/gallivm/lp_bld_passmgr.c b/src/gallium/auxiliary/gallivm/lp_bld_passmgr.c new file mode 100644 index 00000000000..0fd61895d73 --- /dev/null +++ b/src/gallium/auxiliary/gallivm/lp_bld_passmgr.c @@ -0,0 +1,234 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "util/u_debug.h" +#include "util/os_time.h" +#include "lp_bld_debug.h" +#include "lp_bld_passmgr.h" +#include "lp_bld_init.h" + +#if LLVM_VERSION_MAJOR >= 15 +#define HAVE_CORO 0 +#define USE_NEW_PASS 1 +#elif LLVM_VERSION_MAJOR >= 8 +#define HAVE_CORO 1 +#define USE_NEW_PASS 0 +#else +#define HAVE_CORO 0 +#define USE_NEW_PASS 0 +#endif + +#if USE_NEW_PASS == 1 +#include +#elif HAVE_CORO == 1 +#include +#if LLVM_VERSION_MAJOR >= 7 +#include +#endif +#if LLVM_VERSION_MAJOR <= 8 && (DETECT_ARCH_AARCH64 || DETECT_ARCH_ARM || DETECT_ARCH_S390 || DETECT_ARCH_MIPS64) +#include +#endif +#include +#endif + +#if USE_NEW_PASS == 0 +struct lp_passmgr { + LLVMPassManagerRef passmgr; +#if HAVE_CORO == 1 + LLVMPassManagerRef cgpassmgr; +#endif +}; +#else +struct lp_passmgr; +#endif + +bool +lp_passmgr_create(LLVMModuleRef module, struct lp_passmgr **mgr_p) +{ + void *mgr = NULL; +#if USE_NEW_PASS == 0 + mgr = CALLOC_STRUCT(lp_passmgr); + if (!mgr) + return false; + + mgr->passmgr = LLVMCreateFunctionPassManagerForModule(module); + if (!mgr->passmgr) { + free(mgr); + return false; + } + +#if HAVE_CORO == 1 + mgr->cgpassmgr = LLVMCreatePassManager(); +#endif + /* + * TODO: some per module pass manager with IPO passes might be helpful - + * the generated texture functions may benefit from inlining if they are + * simple, or constant propagation into them, etc. + */ + +#if HAVE_CORO == 1 +#if LLVM_VERSION_MAJOR <= 8 && (DETECT_ARCH_AARCH64 || DETECT_ARCH_ARM || DETECT_ARCH_S390 || DETECT_ARCH_MIPS64) + LLVMAddArgumentPromotionPass(mgr->cgpassmgr); + LLVMAddFunctionAttrsPass(mgr->cgpassmgr); +#endif + LLVMAddCoroEarlyPass(mgr->cgpassmgr); + LLVMAddCoroSplitPass(mgr->cgpassmgr); + LLVMAddCoroElidePass(mgr->cgpassmgr); +#endif + + if ((gallivm_perf & GALLIVM_PERF_NO_OPT) == 0) { + /* + * TODO: Evaluate passes some more - keeping in mind + * both quality of generated code and compile times. + */ + /* + * NOTE: if you change this, don't forget to change the output + * with GALLIVM_DEBUG_DUMP_BC in gallivm_compile_module. + */ + LLVMAddScalarReplAggregatesPass(mgr->passmgr); + LLVMAddEarlyCSEPass(mgr->passmgr); + LLVMAddCFGSimplificationPass(mgr->passmgr); + /* + * FIXME: LICM is potentially quite useful. However, for some + * rather crazy shaders the compile time can reach _hours_ per shader, + * due to licm implying lcssa (since llvm 3.5), which can take forever. + * Even for sane shaders, the cost of licm is rather high (and not just + * due to lcssa, licm itself too), though mostly only in cases when it + * can actually move things, so having to disable it is a pity. + * LLVMAddLICMPass(mgr->passmgr); + */ + LLVMAddReassociatePass(mgr->passmgr); + LLVMAddPromoteMemoryToRegisterPass(mgr->passmgr); +#if LLVM_VERSION_MAJOR <= 11 + LLVMAddConstantPropagationPass(mgr->passmgr); +#else + LLVMAddInstructionSimplifyPass(mgr->passmgr); +#endif + LLVMAddInstructionCombiningPass(mgr->passmgr); + LLVMAddGVNPass(mgr->passmgr); + } + else { + /* We need at least this pass to prevent the backends to fail in + * unexpected ways. + */ + LLVMAddPromoteMemoryToRegisterPass(mgr->passmgr); + } +#if HAVE_CORO == 1 + LLVMAddCoroCleanupPass(mgr->passmgr); +#endif +#endif + *mgr_p = mgr; + return true; +} + +void +lp_passmgr_run(struct lp_passmgr *mgr, + LLVMModuleRef module, + LLVMTargetMachineRef tm, + const char *module_name) +{ + int64_t time_begin; + + if (gallivm_debug & GALLIVM_DEBUG_PERF) + time_begin = os_time_get(); + +#if USE_NEW_PASS == 1 + char passes[1024]; + passes[0] = 0; + + /* + * there should be some way to combine these two pass runs but I'm not seeing it, + * at the time of writing. + */ + strcpy(passes, "default"); + + LLVMPassBuilderOptionsRef opts = LLVMCreatePassBuilderOptions(); + LLVMRunPasses(module, passes, tm, opts); + + if (!(gallivm_perf & GALLIVM_PERF_NO_OPT)) +#if LLVM_VERSION_MAJOR >= 18 + strcpy(passes, "sroa,early-cse,simplifycfg,reassociate,mem2reg,instsimplify,instcombine"); +#else + strcpy(passes, "sroa,early-cse,simplifycfg,reassociate,mem2reg,instsimplify,instcombine"); +#endif + else + strcpy(passes, "mem2reg"); + + LLVMRunPasses(module, passes, tm, opts); + LLVMDisposePassBuilderOptions(opts); +#else +#if HAVE_CORO == 1 + LLVMRunPassManager(mgr->cgpassmgr, module); +#endif + /* Run optimization passes */ + LLVMInitializeFunctionPassManager(mgr->passmgr); + LLVMValueRef func; + func = LLVMGetFirstFunction(module); + while (func) { + if (0) { + debug_printf("optimizing func %s...\n", LLVMGetValueName(func)); + } + + /* Disable frame pointer omission on debug/profile builds */ + /* XXX: And workaround http://llvm.org/PR21435 */ +#if MESA_DEBUG || defined(PROFILE) || DETECT_ARCH_X86 || DETECT_ARCH_X86_64 + LLVMAddTargetDependentFunctionAttr(func, "no-frame-pointer-elim", "true"); + LLVMAddTargetDependentFunctionAttr(func, "no-frame-pointer-elim-non-leaf", "true"); +#endif + + LLVMRunFunctionPassManager(mgr->passmgr, func); + func = LLVMGetNextFunction(func); + } + LLVMFinalizeFunctionPassManager(mgr->passmgr); +#endif + if (gallivm_debug & GALLIVM_DEBUG_PERF) { + int64_t time_end = os_time_get(); + int time_msec = (int)((time_end - time_begin) / 1000); + assert(module_name); + debug_printf("optimizing module %s took %d msec\n", + module_name, time_msec); + } +} + +void +lp_passmgr_dispose(struct lp_passmgr *mgr) +{ +#if USE_NEW_PASS == 0 + if (mgr->passmgr) { + LLVMDisposePassManager(mgr->passmgr); + mgr->passmgr = NULL; + } + +#if HAVE_CORO == 1 + if (mgr->cgpassmgr) { + LLVMDisposePassManager(mgr->cgpassmgr); + mgr->cgpassmgr = NULL; + } +#endif + FREE(mgr); +#endif +} diff --git a/src/gallium/auxiliary/gallivm/lp_bld_passmgr.h b/src/gallium/auxiliary/gallivm/lp_bld_passmgr.h new file mode 100644 index 00000000000..4ebf6149117 --- /dev/null +++ b/src/gallium/auxiliary/gallivm/lp_bld_passmgr.h @@ -0,0 +1,55 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef LP_BLD_PASSMGR_H +#define LP_BLD_PASSMGR_H + +#include "lp_bld.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct lp_passmgr; + +/* + * mgr can be returned as NULL for modern pass mgr handling + * so use a bool to denote success/fail. + */ +bool lp_passmgr_create(LLVMModuleRef module, struct lp_passmgr **mgr); +void lp_passmgr_run(struct lp_passmgr *mgr, + LLVMModuleRef module, + LLVMTargetMachineRef tm, + const char *module_name); +void lp_passmgr_dispose(struct lp_passmgr *mgr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/gallium/auxiliary/meson.build b/src/gallium/auxiliary/meson.build index 35ad5247b4c..53459aa2d4a 100644 --- a/src/gallium/auxiliary/meson.build +++ b/src/gallium/auxiliary/meson.build @@ -366,6 +366,8 @@ if draw_with_llvm 'gallivm/lp_bld_nir_soa.c', 'gallivm/lp_bld_pack.c', 'gallivm/lp_bld_pack.h', + 'gallivm/lp_bld_passmgr.h', + 'gallivm/lp_bld_passmgr.c', 'gallivm/lp_bld_printf.c', 'gallivm/lp_bld_printf.h', 'gallivm/lp_bld_quad.c',