diff --git a/src/amd/llvm/ac_llvm_helper.cpp b/src/amd/llvm/ac_llvm_helper.cpp index 22e5c080e4a..7b0e7049486 100644 --- a/src/amd/llvm/ac_llvm_helper.cpp +++ b/src/amd/llvm/ac_llvm_helper.cpp @@ -33,6 +33,10 @@ #include #include +#if LLVM_VERSION_MAJOR >= 15 +#include "llvm/CodeGen/SelectionDAGNodes.h" +#endif + #include /* DO NOT REORDER THE HEADERS @@ -48,6 +52,37 @@ using namespace llvm; +#if LLVM_VERSION_MAJOR >= 15 +class RunAtExitForStaticDestructors : public SDNode +{ +public: + /* getSDVTList (protected) calls getValueTypeList (private), which contains static variables. */ + RunAtExitForStaticDestructors(): SDNode(0, 0, DebugLoc(), getSDVTList(MVT::Other)) + { + } +}; +#endif + +void ac_llvm_run_atexit_for_destructors(void) +{ +#if LLVM_VERSION_MAJOR >= 15 + /* LLVM >= 16 registers static variable destructors on the first compile, which gcc + * implements by calling atexit there. Before that, u_queue registers its atexit + * handler to kill all threads. Since exit() runs atexit handlers in the reverse order, + * the LLVM destructors are called first while shader compiler threads may still be + * running, which crashes in LLVM in SelectionDAG.cpp. + * + * The solution is to run the code that declares the LLVM static variables first, + * so that atexit for LLVM is registered first and u_queue is registered after that, + * which ensures that all u_queue threads are terminated before LLVM destructors are + * called. + * + * This just executes the code that declares static variables. + */ + RunAtExitForStaticDestructors(); +#endif +} + bool ac_is_llvm_processor_supported(LLVMTargetMachineRef tm, const char *processor) { TargetMachine *TM = reinterpret_cast(tm); diff --git a/src/amd/llvm/ac_llvm_util.c b/src/amd/llvm/ac_llvm_util.c index f55e8f65dc6..8af0ef15b13 100644 --- a/src/amd/llvm/ac_llvm_util.c +++ b/src/amd/llvm/ac_llvm_util.c @@ -64,6 +64,8 @@ static void ac_init_llvm_target(void) ac_reset_llvm_all_options_occurences(); LLVMParseCommandLineOptions(ARRAY_SIZE(argv), argv, NULL); + + ac_llvm_run_atexit_for_destructors(); } PUBLIC void ac_init_shared_llvm_once(void) diff --git a/src/amd/llvm/ac_llvm_util.h b/src/amd/llvm/ac_llvm_util.h index 5006950255a..a22c3fabca6 100644 --- a/src/amd/llvm/ac_llvm_util.h +++ b/src/amd/llvm/ac_llvm_util.h @@ -78,6 +78,7 @@ struct ac_llvm_compiler { LLVMTargetRef ac_get_llvm_target(const char *triple); const char *ac_get_llvm_processor_name(enum radeon_family family); +void ac_llvm_run_atexit_for_destructors(void); bool ac_is_llvm_processor_supported(LLVMTargetMachineRef tm, const char *processor); void ac_reset_llvm_all_options_occurences(); void ac_add_attr_dereferenceable(LLVMValueRef val, uint64_t bytes);