diff --git a/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp b/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp index e213f7e4be1..a5e84d708f2 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp +++ b/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp @@ -62,6 +62,7 @@ #include #include #include +#include #if LLVM_VERSION_MAJOR >= 15 #include #endif @@ -100,6 +101,8 @@ #include "lp_bld_misc.h" #include "lp_bld_debug.h" +static void lp_run_atexit_for_destructors(void); + namespace { class LLVMEnsureMultithreaded { @@ -147,6 +150,7 @@ static void init_native_targets() } } #endif + lp_run_atexit_for_destructors(); } extern "C" void @@ -623,3 +627,33 @@ lp_set_module_stack_alignment_override(LLVMModuleRef MRef, unsigned align) M->setOverrideStackAlignment(align); #endif } + +using namespace llvm; + +class GallivmRunAtExitForStaticDestructors : public SDNode +{ +public: + /* getSDVTList (protected) calls getValueTypeList (private), which contains static variables. */ + GallivmRunAtExitForStaticDestructors(): SDNode(0, 0, DebugLoc(), getSDVTList(MVT::Other)) + { + } +}; + +static void +lp_run_atexit_for_destructors(void) +{ + /* 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. + */ + GallivmRunAtExitForStaticDestructors(); +}