sumeeth kc
2013-Nov-01 03:39 UTC
[LLVMdev] [Proposal] Adding callback mechanism to Execution Engines
Hello,
I would like to have your opinions on this.
*Problem:*
Currently, there are no ways to perform hypercalls into LLVM (they transfer
execution from the program being executed to the LLVM infrastructure to
perform compilation). The goal of this project is to cleanly integrate an
API into the LLVM code/execution engine to create custom callbacks. The
“lli” executable should allow having a function be registered as callback
with the execution engines and the program being compiled by LLVM should be
able to make a callback into that function inside lli during its execution.
*Design:*
1. The user programs link with a dummy library function called
PerformCustomCallback(const char* CallbackName, void *Args).
2. LLVM ExecutionEngines (JIT and MCJIT) will implement this function
to perform the multiplexing of the various callbacks registered with them.
3. Whenever the user program calls PerformCustomCallback with
appropriate arguments, lli should experience a call to one of the
registered callbacks.
*Methodology:*
In JIT, the external symbols are resolved during the call to void
*JIT::getPointerToNamedFunction(const std::string &Name, bool
AbortOnFailure). So, the hypercall resolution can be done here.
In MCJIT, during finalizeObject(), all the symbol relocations are
finalized. In the Memory Managers, the external symbols are resolved. So,
the hypercall resolution can be done in
LinkingMemoryManager::getSymbolAddress().
In JIT::getPointerToNamedFunction(), check whether the function name is
PerformCustomCallback and store the address of the function
PerformCustomCallback in the global table. So the next time a call happens,
JIT will get the address directly from the table.
In MCJIT, in LinkingMemoryManager::getSymbolAddress() do the same.
The execution engines (JIT and MCJIT) will provide the concrete
implementation of PerformCustomCallback function. The PerformCustomCallback
function has to call the appropriate function with the callback name
provided by the user program and pass the arguments supplied by the user
program to the callback functions. It also passes an extra argument to the
callback functions which may contain the LLVM context as specified during
the registering of the callback.
I propose to add a new API to the LLVM ExecutionEngine *int
registerCustomCallback(const char *CallbackName, void* (*)(), void
*LLVM_args)* to be used by llvm tools such as lli. This takes a function’s
name to be registered as a callback, the pointer to the function and a
placeholder for any extra arguments which the lli needs to pass to the
callback functions. The ExecutionEngine will register the function names
as callbacks and calls them when it encounters a callback in the user
program.
*Interface*:
Whenever a new callback has to be registered, the following things are to
be done:
1. The new callback has to be defined in lli (a function definition).
2. The callback has to be registered with the ExecutionEngine (JIT or
MCJIT) using the API registerCustomCallback(). Depending upon the flags set
during lli invocation, the call goes to JIT or MCJIT.
3. In the user program, a call to PerformCustomCallback() with the
name and arguments will execute the registered callback.
Example:
Suppose, I want to register a function named Callback1 which takes two
integers as its parameters.
In lli.cpp in main(), define the function Callback1 and register it as
follows:
EE->registerCustomCallback("Callback1",
(reinterpret_cast<void*(*)()>(&Callback1)));
The user programs have to include the header file of the dummy library to
get the PerformCustomCallback symbol. To make a hypercall to
"Callback1",
do the following:
struct arg {
int arg1;
int arg2;
}Arg;
Arg.arg1 = 10;
Arg.arg2 = 20;
PerformCustomCallback("Callback1", &Arg);
Compile the user program (test.cc) using clang as follows:
# clang -c -emit-llvm `llvm-config --cppflags` -o test test.cc `llvm-config
--libs` `llvm-config --ldflags` -lLLVMCustomCallback
*Usecases:*
A typical usecase for this is to induce LLVM into Recompiling and relinking
a function on demand from the client. Also, if we want to find the address
of a function in a large module, we can get it using a mechanism like this.
Please let me know if there is a better design to achieve this. I am
attaching the diff of the implementation for your reference.
Thanks,
Sumeeth
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://lists.llvm.org/pipermail/llvm-dev/attachments/20131031/73d42da1/attachment.html>
-------------- next part --------------
Index: tools/lli/lli.cpp
==================================================================---
tools/lli/lli.cpp (revision 193441)
+++ tools/lli/lli.cpp (working copy)
@@ -49,6 +49,8 @@
#include "llvm/Transforms/Instrumentation.h"
#include <cerrno>
+#include <iostream>
+
#ifdef __CYGWIN__
#include <cygwin/version.h>
#if defined(CYGWIN_VERSION_DLL_MAJOR) &&
CYGWIN_VERSION_DLL_MAJOR<1007
@@ -228,6 +230,28 @@
#endif
}
+void *Callback1(void *Arg, void *LLVM_arg) {
+ std::cout << "In Callback1" << std::endl;
+ struct arg{
+ int Arg1;
+ int Arg2;
+ };
+ struct arg *Args = (struct arg *)Arg;
+ std::cout << "Arg1 = " << Args->Arg1 << "
Arg2 = " << Args->Arg2 << std::endl;
+ if(LLVM_arg){
+ std::string *str = (std::string *)LLVM_arg;
+ std::cout << "Arg = " << *str << std::endl;
+ }
+ return NULL;
+}
+
+void *Callback2(const void *Arg) {
+ std::cout << "In Callback2" << std::endl;
+ std::string *str = (std::string *)Arg;
+ std::cout << "Arg = " << *str << std::endl;
+ return NULL;
+}
+
//===----------------------------------------------------------------------===//
// main Driver function
//
@@ -402,6 +426,12 @@
errno = 0;
int Result;
+
+ // Register the callbacks with EE->registerCustomCallback
+ if(!ForceInterpreter) {
+ EE->registerCustomCallback("Callback1",
(reinterpret_cast<void*(*)()>(&Callback1)));
+ EE->registerCustomCallback("Callback2",
(reinterpret_cast<void*(*)()>(&Callback2)));
+ }
if (!RemoteMCJIT) {
// If the program doesn't explicitly call exit, we will need the Exit
Index: lib/ExecutionEngine/MCJIT/MCJIT.h
==================================================================---
lib/ExecutionEngine/MCJIT/MCJIT.h (revision 193441)
+++ lib/ExecutionEngine/MCJIT/MCJIT.h (working copy)
@@ -297,6 +297,8 @@
virtual uint64_t getGlobalValueAddress(const std::string &Name);
virtual uint64_t getFunctionAddress(const std::string &Name);
+ // CustomCallback register function.
+ int registerCustomCallback(const char *CallbackName, void* (*)(), void
*LLVM_args = NULL);
/// @}
/// @name (Private) Registration Interfaces
/// @{
Index: lib/ExecutionEngine/MCJIT/MCJIT.cpp
==================================================================---
lib/ExecutionEngine/MCJIT/MCJIT.cpp (revision 193441)
+++ lib/ExecutionEngine/MCJIT/MCJIT.cpp (working copy)
@@ -39,6 +39,43 @@
extern "C" void LLVMLinkInMCJIT() {
}
+typedef std::map<std::string, void*(*)()> FunctionIndexMapTy;
+static FunctionIndexMapTy FunctionIndexMap;
+
+static FunctionIndexMapTy& GetFunctionIndexMap() {
+ return FunctionIndexMap;
+}
+
+typedef std::map<std::string, void*> ArgumentsIndexMapTy;
+static ArgumentsIndexMapTy ArgumentsIndexMap;
+
+static ArgumentsIndexMapTy& GetArgumentsIndexMap() {
+ return ArgumentsIndexMap;
+}
+
+/// PerformCustomCallback - This is the function responsible for calling one of
the
+/// registered callbacks as indicated by the parameter "CallbackName"
and passes the
+/// the argument "Args" and the extra LLVM argument to the registered
function.
+static void* PerformCustomCallback(const char* CallbackName, void *Args ) {
+ std::string CbName(CallbackName);
+ void* (*F)() = NULL;
+ FunctionIndexMapTy::iterator Fun_iter = GetFunctionIndexMap().find(CbName);
+ if(Fun_iter != GetFunctionIndexMap().end()) {
+ F = Fun_iter->second;
+ }
+ assert(F != 0);
+ if(F){
+ void *LLVM_args = NULL;
+ ArgumentsIndexMapTy::iterator Args_iter =
GetArgumentsIndexMap().find(CbName);
+ if(Args_iter != GetArgumentsIndexMap().end()) {
+ LLVM_args = Args_iter->second;
+ }
+ void (*PF)(void *, void *) = (void (*)(void *, void *))(intptr_t)F;
+ PF(Args, LLVM_args);
+ }
+ return NULL;
+}
+
ExecutionEngine *MCJIT::createJIT(Module *M,
std::string *ErrorStr,
RTDyldMemoryManager *MemMgr,
@@ -535,7 +572,25 @@
// without the underscore.
if (!Result && Name[0] == '_')
Result = ParentEngine->getSymbolAddress(Name.substr(1), false);
+
+ if(!Result && Name == "PerformCustomCallback")
+ return (uint64_t)&(PerformCustomCallback);
+
if (Result)
return Result;
return ClientMM->getSymbolAddress(Name);
}
+
+int MCJIT::registerCustomCallback(const char *CallbackName, void* (*Fp)(), void
*LLVM_args) {
+ std::string CbName(CallbackName);
+ // Add the function to the map
+ FunctionIndexMapTy::iterator I = GetFunctionIndexMap().find(CbName);
+ if (I == GetFunctionIndexMap().end()) {
+ GetFunctionIndexMap()[CbName] = Fp;
+ }
+
+ // Add the extra arguments to the map
+ if(LLVM_args == NULL) return 0;
+ GetArgumentsIndexMap()[CbName] = LLVM_args;
+ return 0;
+}
Index: lib/ExecutionEngine/RTDyldMemoryManager.cpp
==================================================================---
lib/ExecutionEngine/RTDyldMemoryManager.cpp (revision 193441)
+++ lib/ExecutionEngine/RTDyldMemoryManager.cpp (working copy)
@@ -28,6 +28,14 @@
#include <unistd.h>
#endif
+#ifndef HAVE___DSO_HANDLE
+#define HAVE___DSO_HANDLE 1
+#endif
+
+#if HAVE___DSO_HANDLE
+extern void *__dso_handle __attribute__ ((__visibility__
("hidden")));
+#endif
+
namespace llvm {
RTDyldMemoryManager::~RTDyldMemoryManager() {}
@@ -173,6 +181,11 @@
// is called before ExecutionEngine::runFunctionAsMain() is called.
if (Name == "__main") return (uint64_t)&jit_noop;
+ #if HAVE___DSO_HANDLE
+ if (Name == "__dso_handle")
+ return (uint64_t)&__dso_handle;
+ #endif
+
const char *NameStr = Name.c_str();
void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr);
if (Ptr)
Index: lib/ExecutionEngine/JIT/JIT.cpp
==================================================================---
lib/ExecutionEngine/JIT/JIT.cpp (revision 193441)
+++ lib/ExecutionEngine/JIT/JIT.cpp (working copy)
@@ -67,6 +67,47 @@
extern "C" void LLVMLinkInJIT() {
}
+/// The map is used to store the callback name and the function address during
+/// callback registering.
+typedef std::map<std::string, void*(*)()> FunctionIndexMapTy;
+static FunctionIndexMapTy FunctionIndexMap;
+
+static FunctionIndexMapTy& GetFunctionIndexMap() {
+ return FunctionIndexMap;
+}
+
+typedef std::map<std::string, void*> ArgumentsIndexMapTy;
+static ArgumentsIndexMapTy ArgumentsIndexMap;
+
+static ArgumentsIndexMapTy& GetArgumentsIndexMap() {
+ return ArgumentsIndexMap;
+}
+
+/// PerformCustomCallback - This is the function responsible for calling one of
the
+/// registered callbacks as indicated by the parameter "CallbackName"
and passes the
+/// the argument "Args" and the extra LLVM argument to the registered
function.
+static void* PerformCustomCallback(const char* CallbackName, void *Args ) {
+ std::string CbName(CallbackName);
+ void* (*F)() = NULL;
+ FunctionIndexMapTy::iterator Fun_iter = GetFunctionIndexMap().find(CbName);
+ if(Fun_iter != GetFunctionIndexMap().end()) {
+ F = Fun_iter->second;
+ }
+ assert(F != 0);
+ if(F){
+ void *LLVM_args = NULL;
+
+ ArgumentsIndexMapTy::iterator Arg_iter =
GetArgumentsIndexMap().find(CbName);
+ if (Arg_iter != GetArgumentsIndexMap().end()) {
+ LLVM_args = Arg_iter->second;
+ }
+
+ void (*PF)(void *, void *) = (void (*)(void *, void *))(intptr_t)F;
+ PF(Args, LLVM_args);
+ }
+ return NULL;
+}
+
/// createJIT - This is the factory method for creating a JIT for the current
/// machine, it does not fall back to the interpreter. This takes ownership
/// of the module.
@@ -571,6 +612,10 @@
if (ptr)
return ptr;
}
+
+ if(Name == "PerformCustomCallback") {
+ return (void*)(intptr_t)&(PerformCustomCallback);
+ }
/// If a LazyFunctionCreator is installed, use it to get/create the function.
if (LazyFunctionCreator)
@@ -688,5 +733,19 @@
jitstate->getPendingFunctions(locked).push_back(F);
}
+int JIT::registerCustomCallback(const char *CallbackName, void* (*Fp)(), void
*LLVM_args) {
+ std::string CbName(CallbackName);
+ // Add the function to the map
+ FunctionIndexMapTy::iterator I = GetFunctionIndexMap().find(CbName);
+ if (I == GetFunctionIndexMap().end()) {
+ GetFunctionIndexMap()[CbName] = Fp;
+ }
+
+ // Add the extra arguments to the map
+ if (LLVM_args == NULL) return 0;
+ GetArgumentsIndexMap()[CbName] = LLVM_args;
+ return 0;
+}
+
JITEventListener::~JITEventListener() {}
Index: lib/ExecutionEngine/JIT/JIT.h
==================================================================---
lib/ExecutionEngine/JIT/JIT.h (revision 193441)
+++ lib/ExecutionEngine/JIT/JIT.h (working copy)
@@ -17,7 +17,8 @@
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/PassManager.h"
#include "llvm/Support/ValueHandle.h"
-
+#include <vector>
+#include <map>
namespace llvm {
class Function;
@@ -205,8 +206,9 @@
getBasicBlockAddressMap(const MutexGuard &) {
return BasicBlockAddressMap;
}
+ /// CustomCallback handling
+ int registerCustomCallback(const char *CallbackName, void* (*Fp)(), void
*LLVM_args = NULL);
-
private:
static JITCodeEmitter *createEmitter(JIT &J, JITMemoryManager *JMM,
TargetMachine &tm);
Index: include/llvm/CustomCallback.h
==================================================================---
include/llvm/CustomCallback.h (revision 0)
+++ include/llvm/CustomCallback.h (working copy)
@@ -0,0 +1,19 @@
+//===-- CustomCallback.h - LLVM CustomCallback --------------------*- C++
-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CUSTOMCALLBACK_H
+#define CUSTOMCALLBACK_H
+
+namespace llvm {
+ extern "C" {
+ void* PerformCustomCallback(const char* CallbackName, void *Args);
+ }
+
+} // End of llvm namespace.
+#endif
Index: include/llvm/ExecutionEngine/ExecutionEngine.h
==================================================================---
include/llvm/ExecutionEngine/ExecutionEngine.h (revision 193441)
+++ include/llvm/ExecutionEngine/ExecutionEngine.h (working copy)
@@ -429,7 +429,10 @@
virtual void setObjectCache(ObjectCache *) {
llvm_unreachable("No support for an object cache");
}
-
+
+ /// LLVM hypercall functions. To be overridden in JIT and MCJIT.
+ virtual int registerCustomCallback(const char *CallbackName, void* (*Fp)(),
void *LLVM_args = NULL) {return 0;}
+
/// DisableLazyCompilation - When lazy compilation is off (the default), the
/// JIT will eagerly compile every function reachable from the argument to
/// getPointerToFunction. If lazy compilation is turned on, the JIT will
only
Index: Makefile
==================================================================--- Makefile
(revision 193441)
+++ Makefile (working copy)
@@ -31,7 +31,7 @@
OPTIONAL_DIRS := tools/clang/utils/TableGen
else
DIRS := lib/Support lib/TableGen utils lib/IR lib tools/llvm-shlib \
- tools/llvm-config tools docs unittests
+ tools/llvm-config tools CustomCallback docs unittests
OPTIONAL_DIRS := projects bindings
endif
Index: CustomCallback/CustomCallback.cpp
==================================================================---
CustomCallback/CustomCallback.cpp (revision 0)
+++ CustomCallback/CustomCallback.cpp (working copy)
@@ -0,0 +1,30 @@
+//===-- CustomCallback.cpp - LLVM Custom Callback
------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This library implements a callback mechanism from target program back to
LLI.
+//
+//===----------------------------------------------------------------------===//
+#include "llvm/CustomCallback.h"
+#include <iostream>
+using namespace llvm;
+
+/// performCustomCallback - Perform the registered callback function. Initiate
a call to the
+/// function belonging to LLI (hence, a hypercall). The target program calls
this function
+/// by specifying the callbackName.
+extern "C"{
+ void* PerformCustomCallback(const char* CallbackName, void *Args) {
+ std::cout <<"In CustomCallback Library " <<
"\n";
+
+ return NULL;
+ }
+}
+
Index: CustomCallback/LLVMBuild.txt
==================================================================---
CustomCallback/LLVMBuild.txt (revision 0)
+++ CustomCallback/LLVMBuild.txt (working copy)
@@ -0,0 +1,22 @@
+;===- ./lib/ExecutionEngine/CustomCallback/LLVMBuild.txt
-------------------------------*- Conf -*--===;
+;
+; The LLVM Compiler Infrastructure
+;
+; This file is distributed under the University of Illinois Open Source
+; License. See LICENSE.TXT for details.
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this
subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+; http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Library
+name = CustomCallback
+parent = $ROOT
+required_libraries = Core Support Target
Index: CustomCallback/Makefile
==================================================================---
CustomCallback/Makefile (revision 0)
+++ CustomCallback/Makefile (working copy)
@@ -0,0 +1,13 @@
+##===- lib/ExecutionEngine/CustomCallback/Makefile
---------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+LEVEL = ..
+LIBRARYNAME = LLVMCustomCallback
+SHARED_LIBRARY = 1
+include $(LEVEL)/Makefile.common
+
Index: CustomCallback/CMakeLists.txt
==================================================================---
CustomCallback/CMakeLists.txt (revision 0)
+++ CustomCallback/CMakeLists.txt (working copy)
@@ -0,0 +1,4 @@
+
+add_llvm_library(LLVMCustomCallback
+ CustomCallback.cpp
+ )
Sean Silva
2013-Nov-01 06:20 UTC
[LLVMdev] [Proposal] Adding callback mechanism to Execution Engines
On Thu, Oct 31, 2013 at 11:39 PM, sumeeth kc <sumeethkc at gmail.com> wrote:> Hello, > > I would like to have your opinions on this. > > *Problem:* > > Currently, there are no ways to perform hypercalls into LLVM (they > transfer execution from the program being executed to the LLVM > infrastructure to perform compilation). The goal of this project is to > cleanly integrate an API into the LLVM code/execution engine to create > custom callbacks. The “lli” executable should allow having a function be > registered as callback with the execution engines and the program being > compiled by LLVM should be able to make a callback into that function > inside lli during its execution. >What are you using lli for that you are running into this problem? -- Sean Silva> > > *Design:* > > 1. The user programs link with a dummy library function called > PerformCustomCallback(const char* CallbackName, void *Args). > > 2. LLVM ExecutionEngines (JIT and MCJIT) will implement this > function to perform the multiplexing of the various callbacks registered > with them. > > 3. Whenever the user program calls PerformCustomCallback with > appropriate arguments, lli should experience a call to one of the > registered callbacks. > > > > *Methodology:* > > In JIT, the external symbols are resolved during the call to void > *JIT::getPointerToNamedFunction(const std::string &Name, bool > AbortOnFailure). So, the hypercall resolution can be done here. > > In MCJIT, during finalizeObject(), all the symbol relocations are > finalized. In the Memory Managers, the external symbols are resolved. So, > the hypercall resolution can be done in > LinkingMemoryManager::getSymbolAddress(). > > > > In JIT::getPointerToNamedFunction(), check whether the function name is > PerformCustomCallback and store the address of the function > PerformCustomCallback in the global table. So the next time a call happens, > JIT will get the address directly from the table. > > > > In MCJIT, in LinkingMemoryManager::getSymbolAddress() do the same. > > > > The execution engines (JIT and MCJIT) will provide the concrete > implementation of PerformCustomCallback function. The PerformCustomCallback > function has to call the appropriate function with the callback name > provided by the user program and pass the arguments supplied by the user > program to the callback functions. It also passes an extra argument to the > callback functions which may contain the LLVM context as specified during > the registering of the callback. > > > > I propose to add a new API to the LLVM ExecutionEngine *int > registerCustomCallback(const char *CallbackName, void* (*)(), void > *LLVM_args)* to be used by llvm tools such as lli. This takes a > function’s name to be registered as a callback, the pointer to the function > and a placeholder for any extra arguments which the lli needs to pass to > the callback functions. The ExecutionEngine will register the function > names as callbacks and calls them when it encounters a callback in the user > program. > > > > *Interface*: > > Whenever a new callback has to be registered, the following things are to > be done: > > 1. The new callback has to be defined in lli (a function > definition). > > 2. The callback has to be registered with the ExecutionEngine (JIT > or MCJIT) using the API registerCustomCallback(). Depending upon the flags > set during lli invocation, the call goes to JIT or MCJIT. > > 3. In the user program, a call to PerformCustomCallback() with the > name and arguments will execute the registered callback. > > > > Example: > > Suppose, I want to register a function named Callback1 which takes two > integers as its parameters. > > In lli.cpp in main(), define the function Callback1 and register it as > follows: > > EE->registerCustomCallback("Callback1", > (reinterpret_cast<void*(*)()>(&Callback1))); > > > > The user programs have to include the header file of the dummy library to > get the PerformCustomCallback symbol. To make a hypercall to "Callback1", > do the following: > > struct arg { > > int arg1; > > int arg2; > > }Arg; > > Arg.arg1 = 10; > > Arg.arg2 = 20; > > > > PerformCustomCallback("Callback1", &Arg); > > > > Compile the user program (test.cc) using clang as follows: > > # clang -c -emit-llvm `llvm-config --cppflags` -o test test.cc > `llvm-config --libs` `llvm-config --ldflags` -lLLVMCustomCallback > > > > *Usecases:* > > A typical usecase for this is to induce LLVM into Recompiling and > relinking a function on demand from the client. Also, if we want to find > the address of a function in a large module, we can get it using a > mechanism like this. > > > > Please let me know if there is a better design to achieve this. I am > attaching the diff of the implementation for your reference. > > > > Thanks, > > Sumeeth > > > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20131101/51670cbe/attachment.html>
Yaron Keren
2013-Nov-01 06:45 UTC
[LLVMdev] [Proposal] Adding callback mechanism to Execution Engines
Hi Sumeeth, You want to call machine code functions from a program running under some EE. Can't this be implemented by directly mapping llvm::Function into an address? Function* F = Function::Create(YourFunctionType, ExternalLinkage); JIT->addGlobalMapping(F, Addr); You can either add the CustomCallback function or better yet add exactly the functions you need with correct prototypes. Yaron 2013/11/1 Sean Silva <chisophugis at gmail.com>> > > On Thu, Oct 31, 2013 at 11:39 PM, sumeeth kc <sumeethkc at gmail.com> wrote: > >> Hello, >> >> I would like to have your opinions on this. >> >> *Problem:* >> >> Currently, there are no ways to perform hypercalls into LLVM (they >> transfer execution from the program being executed to the LLVM >> infrastructure to perform compilation). The goal of this project is to >> cleanly integrate an API into the LLVM code/execution engine to create >> custom callbacks. The “lli” executable should allow having a function be >> registered as callback with the execution engines and the program being >> compiled by LLVM should be able to make a callback into that function >> inside lli during its execution. >> > > What are you using lli for that you are running into this problem? > > -- Sean Silva > > >> >> >> *Design:* >> >> 1. The user programs link with a dummy library function called >> PerformCustomCallback(const char* CallbackName, void *Args). >> >> 2. LLVM ExecutionEngines (JIT and MCJIT) will implement this >> function to perform the multiplexing of the various callbacks registered >> with them. >> >> 3. Whenever the user program calls PerformCustomCallback with >> appropriate arguments, lli should experience a call to one of the >> registered callbacks. >> >> >> >> *Methodology:* >> >> In JIT, the external symbols are resolved during the call to void >> *JIT::getPointerToNamedFunction(const std::string &Name, bool >> AbortOnFailure). So, the hypercall resolution can be done here. >> >> In MCJIT, during finalizeObject(), all the symbol relocations are >> finalized. In the Memory Managers, the external symbols are resolved. So, >> the hypercall resolution can be done in >> LinkingMemoryManager::getSymbolAddress(). >> >> >> >> In JIT::getPointerToNamedFunction(), check whether the function name is >> PerformCustomCallback and store the address of the function >> PerformCustomCallback in the global table. So the next time a call happens, >> JIT will get the address directly from the table. >> >> >> >> In MCJIT, in LinkingMemoryManager::getSymbolAddress() do the same. >> >> >> >> The execution engines (JIT and MCJIT) will provide the concrete >> implementation of PerformCustomCallback function. The PerformCustomCallback >> function has to call the appropriate function with the callback name >> provided by the user program and pass the arguments supplied by the user >> program to the callback functions. It also passes an extra argument to the >> callback functions which may contain the LLVM context as specified during >> the registering of the callback. >> >> >> >> I propose to add a new API to the LLVM ExecutionEngine *int >> registerCustomCallback(const char *CallbackName, void* (*)(), void >> *LLVM_args)* to be used by llvm tools such as lli. This takes a >> function’s name to be registered as a callback, the pointer to the function >> and a placeholder for any extra arguments which the lli needs to pass to >> the callback functions. The ExecutionEngine will register the function >> names as callbacks and calls them when it encounters a callback in the user >> program. >> >> >> >> *Interface*: >> >> Whenever a new callback has to be registered, the following things are to >> be done: >> >> 1. The new callback has to be defined in lli (a function >> definition). >> >> 2. The callback has to be registered with the ExecutionEngine (JIT >> or MCJIT) using the API registerCustomCallback(). Depending upon the flags >> set during lli invocation, the call goes to JIT or MCJIT. >> >> 3. In the user program, a call to PerformCustomCallback() with the >> name and arguments will execute the registered callback. >> >> >> >> Example: >> >> Suppose, I want to register a function named Callback1 which takes two >> integers as its parameters. >> >> In lli.cpp in main(), define the function Callback1 and register it as >> follows: >> >> EE->registerCustomCallback("Callback1", >> (reinterpret_cast<void*(*)()>(&Callback1))); >> >> >> >> The user programs have to include the header file of the dummy library to >> get the PerformCustomCallback symbol. To make a hypercall to "Callback1", >> do the following: >> >> struct arg { >> >> int arg1; >> >> int arg2; >> >> }Arg; >> >> Arg.arg1 = 10; >> >> Arg.arg2 = 20; >> >> >> >> PerformCustomCallback("Callback1", &Arg); >> >> >> >> Compile the user program (test.cc) using clang as follows: >> >> # clang -c -emit-llvm `llvm-config --cppflags` -o test test.cc >> `llvm-config --libs` `llvm-config --ldflags` -lLLVMCustomCallback >> >> >> >> *Usecases:* >> >> A typical usecase for this is to induce LLVM into Recompiling and >> relinking a function on demand from the client. Also, if we want to find >> the address of a function in a large module, we can get it using a >> mechanism like this. >> >> >> >> Please let me know if there is a better design to achieve this. I am >> attaching the diff of the implementation for your reference. >> >> >> >> Thanks, >> >> Sumeeth >> >> >> _______________________________________________ >> LLVM Developers mailing list >> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev >> >> > > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20131101/b61f4a67/attachment.html>
Kaylor, Andrew
2013-Nov-01 17:06 UTC
[LLVMdev] [Proposal] Adding callback mechanism to Execution Engines
Hi Sumeeth,
I'm not sure I understand what your new mechanism is supposed to add. You
can already call functions defined in the host program from generated code. The
Kaleidoscope tutorial does this. If the function you want to call is defined in
a module that is dynamically loaded and you are using the default memory manager
all you need to do is declare a prototype for the function in your generated
module and the linking mechanism will handle it.
If the function is in a statically linked module, you need to do something to
explicitly expose it. With the older JIT engine you can use addGlobalMapping as
Yaron suggests, but I don't think that will work with MCJIT. I believe that
sys::DynamicLibrary::addSymbol will work with either engine. Alternatively, you
could implement a custom memory manager to manage the linking directly.
-Andy
From: llvmdev-bounces at cs.uiuc.edu [mailto:llvmdev-bounces at cs.uiuc.edu] On
Behalf Of sumeeth kc
Sent: Thursday, October 31, 2013 8:40 PM
To: LLVM Dev
Subject: [LLVMdev] [Proposal] Adding callback mechanism to Execution Engines
Hello,
I would like to have your opinions on this.
Problem:
Currently, there are no ways to perform hypercalls into LLVM (they transfer
execution from the program being executed to the LLVM infrastructure to perform
compilation). The goal of this project is to cleanly integrate an API into the
LLVM code/execution engine to create custom callbacks. The "lli"
executable should allow having a function be registered as callback with the
execution engines and the program being compiled by LLVM should be able to make
a callback into that function inside lli during its execution.
Design:
1. The user programs link with a dummy library function called
PerformCustomCallback(const char* CallbackName, void *Args).
2. LLVM ExecutionEngines (JIT and MCJIT) will implement this function to
perform the multiplexing of the various callbacks registered with them.
3. Whenever the user program calls PerformCustomCallback with appropriate
arguments, lli should experience a call to one of the registered callbacks.
Methodology:
In JIT, the external symbols are resolved during the call to void
*JIT::getPointerToNamedFunction(const std::string &Name, bool
AbortOnFailure). So, the hypercall resolution can be done here.
In MCJIT, during finalizeObject(), all the symbol relocations are finalized. In
the Memory Managers, the external symbols are resolved. So, the hypercall
resolution can be done in LinkingMemoryManager::getSymbolAddress().
In JIT::getPointerToNamedFunction(), check whether the function name is
PerformCustomCallback and store the address of the function
PerformCustomCallback in the global table. So the next time a call happens, JIT
will get the address directly from the table.
In MCJIT, in LinkingMemoryManager::getSymbolAddress() do the same.
The execution engines (JIT and MCJIT) will provide the concrete implementation
of PerformCustomCallback function. The PerformCustomCallback function has to
call the appropriate function with the callback name provided by the user
program and pass the arguments supplied by the user program to the callback
functions. It also passes an extra argument to the callback functions which may
contain the LLVM context as specified during the registering of the callback.
I propose to add a new API to the LLVM ExecutionEngine int
registerCustomCallback(const char *CallbackName, void* (*)(), void *LLVM_args)
to be used by llvm tools such as lli. This takes a function's name to be
registered as a callback, the pointer to the function and a placeholder for any
extra arguments which the lli needs to pass to the callback functions. The
ExecutionEngine will register the function names as callbacks and calls them
when it encounters a callback in the user program.
Interface:
Whenever a new callback has to be registered, the following things are to be
done:
1. The new callback has to be defined in lli (a function definition).
2. The callback has to be registered with the ExecutionEngine (JIT or
MCJIT) using the API registerCustomCallback(). Depending upon the flags set
during lli invocation, the call goes to JIT or MCJIT.
3. In the user program, a call to PerformCustomCallback() with the name
and arguments will execute the registered callback.
Example:
Suppose, I want to register a function named Callback1 which takes two integers
as its parameters.
In lli.cpp in main(), define the function Callback1 and register it as follows:
EE->registerCustomCallback("Callback1",
(reinterpret_cast<void*(*)()>(&Callback1)));
The user programs have to include the header file of the dummy library to get
the PerformCustomCallback symbol. To make a hypercall to "Callback1",
do the following:
struct arg {
int arg1;
int arg2;
}Arg;
Arg.arg1 = 10;
Arg.arg2 = 20;
PerformCustomCallback("Callback1", &Arg);
Compile the user program (test.cc) using clang as follows:
# clang -c -emit-llvm `llvm-config --cppflags` -o test test.cc `llvm-config
--libs` `llvm-config --ldflags` -lLLVMCustomCallback
Usecases:
A typical usecase for this is to induce LLVM into Recompiling and relinking a
function on demand from the client. Also, if we want to find the address of a
function in a large module, we can get it using a mechanism like this.
Please let me know if there is a better design to achieve this. I am attaching
the diff of the implementation for your reference.
Thanks,
Sumeeth
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://lists.llvm.org/pipermail/llvm-dev/attachments/20131101/42996586/attachment.html>
Caldarale, Charles R
2013-Nov-01 17:53 UTC
[LLVMdev] [Proposal] Adding callback mechanism to Execution Engines
> From: llvmdev-bounces at cs.uiuc.edu [mailto:llvmdev-bounces at cs.uiuc.edu] > On Behalf Of Kaylor, Andrew > Subject: Re: [LLVMdev] [Proposal] Adding callback mechanism to Execution Engines> If the function is in a statically linked module, you need to do something to explicitly expose it. With > the older JIT engine you can use addGlobalMapping as Yaron suggests, but I don't think that will work > with MCJIT.Seems to work fine for us with MCJIT. - Chuck -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20131101/6159fa5d/attachment.html>
Reasonably Related Threads
- [LLVMdev] [Proposal] Adding callback mechanism to Execution Engines
- [LLVMdev] [Proposal] Adding callback mechanism to Execution Engines
- [LLVMdev] [Proposal] Adding callback mechanism to Execution Engines
- [LLVMdev] [Proposal] Adding callback mechanism to Execution Engines
- [LLVMdev] [Proposal] Adding callback mechanism to Execution Engines