mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-20 02:58:10 +00:00
Re-commit r208025, reverted in r208030, with a fix for a conformance issue
which GCC detects and Clang does not! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@208033 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
f3a199b2ae
commit
36ecb2ee9d
@ -108,6 +108,8 @@ unlikely to be supported by our host compilers.
|
||||
* Lambdas: N2927_
|
||||
|
||||
* But *not* ``std::function``, until Clang implements `MSVC-compatible RTTI`_.
|
||||
In many cases, you may be able to use ``llvm::function_ref`` instead, and it
|
||||
is a superior choice in those cases.
|
||||
* And *not* lambdas with default arguments.
|
||||
|
||||
* ``decltype``: N2343_
|
||||
|
@ -263,6 +263,78 @@ almost never be stored or mentioned directly. They are intended solely for use
|
||||
when defining a function which should be able to efficiently accept concatenated
|
||||
strings.
|
||||
|
||||
.. _function_apis:
|
||||
|
||||
Passing functions and other callable objects
|
||||
--------------------------------------------
|
||||
|
||||
Sometimes you may want a function to be passed a callback object. In order to
|
||||
support lambda expressions and other function objects, you should not use the
|
||||
traditional C approach of taking a function pointer and an opaque cookie:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
void takeCallback(bool (*Callback)(Function *, void *), void *Cookie);
|
||||
|
||||
Instead, use one of the following approaches:
|
||||
|
||||
Function template
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
If you don't mind putting the definition of your function into a header file,
|
||||
make it a function template that is templated on the callable type.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
template<typename Callable>
|
||||
void takeCallback(Callable Callback) {
|
||||
Callback(1, 2, 3);
|
||||
}
|
||||
|
||||
The ``function_ref`` class template
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The ``function_ref``
|
||||
(`doxygen <http://llvm.org/doxygen/classllvm_1_1function_ref.html>`__) class
|
||||
template represents a reference to a callable object, templated over the type
|
||||
of the callable. This is a good choice for passing a callback to a function,
|
||||
if you don't need to hold onto the callback after the function returns.
|
||||
|
||||
``function_ref<Ret(Param1, Param2, ...)>`` can be implicitly constructed from
|
||||
any callable object that can be called with arguments of type ``Param1``,
|
||||
``Param2``, ..., and returns a value that can be converted to type ``Ret``.
|
||||
For example:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
void visitBasicBlocks(Function *F, function_ref<bool (BasicBlock*)> Callback) {
|
||||
for (BasicBlock &BB : *F)
|
||||
if (Callback(&BB))
|
||||
return;
|
||||
}
|
||||
|
||||
can be called using:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
visitBasicBlocks(F, [&](BasicBlock *BB) {
|
||||
if (process(BB))
|
||||
return isEmpty(BB);
|
||||
return false;
|
||||
});
|
||||
|
||||
Note that a ``function_ref`` object contains pointers to external memory, so
|
||||
it is not generally safe to store an instance of the class (unless you know
|
||||
that the external storage will not be freed).
|
||||
``function_ref`` is small enough that it should always be passed by value.
|
||||
|
||||
``std::function``
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
You cannot use ``std::function`` within LLVM code, because it is not supported
|
||||
by all our target toolchains.
|
||||
|
||||
|
||||
.. _DEBUG:
|
||||
|
||||
The ``DEBUG()`` macro and ``-debug`` option
|
||||
|
@ -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<typename std::remove_reference<Callable>::type>),
|
||||
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<typename std::remove_reference<Callable>::type>),
|
||||
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<typename std::remove_reference<Callable>::type>),
|
||||
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<typename std::remove_reference<Callable>::type>),
|
||||
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<typename std::remove_reference<Callable>::type>),
|
||||
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,6 +12,8 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
|
||||
namespace llvm {
|
||||
class StringRef;
|
||||
|
||||
@ -46,17 +48,6 @@ 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();
|
||||
@ -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