llvm.org GIT mirror llvm / 245e8bd
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 Richard Smith 6 years ago
7 changed file(s) with 154 addition(s) and 47 deletion(s). Raw diff Collapse all Expand all
5353 return *right < *left;
5454 }
5555 };
56
57 /// An efficient, type-erasing, non-owning reference to a callable. This is
58 /// intended for use as the type of a function parameter that is not used
59 /// after the function in question returns.
60 ///
61 /// This class does not own the callable, so it is not in general safe to store
62 /// a function_ref.
63 template class function_ref;
64
65 #if LLVM_HAS_VARIADIC_TEMPLATES
66
67 template
68 class function_ref {
69 Ret (*callback)(void *callable, Params ...params);
70 void *callable;
71
72 template
73 static Ret callback_fn(void *callable, Params ...params) {
74 return reinterpret_cast(*callable)(
75 std::forward(params)...);
76 }
77
78 public:
79 template
80 function_ref(Callable &&callable)
81 : callback(callback_fn),
82 callable(reinterpret_cast(&callable)) {}
83 Ret operator()(Params ...params) const {
84 return callback(callable, std::forward(params)...);
85 }
86 };
87
88 #else
89
90 template
91 class function_ref {
92 Ret (*callback)(void *callable);
93 void *callable;
94
95 template
96 static Ret callback_fn(void *callable) {
97 return reinterpret_cast(*callable)();
98 }
99
100 public:
101 template
102 function_ref(Callable &&callable)
103 : callback(callback_fn),
104 callable(reinterpret_cast(&callable)) {}
105 Ret operator()() const { return callback(callable); }
106 };
107
108 template
109 class function_ref {
110 Ret (*callback)(void *callable, Param1 param1);
111 void *callable;
112
113 template
114 static Ret callback_fn(void *callable, Param1 param1) {
115 return reinterpret_cast(*callable)(
116 std::forward(param1));
117 }
118
119 public:
120 template
121 function_ref(Callable &&callable)
122 : callback(callback_fn),
123 callable(reinterpret_cast(&callable)) {}
124 Ret operator()(Param1 param1) {
125 return callback(callable, std::forward(param1));
126 }
127 };
128
129 template
130 class function_ref {
131 Ret (*callback)(void *callable, Param1 param1, Param2 param2);
132 void *callable;
133
134 template
135 static Ret callback_fn(void *callable, Param1 param1, Param2 param2) {
136 return reinterpret_cast(*callable)(
137 std::forward(param1),
138 std::forward(param2));
139 }
140
141 public:
142 template
143 function_ref(Callable &&callable)
144 : callback(callback_fn),
145 callable(reinterpret_cast(&callable)) {}
146 Ret operator()(Param1 param1, Param2 param2) {
147 return callback(callable,
148 std::forward(param1),
149 std::forward(param2));
150 }
151 };
152
153 template
154 class function_ref {
155 Ret (*callback)(void *callable, Param1 param1, Param2 param2, Param3 param3);
156 void *callable;
157
158 template
159 static Ret callback_fn(void *callable, Param1 param1, Param2 param2,
160 Param3 param3) {
161 return reinterpret_cast(*callable)(
162 std::forward(param1),
163 std::forward(param2),
164 std::forward(param3));
165 }
166
167 public:
168 template
169 function_ref(Callable &&callable)
170 : callback(callback_fn),
171 callable(reinterpret_cast(&callable)) {}
172 Ret operator()(Param1 param1, Param2 param2, Param3 param3) {
173 return callback(callable,
174 std::forward(param1),
175 std::forward(param2),
176 std::forward(param3));
177 }
178 };
179
180 #endif
56181
57182 // deleter - Very very very simple method that is used to invoke operator
58183 // delete on something. It is used like this:
1111
1212 #include
1313
14 #include "llvm/ADT/STLExtras.h"
15
1416 namespace llvm {
1517 class StringRef;
1618
1719 class CrashRecoveryContextCleanup;
18
20
1921 /// \brief Crash recovery helper object.
2022 ///
2123 /// This class implements support for running operations in a safe context so
4547 void *Impl;
4648 CrashRecoveryContextCleanup *head;
4749
48 /// An adaptor to convert an arbitrary functor into a void(void*), void* pair.
49 template struct FunctorAdaptor {
50 T Fn;
51 static void invoke(void *Data) {
52 return static_cast*>(Data)->Fn();
53 }
54 typedef void Callback(void*);
55 Callback *fn() { return &invoke; }
56 void *arg() { return this; }
57 };
58
5950 public:
6051 CrashRecoveryContext() : Impl(nullptr), head(nullptr) {}
6152 ~CrashRecoveryContext();
62
53
6354 void registerCleanup(CrashRecoveryContextCleanup *cleanup);
6455 void unregisterCleanup(CrashRecoveryContextCleanup *cleanup);
6556
8576 /// make as little assumptions as possible about the program state when
8677 /// RunSafely has returned false. Clients can use getBacktrace() to retrieve
8778 /// the backtrace of the crash on failures.
88 bool RunSafely(void (*Fn)(void*), void *UserData);
89 template
90 bool RunSafely(Functor Fn) {
91 FunctorAdaptor Adaptor = { Fn };
92 return RunSafely(Adaptor.fn(), Adaptor.arg());
79 bool RunSafely(function_ref Fn);
80 bool RunSafely(void (*Fn)(void*), void *UserData) {
81 return RunSafely([&]() { Fn(UserData); });
9382 }
9483
9584 /// \brief Execute the provide callback function (with the given arguments) in
9786 /// requested stack size).
9887 ///
9988 /// See RunSafely() and llvm_execute_on_thread().
89 bool RunSafelyOnThread(function_ref, unsigned RequestedStackSize = 0);
10090 bool RunSafelyOnThread(void (*Fn)(void*), void *UserData,
101 unsigned RequestedStackSize = 0);
102 template
103 bool RunSafelyOnThread(Functor Fn, unsigned RequestedStackSize = 0) {
104 FunctorAdaptor Adaptor = { Fn };
105 return RunSafelyOnThread(Adaptor.fn(), Adaptor.arg(), RequestedStackSize);
91 unsigned RequestedStackSize = 0) {
92 return RunSafelyOnThread([&]() { Fn(UserData); }, RequestedStackSize);
10693 }
10794
10895 /// \brief Explicitly trigger a crash recovery in the current process, and
1313 #ifndef LLVM_TRANSFORMS_UTILS_CTOR_UTILS_H
1414 #define LLVM_TRANSFORMS_UTILS_CTOR_UTILS_H
1515
16 #include
17 #include
16 #include "llvm/ADT/STLExtras.h"
1817
1918 namespace llvm {
2019
2221 class Function;
2322 class Module;
2423
25 typedef bool (*ShouldRemoveCtor)(void *, Function *);
26
2724 /// Call "ShouldRemove" for every entry in M's global_ctor list and remove the
2825 /// entries for which it returns true. Return true if anything changed.
29 bool optimizeGlobalCtorsList(Module &M, ShouldRemoveCtor ShouldRemove,
30 void *Context);
26 bool optimizeGlobalCtorsList(Module &M,
27 function_ref ShouldRemove);
3128
3229 } // End llvm namespace
3330
300300
301301 #endif
302302
303 bool CrashRecoveryContext::RunSafely(void (*Fn)(void*), void *UserData) {
303 bool CrashRecoveryContext::RunSafely(function_ref Fn) {
304304 // If crash recovery is disabled, do nothing.
305305 if (gCrashRecoveryEnabled) {
306306 assert(!Impl && "Crash recovery context already initialized!");
312312 }
313313 }
314314
315 Fn(UserData);
315 Fn();
316316 return true;
317317 }
318318
333333
334334 namespace {
335335 struct RunSafelyOnThreadInfo {
336 void (*Fn)(void*);
337 void *Data;
336 function_ref Fn;
338337 CrashRecoveryContext *CRC;
339338 bool Result;
340339 };
343342 static void RunSafelyOnThread_Dispatch(void *UserData) {
344343 RunSafelyOnThreadInfo *Info =
345344 reinterpret_cast(UserData);
346 Info->Result = Info->CRC->RunSafely(Info->Fn, Info->Data);
347 }
348 bool CrashRecoveryContext::RunSafelyOnThread(void (*Fn)(void*), void *UserData,
345 Info->Result = Info->CRC->RunSafely(Info->Fn);
346 }
347 bool CrashRecoveryContext::RunSafelyOnThread(function_ref Fn,
349348 unsigned RequestedStackSize) {
350 RunSafelyOnThreadInfo Info = { Fn, UserData, this, false };
349 RunSafelyOnThreadInfo Info = { Fn, this, false };
351350 llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info, RequestedStackSize);
352351 if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl)
353352 CRC->setSwitchedThread();
5353
5454 bool RemoveUnusedGlobalValue(GlobalValue &GV);
5555 };
56 }
5657
5758 /// Returns true if F contains only a single "ret" instruction.
58 bool isEmptyFunction(void *Context, Function *F) {
59 static bool isEmptyFunction(Function *F) {
5960 BasicBlock &Entry = F->getEntryBlock();
6061 if (Entry.size() != 1 || !isa(Entry.front()))
6162 return false;
6263 ReturnInst &RI = cast(Entry.front());
6364 return RI.getReturnValue() == NULL;
6465 }
65 }
6666
6767 char GlobalDCE::ID = 0;
6868 INITIALIZE_PASS(GlobalDCE, "globaldce",
7474 bool Changed = false;
7575
7676 // Remove empty functions from the global ctors list.
77 Changed |= optimizeGlobalCtorsList(M, isEmptyFunction, nullptr);
77 Changed |= optimizeGlobalCtorsList(M, isEmptyFunction);
7878
7979 // Loop over the module, adding globals which are obviously necessary.
8080 for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
30213021 LocalChange |= OptimizeFunctions(M);
30223022
30233023 // Optimize global_ctors list.
3024 LocalChange |= optimizeGlobalCtorsList(M, [](void *C, Function *F) -> bool {
3025 GlobalOpt *self = static_cast(C);
3026 return EvaluateStaticConstructor(F, self->DL, self->TLI);
3027 }, this);
3024 LocalChange |= optimizeGlobalCtorsList(M, [&](Function *F) {
3025 return EvaluateStaticConstructor(F, DL, TLI);
3026 });
30283027
30293028 // Optimize non-address-taken globals.
30303029 LocalChange |= OptimizeGlobalVars(M);
131131
132132 /// Call "ShouldRemove" for every entry in M's global_ctor list and remove the
133133 /// entries for which it returns true. Return true if anything changed.
134 bool optimizeGlobalCtorsList(Module &M, ShouldRemoveCtor ShouldRemove,
135 void *Context) {
134 bool optimizeGlobalCtorsList(Module &M,
135 function_ref ShouldRemove) {
136136 GlobalVariable *GlobalCtors = findGlobalCtors(M);
137137 if (!GlobalCtors)
138138 return false;
162162 continue;
163163
164164 // If we can evaluate the ctor at compile time, do.
165 if (ShouldRemove(Context, F)) {
165 if (ShouldRemove(F)) {
166166 Ctors.erase(Ctors.begin() + i);
167167 MadeChange = true;
168168 --i;