add dumping of assembly and machine code

pull/81/head
Dibyendu Majumdar 9 years ago
parent 09e2c4fc76
commit ab0e95ea18

@ -316,7 +316,7 @@ public:
// Compile the function if not already compiled and
// return pointer to function
virtual void *compile();
virtual void *compile(bool doDump = false);
// Add declaration for an extern function that is not
// loaded dynamically - i.e., is part of the the executable
@ -331,6 +331,7 @@ public:
virtual llvm::ExecutionEngine *engine() const { return engine_; }
virtual RaviJITState *owner() const;
virtual void dump();
virtual void dumpAssembly();
};
// Ravi's JIT State
@ -359,10 +360,10 @@ class RAVI_API RaviJITStateImpl : public RaviJITState {
// Size level (LLVM PassManagerBuilder)
int size_level_;
// min code size for compilation
int min_code_size_;
// min execution count for compilation
int min_exec_count_;
@ -401,10 +402,13 @@ public:
size_level_ = value;
}
int get_mincodesize() const { return min_code_size_; }
void set_mincodesize(int value) { min_code_size_ = value > 0 ? value : min_code_size_; }
void set_mincodesize(int value) {
min_code_size_ = value > 0 ? value : min_code_size_;
}
int get_minexeccount() const { return min_exec_count_; }
void set_minexeccount(int value) { min_exec_count_ = value > 0 ? value : min_exec_count_; }
void set_minexeccount(int value) {
min_exec_count_ = value > 0 ? value : min_exec_count_;
}
};
// To optimise fornum loops
@ -525,7 +529,7 @@ public:
// The p->ravi_jit structure will be updated
// Note that if a function fails to compile then
// a flag is set so that it doesn't get compiled again
void compile(lua_State *L, Proto *p);
void compile(lua_State *L, Proto *p, bool doDump = false, bool doVerify=true);
// We can only compile a subset of op codes
// and not all features are supported
@ -548,19 +552,23 @@ public:
void emit_extern_declarations(RaviFunctionDef *def);
// Retrieve the proto->sizep
llvm::Instruction *emit_load_proto_sizep(RaviFunctionDef *def, llvm::Value *proto_ptr);
llvm::Instruction *emit_load_proto_sizep(RaviFunctionDef *def,
llvm::Value *proto_ptr);
// Store lua_Number or lua_Integer
llvm::Instruction *emit_store_local_n(RaviFunctionDef *def, llvm::Value *src, llvm::Value *dest);
// Store lua_Number or lua_Integer
llvm::Instruction *emit_store_local_n(RaviFunctionDef *def, llvm::Value *src,
llvm::Value *dest);
// Load lua_Number or lua_Integer
llvm::Instruction *emit_load_local_n(RaviFunctionDef *def, llvm::Value *src);
// Store int
llvm::Instruction *emit_store_local_int(RaviFunctionDef *def, llvm::Value *src, llvm::Value *dest);
// Store int
llvm::Instruction *emit_store_local_int(RaviFunctionDef *def,
llvm::Value *src, llvm::Value *dest);
// Load int
llvm::Instruction *emit_load_local_int(RaviFunctionDef *def, llvm::Value *src);
llvm::Instruction *emit_load_local_int(RaviFunctionDef *def,
llvm::Value *src);
// emit code for (LClosure *)ci->func->value_.gc
llvm::Value *emit_gep_ci_func_value_gc_asLClosure(RaviFunctionDef *def,

@ -37,7 +37,7 @@ int raviV_initjit(struct lua_State *L);
void raviV_close(struct lua_State *L);
/* Compile the given function if possible */
int raviV_compile(struct lua_State *L, struct Proto *p, int manual_request);
int raviV_compile(struct lua_State *L, struct Proto *p, int manual_request, int dump);
/* Free the JIT structures associated with the prototype */
void raviV_freeproto(struct lua_State *L, struct Proto *p);

@ -52,6 +52,7 @@
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Support/FormattedStream.h"
#include <cstdio>
#include <string>
@ -84,7 +85,7 @@ public:
// Compile the function if not already compiled and
// return pointer to function
virtual void *compile() = 0;
virtual void *compile(bool doDump = false) = 0;
// Add declaration for an extern function that is not
// loaded dynamically - i.e., is part of the the executable
@ -98,6 +99,7 @@ public:
virtual llvm::ExecutionEngine *engine() const = 0;
virtual RaviJITState *owner() const = 0;
virtual void dump() = 0;
virtual void dumpAssembly() = 0;
protected:
RaviJITFunction() {}

@ -372,7 +372,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
callhook(L, ci);
if (L == G(L)->mainthread && p->ravi_jit.jit_status == 0) {
/* not compiled */
raviV_compile(L, p, 0);
raviV_compile(L, p, 0, 0);
}
if (L == G(L)->mainthread && p->ravi_jit.jit_status == 2) {
/* compiled */

@ -684,7 +684,7 @@ RaviCodeGenerator::emit_gep_upval_value(RaviFunctionDef *def,
return emit_gep(def, "value", pupval, 0, 2);
}
void RaviCodeGenerator::compile(lua_State *L, Proto *p) {
void RaviCodeGenerator::compile(lua_State *L, Proto *p, bool doDump, bool doVerify) {
if (p->ravi_jit.jit_status != 0 || !canCompile(p))
return;
@ -1192,11 +1192,11 @@ void RaviCodeGenerator::compile(lua_State *L, Proto *p) {
}
}
if (llvm::verifyFunction(*f->function(), &llvm::errs()))
if (doVerify && llvm::verifyFunction(*f->function(), &llvm::errs()))
abort();
ravi::RaviJITFunctionImpl *llvm_func = f.release();
p->ravi_jit.jit_data = reinterpret_cast<void *>(llvm_func);
p->ravi_jit.jit_function = (lua_CFunction)llvm_func->compile();
p->ravi_jit.jit_function = (lua_CFunction)llvm_func->compile(doDump);
lua_assert(p->ravi_jit.jit_function);
if (p->ravi_jit.jit_function == nullptr) {
p->ravi_jit.jit_status = 1; // can't compile

@ -135,16 +135,15 @@ RaviJITFunctionImpl::RaviJITFunctionImpl(
#if LLVM_VERSION_MINOR > 5
// LLVM 3.6.0 change
std::unique_ptr<llvm::Module> module(module_);
engine_ = llvm::EngineBuilder(std::move(module))
.setEngineKind(llvm::EngineKind::JIT)
.setErrorStr(&errStr)
.create();
llvm::EngineBuilder builder(std::move(module));
builder.setEngineKind(llvm::EngineKind::JIT).setErrorStr(&errStr);
engine_ = builder.create();
#else
engine_ = llvm::EngineBuilder(module_)
.setEngineKind(llvm::EngineKind::JIT)
.setUseMCJIT(true)
.setErrorStr(&errStr)
.create();
llvm::EngineBuilder builder(module_);
builder.setEngineKind(llvm::EngineKind::JIT)
.setUseMCJIT(true)
.setErrorStr(&errStr);
engine_ = builder.create();
#endif
if (!engine_) {
fprintf(stderr, "Could not create ExecutionEngine: %s\n", errStr.c_str());
@ -187,7 +186,7 @@ static void addMemorySanitizerPass(const llvm::PassManagerBuilder &Builder,
}
}
void *RaviJITFunctionImpl::compile() {
void *RaviJITFunctionImpl::compile(bool doDump) {
// We use the PassManagerBuilder to setup optimization
// passes - the PassManagerBuilder allows easy configuration of
@ -246,6 +245,11 @@ void *RaviJITFunctionImpl::compile() {
if (!function_ || !engine_)
return NULL;
if (doDump) {
llvm::TargetMachine *TM = engine_->getTargetMachine();
TM->Options.PrintMachineCode = 1;
}
// Upon creation, MCJIT holds a pointer to the Module object
// that it received from EngineBuilder but it does not immediately
// generate code for this module. Code generation is deferred
@ -274,6 +278,31 @@ RaviJITFunctionImpl::addExternFunction(llvm::FunctionType *type, void *address,
void RaviJITFunctionImpl::dump() { module_->dump(); }
// Dumps the machine code
void RaviJITFunctionImpl::dumpAssembly() {
std::string codestr;
llvm::raw_string_ostream ostream(codestr);
llvm::formatted_raw_ostream formatted_stream(ostream);
llvm::TargetMachine *TM = engine_->getTargetMachine();
if (!TM) {
llvm::errs() << "unable to dump assembly\n";
return;
}
if (!ptr_)
module_->setDataLayout(engine_->getDataLayout());
llvm::legacy::PassManager pass;
if (TM->addPassesToEmitFile(pass, formatted_stream,
llvm::TargetMachine::CGFT_AssemblyFile)) {
llvm::errs() << "unable to add passes for generating assemblyfile\n";
return;
}
pass.run(*module_);
formatted_stream.flush();
llvm::errs() << codestr << "\n";
llvm::errs()
<< "Please note that this is not a disassembly of JITed function\n";
}
std::unique_ptr<RaviJITState> RaviJITStateFactory::newJITState() {
return std::unique_ptr<RaviJITState>(new RaviJITStateImpl());
}
@ -322,7 +351,8 @@ void raviV_close(struct lua_State *L) {
// Compilation occurs if either auto compilation is ON or
// a manual compilation request was made
// Returns true if compilation was successful
int raviV_compile(struct lua_State *L, struct Proto *p, int manual_request) {
int raviV_compile(struct lua_State *L, struct Proto *p, int manual_request,
int dump) {
if (p->ravi_jit.jit_status == 2)
return true;
global_State *G = G(L);
@ -352,7 +382,7 @@ int raviV_compile(struct lua_State *L, struct Proto *p, int manual_request) {
}
#endif
if (doCompile)
G->ravi_state->code_generator->compile(L, p);
G->ravi_state->code_generator->compile(L, p, dump != 0);
return p->ravi_jit.jit_status == 2;
}
@ -381,6 +411,16 @@ void raviV_dumpllvmir(struct lua_State *L, struct Proto *p) {
}
}
// Dump the LLVM ASM
void raviV_dumpllvmasm(struct lua_State *L, struct Proto *p) {
if (p->ravi_jit.jit_status == 2) /* compiled */ {
ravi::RaviJITFunction *f =
reinterpret_cast<ravi::RaviJITFunction *>(p->ravi_jit.jit_data);
if (f)
f->dumpAssembly();
}
}
// Test if the given function is compiled
static int ravi_is_compiled(lua_State *L) {
int n = lua_gettop(L);
@ -396,12 +436,12 @@ static int ravi_is_compiled(lua_State *L) {
// Try to JIT compile the given function
static int ravi_compile(lua_State *L) {
int n = lua_gettop(L);
luaL_argcheck(L, n == 1, 1, "1 argument expected");
luaL_argcheck(L, n >= 1, 1, "1 or 2 arguments expected");
luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1,
"argument must be a Lua function");
void *p = (void *)lua_topointer(L, 1);
LClosure *l = (LClosure *)p;
int result = raviV_compile(L, l->p, 1);
int result = raviV_compile(L, l->p, 1, (n == 2) ? lua_toboolean(L, 2) : 0);
lua_pushboolean(L, result);
return 1;
}
@ -429,6 +469,19 @@ static int ravi_dump_llvmir(lua_State *L) {
return 0;
}
// Dump LLVM ASM of the supplied function
// if it has been compiled
static int ravi_dump_llvmasm(lua_State *L) {
int n = lua_gettop(L);
luaL_argcheck(L, n == 1, 1, "1 argument expected");
luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1,
"argument must be a Lua function");
void *p = (void *)lua_topointer(L, 1);
LClosure *l = (LClosure *)p;
raviV_dumpllvmasm(L, l->p);
return 0;
}
// Turn on/off auto JIT compilation
static int ravi_auto(lua_State *L) {
global_State *G = G(L);
@ -510,6 +563,7 @@ static const luaL_Reg ravilib[] = {{"iscompiled", ravi_is_compiled},
{"compile", ravi_compile},
{"dumplua", ravi_dump_luacode},
{"dumpllvm", ravi_dump_llvmir},
{"dumpllvmasm", ravi_dump_llvmasm},
{"auto", ravi_auto},
{"jit", ravi_jitenable},
{"optlevel", ravi_optlevel},

Loading…
Cancel
Save