mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-29 06:30:39 +00:00
Add llvm::function_ref (and a couple of uses of it), representing a type-erased reference to a callable object.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@208025 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
9331beb910
commit
245e8bdfba
@ -55,6 +55,131 @@ struct greater_ptr : public std::binary_function<Ty, Ty, bool> {
|
||||
}
|
||||
};
|
||||
|
||||
/// An efficient, type-erasing, non-owning reference to a callable. This is
|
||||
/// intended for use as the type of a function parameter that is not used
|
||||
/// after the function in question returns.
|
||||
///
|
||||
/// This class does not own the callable, so it is not in general safe to store
|
||||
/// a function_ref.
|
||||
template<typename Fn> class function_ref;
|
||||
|
||||
#if LLVM_HAS_VARIADIC_TEMPLATES
|
||||
|
||||
template<typename Ret, typename ...Params>
|
||||
class function_ref<Ret(Params...)> {
|
||||
Ret (*callback)(void *callable, Params ...params);
|
||||
void *callable;
|
||||
|
||||
template<typename Callable>
|
||||
static Ret callback_fn(void *callable, Params ...params) {
|
||||
return reinterpret_cast<Callable&>(*callable)(
|
||||
std::forward<Params>(params)...);
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename Callable>
|
||||
function_ref(Callable &&callable)
|
||||
: callback(callback_fn<Callable>),
|
||||
callable(reinterpret_cast<void *>(&callable)) {}
|
||||
Ret operator()(Params ...params) const {
|
||||
return callback(callable, std::forward<Params>(params)...);
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
template<typename Ret>
|
||||
class function_ref<Ret()> {
|
||||
Ret (*callback)(void *callable);
|
||||
void *callable;
|
||||
|
||||
template<typename Callable>
|
||||
static Ret callback_fn(void *callable) {
|
||||
return reinterpret_cast<Callable&>(*callable)();
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename Callable>
|
||||
function_ref(Callable &&callable)
|
||||
: callback(callback_fn<Callable>),
|
||||
callable(reinterpret_cast<void *>(&callable)) {}
|
||||
Ret operator()() const { return callback(callable); }
|
||||
};
|
||||
|
||||
template<typename Ret, typename Param1>
|
||||
class function_ref<Ret(Param1)> {
|
||||
Ret (*callback)(void *callable, Param1 param1);
|
||||
void *callable;
|
||||
|
||||
template<typename Callable>
|
||||
static Ret callback_fn(void *callable, Param1 param1) {
|
||||
return reinterpret_cast<Callable&>(*callable)(
|
||||
std::forward<Param1>(param1));
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename Callable>
|
||||
function_ref(Callable &&callable)
|
||||
: callback(callback_fn<Callable>),
|
||||
callable(reinterpret_cast<void *>(&callable)) {}
|
||||
Ret operator()(Param1 param1) {
|
||||
return callback(callable, std::forward<Param1>(param1));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret, typename Param1, typename Param2>
|
||||
class function_ref<Ret(Param1, Param2)> {
|
||||
Ret (*callback)(void *callable, Param1 param1, Param2 param2);
|
||||
void *callable;
|
||||
|
||||
template<typename Callable>
|
||||
static Ret callback_fn(void *callable, Param1 param1, Param2 param2) {
|
||||
return reinterpret_cast<Callable&>(*callable)(
|
||||
std::forward<Param1>(param1),
|
||||
std::forward<Param2>(param2));
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename Callable>
|
||||
function_ref(Callable &&callable)
|
||||
: callback(callback_fn<Callable>),
|
||||
callable(reinterpret_cast<void *>(&callable)) {}
|
||||
Ret operator()(Param1 param1, Param2 param2) {
|
||||
return callback(callable,
|
||||
std::forward<Param1>(param1),
|
||||
std::forward<Param2>(param2));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret, typename Param1, typename Param2, typename Param3>
|
||||
class function_ref<Ret(Param1, Param2, Param3)> {
|
||||
Ret (*callback)(void *callable, Param1 param1, Param2 param2, Param3 param3);
|
||||
void *callable;
|
||||
|
||||
template<typename Callable>
|
||||
static Ret callback_fn(void *callable, Param1 param1, Param2 param2,
|
||||
Param3 param3) {
|
||||
return reinterpret_cast<Callable&>(*callable)(
|
||||
std::forward<Param1>(param1),
|
||||
std::forward<Param2>(param2),
|
||||
std::forward<Param3>(param3));
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename Callable>
|
||||
function_ref(Callable &&callable)
|
||||
: callback(callback_fn<Callable>),
|
||||
callable(reinterpret_cast<void *>(&callable)) {}
|
||||
Ret operator()(Param1 param1, Param2 param2, Param3 param3) {
|
||||
return callback(callable,
|
||||
std::forward<Param1>(param1),
|
||||
std::forward<Param2>(param2),
|
||||
std::forward<Param3>(param3));
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// deleter - Very very very simple method that is used to invoke operator
|
||||
// delete on something. It is used like this:
|
||||
//
|
||||
|
@ -12,11 +12,13 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
|
||||
namespace llvm {
|
||||
class StringRef;
|
||||
|
||||
class CrashRecoveryContextCleanup;
|
||||
|
||||
|
||||
/// \brief Crash recovery helper object.
|
||||
///
|
||||
/// This class implements support for running operations in a safe context so
|
||||
@ -46,21 +48,10 @@ class CrashRecoveryContext {
|
||||
void *Impl;
|
||||
CrashRecoveryContextCleanup *head;
|
||||
|
||||
/// An adaptor to convert an arbitrary functor into a void(void*), void* pair.
|
||||
template<typename T> struct FunctorAdaptor {
|
||||
T Fn;
|
||||
static void invoke(void *Data) {
|
||||
return static_cast<FunctorAdaptor<T>*>(Data)->Fn();
|
||||
}
|
||||
typedef void Callback(void*);
|
||||
Callback *fn() { return &invoke; }
|
||||
void *arg() { return this; }
|
||||
};
|
||||
|
||||
public:
|
||||
CrashRecoveryContext() : Impl(nullptr), head(nullptr) {}
|
||||
~CrashRecoveryContext();
|
||||
|
||||
|
||||
void registerCleanup(CrashRecoveryContextCleanup *cleanup);
|
||||
void unregisterCleanup(CrashRecoveryContextCleanup *cleanup);
|
||||
|
||||
@ -86,11 +77,9 @@ public:
|
||||
/// make as little assumptions as possible about the program state when
|
||||
/// RunSafely has returned false. Clients can use getBacktrace() to retrieve
|
||||
/// the backtrace of the crash on failures.
|
||||
bool RunSafely(void (*Fn)(void*), void *UserData);
|
||||
template<typename Functor>
|
||||
bool RunSafely(Functor Fn) {
|
||||
FunctorAdaptor<Functor> Adaptor = { Fn };
|
||||
return RunSafely(Adaptor.fn(), Adaptor.arg());
|
||||
bool RunSafely(function_ref<void()> Fn);
|
||||
bool RunSafely(void (*Fn)(void*), void *UserData) {
|
||||
return RunSafely([&]() { Fn(UserData); });
|
||||
}
|
||||
|
||||
/// \brief Execute the provide callback function (with the given arguments) in
|
||||
@ -98,12 +87,10 @@ public:
|
||||
/// requested stack size).
|
||||
///
|
||||
/// See RunSafely() and llvm_execute_on_thread().
|
||||
bool RunSafelyOnThread(function_ref<void()>, unsigned RequestedStackSize = 0);
|
||||
bool RunSafelyOnThread(void (*Fn)(void*), void *UserData,
|
||||
unsigned RequestedStackSize = 0);
|
||||
template<typename Functor>
|
||||
bool RunSafelyOnThread(Functor Fn, unsigned RequestedStackSize = 0) {
|
||||
FunctorAdaptor<Functor> Adaptor = { Fn };
|
||||
return RunSafelyOnThread(Adaptor.fn(), Adaptor.arg(), RequestedStackSize);
|
||||
unsigned RequestedStackSize = 0) {
|
||||
return RunSafelyOnThread([&]() { Fn(UserData); }, RequestedStackSize);
|
||||
}
|
||||
|
||||
/// \brief Explicitly trigger a crash recovery in the current process, and
|
||||
|
@ -14,8 +14,7 @@
|
||||
#ifndef LLVM_TRANSFORMS_UTILS_CTOR_UTILS_H
|
||||
#define LLVM_TRANSFORMS_UTILS_CTOR_UTILS_H
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -23,12 +22,10 @@ class GlobalVariable;
|
||||
class Function;
|
||||
class Module;
|
||||
|
||||
typedef bool (*ShouldRemoveCtor)(void *, Function *);
|
||||
|
||||
/// Call "ShouldRemove" for every entry in M's global_ctor list and remove the
|
||||
/// entries for which it returns true. Return true if anything changed.
|
||||
bool optimizeGlobalCtorsList(Module &M, ShouldRemoveCtor ShouldRemove,
|
||||
void *Context);
|
||||
bool optimizeGlobalCtorsList(Module &M,
|
||||
function_ref<bool(Function *)> ShouldRemove);
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
|
@ -301,7 +301,7 @@ void CrashRecoveryContext::Disable() {
|
||||
|
||||
#endif
|
||||
|
||||
bool CrashRecoveryContext::RunSafely(void (*Fn)(void*), void *UserData) {
|
||||
bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
|
||||
// If crash recovery is disabled, do nothing.
|
||||
if (gCrashRecoveryEnabled) {
|
||||
assert(!Impl && "Crash recovery context already initialized!");
|
||||
@ -313,7 +313,7 @@ bool CrashRecoveryContext::RunSafely(void (*Fn)(void*), void *UserData) {
|
||||
}
|
||||
}
|
||||
|
||||
Fn(UserData);
|
||||
Fn();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -334,8 +334,7 @@ const std::string &CrashRecoveryContext::getBacktrace() const {
|
||||
|
||||
namespace {
|
||||
struct RunSafelyOnThreadInfo {
|
||||
void (*Fn)(void*);
|
||||
void *Data;
|
||||
function_ref<void()> Fn;
|
||||
CrashRecoveryContext *CRC;
|
||||
bool Result;
|
||||
};
|
||||
@ -344,11 +343,11 @@ struct RunSafelyOnThreadInfo {
|
||||
static void RunSafelyOnThread_Dispatch(void *UserData) {
|
||||
RunSafelyOnThreadInfo *Info =
|
||||
reinterpret_cast<RunSafelyOnThreadInfo*>(UserData);
|
||||
Info->Result = Info->CRC->RunSafely(Info->Fn, Info->Data);
|
||||
Info->Result = Info->CRC->RunSafely(Info->Fn);
|
||||
}
|
||||
bool CrashRecoveryContext::RunSafelyOnThread(void (*Fn)(void*), void *UserData,
|
||||
bool CrashRecoveryContext::RunSafelyOnThread(function_ref<void()> Fn,
|
||||
unsigned RequestedStackSize) {
|
||||
RunSafelyOnThreadInfo Info = { Fn, UserData, this, false };
|
||||
RunSafelyOnThreadInfo Info = { Fn, this, false };
|
||||
llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info, RequestedStackSize);
|
||||
if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl)
|
||||
CRC->setSwitchedThread();
|
||||
|
@ -54,16 +54,16 @@ namespace {
|
||||
|
||||
bool RemoveUnusedGlobalValue(GlobalValue &GV);
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns true if F contains only a single "ret" instruction.
|
||||
bool isEmptyFunction(void *Context, Function *F) {
|
||||
static bool isEmptyFunction(Function *F) {
|
||||
BasicBlock &Entry = F->getEntryBlock();
|
||||
if (Entry.size() != 1 || !isa<ReturnInst>(Entry.front()))
|
||||
return false;
|
||||
ReturnInst &RI = cast<ReturnInst>(Entry.front());
|
||||
return RI.getReturnValue() == NULL;
|
||||
}
|
||||
}
|
||||
|
||||
char GlobalDCE::ID = 0;
|
||||
INITIALIZE_PASS(GlobalDCE, "globaldce",
|
||||
@ -75,7 +75,7 @@ bool GlobalDCE::runOnModule(Module &M) {
|
||||
bool Changed = false;
|
||||
|
||||
// Remove empty functions from the global ctors list.
|
||||
Changed |= optimizeGlobalCtorsList(M, isEmptyFunction, nullptr);
|
||||
Changed |= optimizeGlobalCtorsList(M, isEmptyFunction);
|
||||
|
||||
// Loop over the module, adding globals which are obviously necessary.
|
||||
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
|
||||
|
@ -3022,10 +3022,9 @@ bool GlobalOpt::runOnModule(Module &M) {
|
||||
LocalChange |= OptimizeFunctions(M);
|
||||
|
||||
// Optimize global_ctors list.
|
||||
LocalChange |= optimizeGlobalCtorsList(M, [](void *C, Function *F) -> bool {
|
||||
GlobalOpt *self = static_cast<GlobalOpt *>(C);
|
||||
return EvaluateStaticConstructor(F, self->DL, self->TLI);
|
||||
}, this);
|
||||
LocalChange |= optimizeGlobalCtorsList(M, [&](Function *F) {
|
||||
return EvaluateStaticConstructor(F, DL, TLI);
|
||||
});
|
||||
|
||||
// Optimize non-address-taken globals.
|
||||
LocalChange |= OptimizeGlobalVars(M);
|
||||
|
@ -132,8 +132,8 @@ GlobalVariable *findGlobalCtors(Module &M) {
|
||||
|
||||
/// Call "ShouldRemove" for every entry in M's global_ctor list and remove the
|
||||
/// entries for which it returns true. Return true if anything changed.
|
||||
bool optimizeGlobalCtorsList(Module &M, ShouldRemoveCtor ShouldRemove,
|
||||
void *Context) {
|
||||
bool optimizeGlobalCtorsList(Module &M,
|
||||
function_ref<bool(Function *)> ShouldRemove) {
|
||||
GlobalVariable *GlobalCtors = findGlobalCtors(M);
|
||||
if (!GlobalCtors)
|
||||
return false;
|
||||
@ -163,7 +163,7 @@ bool optimizeGlobalCtorsList(Module &M, ShouldRemoveCtor ShouldRemove,
|
||||
continue;
|
||||
|
||||
// If we can evaluate the ctor at compile time, do.
|
||||
if (ShouldRemove(Context, F)) {
|
||||
if (ShouldRemove(F)) {
|
||||
Ctors.erase(Ctors.begin() + i);
|
||||
MadeChange = true;
|
||||
--i;
|
||||
|
Loading…
Reference in New Issue
Block a user