Re-commit r208025, reverted in r208030, with a fix for a conformance issue
authorRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 6 May 2014 01:44:26 +0000 (01:44 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 6 May 2014 01:44:26 +0000 (01:44 +0000)
which GCC detects and Clang does not!

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@208033 91177308-0d34-0410-b5e6-96231b3b80d8

docs/CodingStandards.rst
docs/ProgrammersManual.rst
include/llvm/ADT/STLExtras.h
include/llvm/Support/CrashRecoveryContext.h
include/llvm/Transforms/Utils/CtorUtils.h
lib/Support/CrashRecoveryContext.cpp
lib/Transforms/IPO/GlobalDCE.cpp
lib/Transforms/IPO/GlobalOpt.cpp
lib/Transforms/Utils/CtorUtils.cpp

index 0fcca0330f4bc83370ce1e623abc92f61fff9859..edbef3ace53c13d8e081c018e4ae305abca918e6 100644 (file)
@@ -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_
index 473d95df78c1727d15e212a78f91cd6eb1c4b0b0..7e46ac4e8e64fe4128d14b08818783498539df0f 100644 (file)
@@ -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
index 7c2a147bc885dcc5f57a1d0bab6d9da350ef4881..807ec59061d2c55679d195231fc52ef9bfa8573a 100644 (file)
@@ -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:
 //
index 6b9e04397902c173c9c1adbe29f1667c92e0f1ef..c132373e91d24e77f9a19bfb017d970c53abfc51 100644 (file)
 
 #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
index a96ba2b845829a26047ce650a8b7d65fd70701a4..81e7b951c252228fc902ccb62a70c96a1bf53141 100644 (file)
@@ -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
 
index 513875d4de434312455b1ccadc441bdde8a6e0f6..a426377042d3931fc23406260967310c338636d6 100644 (file)
@@ -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();
index 03b17d5238631532f2c5fef8b53a1f2f6ce03fc2..9decddcff80d358d3139cbdd3c217b875822054e 100644 (file)
@@ -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) {
index 3db0abf89f515f51a29054ad1c93c30be72038ce..a8471bacb4991d6c8f14f94344d73e8a5bdf3eef 100644 (file)
@@ -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);
index 0082df0121437cb3cb4c68adb936dbd874664886..7cf793f6266a8e37aec4d4649c36a0e6fa548c4e 100644 (file)
@@ -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;