mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 03:33:20 +01:00
[LPM] Reinstate r271652 to replace the CALL_ONCE_... macro in the legacy
pass manager with the new llvm::call_once facility. This reverts commit r271657 and re-applies r271652 with a fix to actually work with arguments. In the original version, we just ended up directly calling std::call_once via ADL because of the std::once_flag argument. The llvm::call_once never worked with arguments. Now, llvm::call_once is a variadic template that perfectly forwards everything. As a part of this it had to move to the header and we use a generic functor rather than an explict function pointer. It would be nice to use std::invoke here but we don't have it yet. That means pointer to members won't work here, but that seems a tolerable compromise. I've also tested this by forcing the fallback path, so hopefully it sticks this time. Original commit message: ---- [LPM] Replace the CALL_ONCE_... macro in the legacy pass manager with the new llvm::call_once facility. This facility matches the standard APIs and when the platform supports it actually directly uses the standard provided functionality. This is both more efficient on some platforms and much more TSan friendly. The only remaining user of the cas_flag and home-rolled atomics is the fallback implementation of call_once. I have a patch that removes them entirely, but it needs a Windows patch to land first. This alone substantially cleans up the macros for the legacy pass manager, and should subsume some of the work Mehdi was doing to clear the path for TSan testing of ThinLTO, a really important step to have reliable upstream testing of ThinLTO in all forms. llvm-svn: 271781
This commit is contained in:
parent
460aabc61f
commit
39d7104d20
@ -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
|
||||
|
@ -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)); \
|
||||
}
|
||||
|
||||
//===---------------------------------------------------------------------------
|
||||
|
@ -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
|
||||
|
@ -32,7 +32,7 @@ static sys::Mutex* getManagedStaticMutex() {
|
||||
// We need to use a function local static here, since this can get called
|
||||
// during a static constructor and we need to guarantee that it's initialized
|
||||
// correctly.
|
||||
call_once(mutex_init_flag, initializeMutex);
|
||||
llvm::call_once(mutex_init_flag, initializeMutex);
|
||||
return ManagedStaticMutex;
|
||||
}
|
||||
|
||||
|
@ -116,30 +116,3 @@ void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData,
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void llvm::call_once(once_flag &flag, void (*fptr)(void)) {
|
||||
#if LLVM_THREADING_USE_STD_CALL_ONCE
|
||||
std::call_once(flag, fptr);
|
||||
#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) {
|
||||
fptr();
|
||||
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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user