mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-05-16 07:38:43 +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
|
// deleter - Very very very simple method that is used to invoke operator
|
||||||
// delete on something. It is used like this:
|
// delete on something. It is used like this:
|
||||||
//
|
//
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "llvm/ADT/STLExtras.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class StringRef;
|
class StringRef;
|
||||||
|
|
||||||
@ -46,17 +48,6 @@ class CrashRecoveryContext {
|
|||||||
void *Impl;
|
void *Impl;
|
||||||
CrashRecoveryContextCleanup *head;
|
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:
|
public:
|
||||||
CrashRecoveryContext() : Impl(nullptr), head(nullptr) {}
|
CrashRecoveryContext() : Impl(nullptr), head(nullptr) {}
|
||||||
~CrashRecoveryContext();
|
~CrashRecoveryContext();
|
||||||
@ -86,11 +77,9 @@ public:
|
|||||||
/// make as little assumptions as possible about the program state when
|
/// make as little assumptions as possible about the program state when
|
||||||
/// RunSafely has returned false. Clients can use getBacktrace() to retrieve
|
/// RunSafely has returned false. Clients can use getBacktrace() to retrieve
|
||||||
/// the backtrace of the crash on failures.
|
/// the backtrace of the crash on failures.
|
||||||
bool RunSafely(void (*Fn)(void*), void *UserData);
|
bool RunSafely(function_ref<void()> Fn);
|
||||||
template<typename Functor>
|
bool RunSafely(void (*Fn)(void*), void *UserData) {
|
||||||
bool RunSafely(Functor Fn) {
|
return RunSafely([&]() { Fn(UserData); });
|
||||||
FunctorAdaptor<Functor> Adaptor = { Fn };
|
|
||||||
return RunSafely(Adaptor.fn(), Adaptor.arg());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Execute the provide callback function (with the given arguments) in
|
/// \brief Execute the provide callback function (with the given arguments) in
|
||||||
@ -98,12 +87,10 @@ public:
|
|||||||
/// requested stack size).
|
/// requested stack size).
|
||||||
///
|
///
|
||||||
/// See RunSafely() and llvm_execute_on_thread().
|
/// See RunSafely() and llvm_execute_on_thread().
|
||||||
|
bool RunSafelyOnThread(function_ref<void()>, unsigned RequestedStackSize = 0);
|
||||||
bool RunSafelyOnThread(void (*Fn)(void*), void *UserData,
|
bool RunSafelyOnThread(void (*Fn)(void*), void *UserData,
|
||||||
unsigned RequestedStackSize = 0);
|
unsigned RequestedStackSize = 0) {
|
||||||
template<typename Functor>
|
return RunSafelyOnThread([&]() { Fn(UserData); }, RequestedStackSize);
|
||||||
bool RunSafelyOnThread(Functor Fn, unsigned RequestedStackSize = 0) {
|
|
||||||
FunctorAdaptor<Functor> Adaptor = { Fn };
|
|
||||||
return RunSafelyOnThread(Adaptor.fn(), Adaptor.arg(), RequestedStackSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Explicitly trigger a crash recovery in the current process, and
|
/// \brief Explicitly trigger a crash recovery in the current process, and
|
||||||
|
@ -14,8 +14,7 @@
|
|||||||
#ifndef LLVM_TRANSFORMS_UTILS_CTOR_UTILS_H
|
#ifndef LLVM_TRANSFORMS_UTILS_CTOR_UTILS_H
|
||||||
#define LLVM_TRANSFORMS_UTILS_CTOR_UTILS_H
|
#define LLVM_TRANSFORMS_UTILS_CTOR_UTILS_H
|
||||||
|
|
||||||
#include <functional>
|
#include "llvm/ADT/STLExtras.h"
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
@ -23,12 +22,10 @@ class GlobalVariable;
|
|||||||
class Function;
|
class Function;
|
||||||
class Module;
|
class Module;
|
||||||
|
|
||||||
typedef bool (*ShouldRemoveCtor)(void *, Function *);
|
|
||||||
|
|
||||||
/// Call "ShouldRemove" for every entry in M's global_ctor list and remove the
|
/// 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.
|
/// entries for which it returns true. Return true if anything changed.
|
||||||
bool optimizeGlobalCtorsList(Module &M, ShouldRemoveCtor ShouldRemove,
|
bool optimizeGlobalCtorsList(Module &M,
|
||||||
void *Context);
|
function_ref<bool(Function *)> ShouldRemove);
|
||||||
|
|
||||||
} // End llvm namespace
|
} // End llvm namespace
|
||||||
|
|
||||||
|
@ -301,7 +301,7 @@ void CrashRecoveryContext::Disable() {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool CrashRecoveryContext::RunSafely(void (*Fn)(void*), void *UserData) {
|
bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
|
||||||
// If crash recovery is disabled, do nothing.
|
// If crash recovery is disabled, do nothing.
|
||||||
if (gCrashRecoveryEnabled) {
|
if (gCrashRecoveryEnabled) {
|
||||||
assert(!Impl && "Crash recovery context already initialized!");
|
assert(!Impl && "Crash recovery context already initialized!");
|
||||||
@ -313,7 +313,7 @@ bool CrashRecoveryContext::RunSafely(void (*Fn)(void*), void *UserData) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Fn(UserData);
|
Fn();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,8 +334,7 @@ const std::string &CrashRecoveryContext::getBacktrace() const {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
struct RunSafelyOnThreadInfo {
|
struct RunSafelyOnThreadInfo {
|
||||||
void (*Fn)(void*);
|
function_ref<void()> Fn;
|
||||||
void *Data;
|
|
||||||
CrashRecoveryContext *CRC;
|
CrashRecoveryContext *CRC;
|
||||||
bool Result;
|
bool Result;
|
||||||
};
|
};
|
||||||
@ -344,11 +343,11 @@ struct RunSafelyOnThreadInfo {
|
|||||||
static void RunSafelyOnThread_Dispatch(void *UserData) {
|
static void RunSafelyOnThread_Dispatch(void *UserData) {
|
||||||
RunSafelyOnThreadInfo *Info =
|
RunSafelyOnThreadInfo *Info =
|
||||||
reinterpret_cast<RunSafelyOnThreadInfo*>(UserData);
|
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) {
|
unsigned RequestedStackSize) {
|
||||||
RunSafelyOnThreadInfo Info = { Fn, UserData, this, false };
|
RunSafelyOnThreadInfo Info = { Fn, this, false };
|
||||||
llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info, RequestedStackSize);
|
llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info, RequestedStackSize);
|
||||||
if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl)
|
if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl)
|
||||||
CRC->setSwitchedThread();
|
CRC->setSwitchedThread();
|
||||||
|
@ -54,16 +54,16 @@ namespace {
|
|||||||
|
|
||||||
bool RemoveUnusedGlobalValue(GlobalValue &GV);
|
bool RemoveUnusedGlobalValue(GlobalValue &GV);
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if F contains only a single "ret" instruction.
|
/// 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();
|
BasicBlock &Entry = F->getEntryBlock();
|
||||||
if (Entry.size() != 1 || !isa<ReturnInst>(Entry.front()))
|
if (Entry.size() != 1 || !isa<ReturnInst>(Entry.front()))
|
||||||
return false;
|
return false;
|
||||||
ReturnInst &RI = cast<ReturnInst>(Entry.front());
|
ReturnInst &RI = cast<ReturnInst>(Entry.front());
|
||||||
return RI.getReturnValue() == NULL;
|
return RI.getReturnValue() == NULL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
char GlobalDCE::ID = 0;
|
char GlobalDCE::ID = 0;
|
||||||
INITIALIZE_PASS(GlobalDCE, "globaldce",
|
INITIALIZE_PASS(GlobalDCE, "globaldce",
|
||||||
@ -75,7 +75,7 @@ bool GlobalDCE::runOnModule(Module &M) {
|
|||||||
bool Changed = false;
|
bool Changed = false;
|
||||||
|
|
||||||
// Remove empty functions from the global ctors list.
|
// 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.
|
// Loop over the module, adding globals which are obviously necessary.
|
||||||
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
|
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
|
||||||
|
@ -3022,10 +3022,9 @@ bool GlobalOpt::runOnModule(Module &M) {
|
|||||||
LocalChange |= OptimizeFunctions(M);
|
LocalChange |= OptimizeFunctions(M);
|
||||||
|
|
||||||
// Optimize global_ctors list.
|
// Optimize global_ctors list.
|
||||||
LocalChange |= optimizeGlobalCtorsList(M, [](void *C, Function *F) -> bool {
|
LocalChange |= optimizeGlobalCtorsList(M, [&](Function *F) {
|
||||||
GlobalOpt *self = static_cast<GlobalOpt *>(C);
|
return EvaluateStaticConstructor(F, DL, TLI);
|
||||||
return EvaluateStaticConstructor(F, self->DL, self->TLI);
|
});
|
||||||
}, this);
|
|
||||||
|
|
||||||
// Optimize non-address-taken globals.
|
// Optimize non-address-taken globals.
|
||||||
LocalChange |= OptimizeGlobalVars(M);
|
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
|
/// 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.
|
/// entries for which it returns true. Return true if anything changed.
|
||||||
bool optimizeGlobalCtorsList(Module &M, ShouldRemoveCtor ShouldRemove,
|
bool optimizeGlobalCtorsList(Module &M,
|
||||||
void *Context) {
|
function_ref<bool(Function *)> ShouldRemove) {
|
||||||
GlobalVariable *GlobalCtors = findGlobalCtors(M);
|
GlobalVariable *GlobalCtors = findGlobalCtors(M);
|
||||||
if (!GlobalCtors)
|
if (!GlobalCtors)
|
||||||
return false;
|
return false;
|
||||||
@ -163,7 +163,7 @@ bool optimizeGlobalCtorsList(Module &M, ShouldRemoveCtor ShouldRemove,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// If we can evaluate the ctor at compile time, do.
|
// If we can evaluate the ctor at compile time, do.
|
||||||
if (ShouldRemove(Context, F)) {
|
if (ShouldRemove(F)) {
|
||||||
Ctors.erase(Ctors.begin() + i);
|
Ctors.erase(Ctors.begin() + i);
|
||||||
MadeChange = true;
|
MadeChange = true;
|
||||||
--i;
|
--i;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user