diff options
Diffstat (limited to 'llvm/include')
-rw-r--r-- | llvm/include/llvm/CodeGen/Passes.h | 4 | ||||
-rw-r--r-- | llvm/include/llvm/PassSupport.h | 43 | ||||
-rw-r--r-- | llvm/include/llvm/Support/Threading.h | 31 |
3 files changed, 51 insertions, 27 deletions
diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h index 1e01d66a2ce..6c85c250cbb 100644 --- a/llvm/include/llvm/CodeGen/Passes.h +++ b/llvm/include/llvm/CodeGen/Passes.h @@ -377,8 +377,10 @@ namespace llvm { Registry.registerPass(*PI, true); \ return PI; \ } \ + LLVM_DEFINE_ONCE_FLAG(Initialize##passName##PassFlag); \ void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ - CALL_ONCE_INITIALIZATION(initialize##passName##PassOnce) \ + llvm::call_once(Initialize##passName##PassFlag, \ + initialize##passName##PassOnce, std::ref(Registry)); \ } /// This initializer registers TargetMachine constructor, so the pass being diff --git a/llvm/include/llvm/PassSupport.h b/llvm/include/llvm/PassSupport.h index f205c001f53..ba6d84f04ba 100644 --- a/llvm/include/llvm/PassSupport.h +++ b/llvm/include/llvm/PassSupport.h @@ -26,31 +26,13 @@ #include "llvm/PassInfo.h" #include "llvm/PassRegistry.h" #include "llvm/Support/Atomic.h" +#include "llvm/Support/Threading.h" +#include <functional> namespace llvm { class TargetMachine; -#define CALL_ONCE_INITIALIZATION(function) \ - static volatile sys::cas_flag initialized = 0; \ - sys::cas_flag old_val = sys::CompareAndSwap(&initialized, 1, 0); \ - if (old_val == 0) { \ - function(Registry); \ - sys::MemoryFence(); \ - TsanIgnoreWritesBegin(); \ - TsanHappensBefore(&initialized); \ - initialized = 2; \ - TsanIgnoreWritesEnd(); \ - } else { \ - sys::cas_flag tmp = initialized; \ - sys::MemoryFence(); \ - while (tmp != 2) { \ - tmp = initialized; \ - sys::MemoryFence(); \ - } \ - } \ - TsanHappensAfter(&initialized); - #define INITIALIZE_PASS(passName, arg, name, cfg, analysis) \ static void *initialize##passName##PassOnce(PassRegistry &Registry) { \ PassInfo *PI = new PassInfo( \ @@ -59,8 +41,10 @@ class TargetMachine; Registry.registerPass(*PI, true); \ return PI; \ } \ + LLVM_DEFINE_ONCE_FLAG(Initialize##passName##PassFlag); \ void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ - CALL_ONCE_INITIALIZATION(initialize##passName##PassOnce) \ + llvm::call_once(Initialize##passName##PassFlag, \ + initialize##passName##PassOnce, std::ref(Registry)); \ } #define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis) \ @@ -77,8 +61,10 @@ class TargetMachine; Registry.registerPass(*PI, true); \ return PI; \ } \ + LLVM_DEFINE_ONCE_FLAG(Initialize##passName##PassFlag); \ void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ - CALL_ONCE_INITIALIZATION(initialize##passName##PassOnce) \ + llvm::call_once(Initialize##passName##PassFlag, \ + initialize##passName##PassOnce, std::ref(Registry)); \ } #define INITIALIZE_PASS_WITH_OPTIONS(PassName, Arg, Name, Cfg, Analysis) \ @@ -166,8 +152,11 @@ struct RegisterAnalysisGroup : public RegisterAGBase { Registry.registerAnalysisGroup(&agName::ID, 0, *AI, false, true); \ return AI; \ } \ + LLVM_DEFINE_ONCE_FLAG(Initialize##agName##AnalysisGroupFlag); \ void llvm::initialize##agName##AnalysisGroup(PassRegistry &Registry) { \ - CALL_ONCE_INITIALIZATION(initialize##agName##AnalysisGroupOnce) \ + llvm::call_once(Initialize##agName##AnalysisGroupFlag, \ + initialize##agName##AnalysisGroupOnce, \ + std::ref(Registry)); \ } #define INITIALIZE_AG_PASS(passName, agName, arg, name, cfg, analysis, def) \ @@ -184,8 +173,10 @@ struct RegisterAnalysisGroup : public RegisterAGBase { true); \ return AI; \ } \ + LLVM_DEFINE_ONCE_FLAG(Initialize##passName##PassFlag); \ void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ - CALL_ONCE_INITIALIZATION(initialize##passName##PassOnce) \ + llvm::call_once(Initialize##passName##PassFlag, \ + initialize##passName##PassOnce, std::ref(Registry)); \ } #define INITIALIZE_AG_PASS_BEGIN(passName, agName, arg, n, cfg, analysis, def) \ @@ -203,8 +194,10 @@ struct RegisterAnalysisGroup : public RegisterAGBase { Registry.registerAnalysisGroup(&agName::ID, &passName::ID, *AI, def, true); \ return AI; \ } \ + LLVM_DEFINE_ONCE_FLAG(Initialize##passName##PassFlag); \ void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ - CALL_ONCE_INITIALIZATION(initialize##passName##PassOnce) \ + llvm::call_once(Initialize##passName##PassFlag, \ + initialize##passName##PassOnce, std::ref(Registry)); \ } //===--------------------------------------------------------------------------- diff --git a/llvm/include/llvm/Support/Threading.h b/llvm/include/llvm/Support/Threading.h index b51d1f97fa9..9804dd8aff6 100644 --- a/llvm/include/llvm/Support/Threading.h +++ b/llvm/include/llvm/Support/Threading.h @@ -16,7 +16,9 @@ #define LLVM_SUPPORT_THREADING_H #include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX +#include "llvm/Support/Compiler.h" #include <ciso646> // So we can check the C++ standard lib macros. +#include <functional> // We use std::call_once on all Unix platforms except for NetBSD with // libstdc++. That platform has a bug they are working to fix, and they'll @@ -84,7 +86,34 @@ namespace llvm { /// /// \param flag Flag used for tracking whether or not this has run. /// \param UserFn Function to call once. - void call_once(once_flag &flag, void (*UserFn)(void)); + template <typename Function, typename... Args> + void call_once(once_flag &flag, Function &&F, Args &&... ArgList) { +#if LLVM_THREADING_USE_STD_CALL_ONCE + std::call_once(flag, std::forward<Function>(F), + std::forward<Args>(ArgList)...); +#else + // For other platforms we use a generic (if brittle) version based on our + // atomics. + sys::cas_flag old_val = sys::CompareAndSwap(&flag, Wait, Uninitialized); + if (old_val == Uninitialized) { + std::forward<Function>(F)(std::forward<Args>(ArgList)...); + sys::MemoryFence(); + TsanIgnoreWritesBegin(); + TsanHappensBefore(&flag); + flag = Done; + TsanIgnoreWritesEnd(); + } else { + // Wait until any thread doing the call has finished. + sys::cas_flag tmp = flag; + sys::MemoryFence(); + while (tmp != Done) { + tmp = flag; + sys::MemoryFence(); + } + } + TsanHappensAfter(&flag); +#endif + } } #endif |