Reputation: 20420
I'd like to use LLVM lli
tool as static library (rename main()
to lli()
and export it in libLLi.a) - to create rich UI for it. How can i modify it (or use without modifications) in order to intercept stdin?
Assume i know how to generate LLVM assembly file (using clang -S -emit-llvm .. -o output.ll
) and how to execute it using lli
tool (lli output.ll
).
Common use case:
Source code of simple app to be interpreted by lli:
#include <iostream>
using namespace std;
int main() {
char name[128];
cout << "type your name: ";
cin.getline(name, sizeof(name));
cout << "hi, " << name << endl;
return 0;
}
I need to interpret LLVM assembly for it and to show InputBox when cin.getline
invoked and show TextBox when cout <<
invoked (InputBox and TextBox are rich UI controls).
PS. I can't fork process and forward stdin/stdout of the whole child process.
Upvotes: 2
Views: 604
Reputation: 146
lli
is already a thin wrapper around llvm library functions, just use those instead. The main() function in tools/lli/lli.cpp
is long only because it supports tons of flags to control every possible setting. After you strip it down it should be less than 10 lines to create an ExecutionEngine
using an EngineBuilder
and use it to run a llvm::Function
.
You might also find chapter 4 of the Kaleidoscope tutorial helpful, where they add JIT support to the language. This also demonstrates how to use an EngineBuilder, though the ExecutionEngine they choose to build is a JIT
instead of an Interpreter
, you can customize it for your use case.
Now for the other part of your question, how do you trap stdin
and stdout
? LLVM is not a VM, the code is running in your process and using your stdin and stdout. My first suggestion is that since you already have the function in LLVM IR format, just run a transformation pass that replaces standard I/O functions with your own I/O functions. A simpler way to do that if you can get the ABI to line up, is to do the remapping with the ExecutionEngine. Call EE->updateGlobalMapping(functionDeclInIR, &replacementFunctionInNativeCode)
to tell the ExecutionEngine that the Function*
for functionDeclInIR is represented in native code by replacementFunctionInNativeCode. You would need to provide your own implementation of _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc (aka. ostream::operator<<) which uses your GUI.
Upvotes: 4