issue #78 work in progress

pull/81/head
Dibyendu Majumdar 8 years ago
parent 249a4a8acb
commit 402c4b2bc4

@ -122,8 +122,8 @@ if (LLVM_JIT)
src/ravi_llvmcodegen.cpp src/ravi_llvmforprep.cpp src/ravi_llvmcomp.cpp
src/ravi_llvmreturn.cpp src/ravi_llvmload.cpp src/ravi_llvmforloop.cpp
src/ravi_llvmarith1.cpp src/ravi_llvmcall.cpp src/ravi_llvmtable.cpp
src/ravi_llvmarith2.cpp src/ravi_llvmtforcall.cpp src/ravi_llvmrest.cpp
src/ravi_llvmluaapi.cpp)
src/ravi_llvmarith2.cpp src/ravi_llvmtforcall.cpp src/ravi_llvmrest.cpp)
# src/ravi_llvmluaapi.cpp)
endif ()
if (GCC_JIT)
set(GCC_JIT_SRCS src/ravi_gccjit.c src/ravi_gcctypes.c

@ -424,8 +424,9 @@ typedef struct LocVar {
typedef enum {
RAVI_JIT_NOT_COMPILED = 0,
RAVI_JIT_CANT_COMPILE = 1,
RAVI_JIT_COMPILED = 2,
RAVI_JIT_FREED = 3
RAVI_JIT_IR_GENERATED = 2,
RAVI_JIT_COMPILED = 3,
RAVI_JIT_FREED = 4
} ravi_jit_status_t;
typedef enum {

@ -75,92 +75,6 @@
#define RAVI_API
#endif
namespace ravi {
class RAVI_API RaviJITState;
// Represents a JITed or JITable function
// Each function gets its own module and execution engine - this
// may change in future
// The advantage is that we can drop the function when the corresponding
// Lua object is garbage collected - with MCJIT this is not possible
// to do at function level
class RAVI_API RaviJITFunction {
public:
virtual ~RaviJITFunction() {}
// Compile the function if not already compiled and
// return pointer to function
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
// and therefore not visible at runtime by name
virtual llvm::Constant *addExternFunction(llvm::FunctionType *type,
void *address,
const std::string &name) = 0;
virtual const std::string &name() const = 0;
virtual llvm::Function *function() const = 0;
virtual llvm::Module *module() const = 0;
virtual llvm::ExecutionEngine *engine() const = 0;
virtual RaviJITState *owner() const = 0;
virtual void dump() = 0;
virtual void dumpAssembly() = 0;
protected:
RaviJITFunction() {}
private:
RaviJITFunction(const RaviJITFunction &) = delete;
RaviJITFunction &operator=(const RaviJITFunction &) = delete;
};
// Ravi's JIT State
// All of the JIT information is held here
class RAVI_API RaviJITState {
public:
virtual ~RaviJITState() {}
// Create a function of specified type and linkage
virtual RaviJITFunction *
createFunction(llvm::FunctionType *type,
llvm::GlobalValue::LinkageTypes linkage,
const std::string &name) = 0;
virtual void dump() = 0;
virtual llvm::LLVMContext &context() = 0;
virtual bool is_auto() const = 0;
virtual void set_auto(bool value) = 0;
virtual bool is_enabled() const = 0;
virtual void set_enabled(bool value) = 0;
virtual int get_optlevel() const = 0;
virtual void set_optlevel(int value) = 0;
virtual int get_sizelevel() const = 0;
virtual void set_sizelevel(int value) = 0;
virtual int get_mincodesize() const = 0;
virtual void set_mincodesize(int) = 0;
virtual int get_minexeccount() const = 0;
virtual void set_minexeccount(int) = 0;
virtual int get_gcstep() const = 0;
virtual void set_gcstep(int) = 0;
virtual bool is_tracehook_enabled() const = 0;
virtual void set_tracehook_enabled(bool) = 0;
protected:
RaviJITState() {}
private:
RaviJITState(const RaviJITState &) = delete;
RaviJITState &operator=(const RaviJITState &) = delete;
};
class RAVI_API RaviJITStateFactory {
public:
static std::unique_ptr<RaviJITState> newJITState();
};
}
#endif
#endif

@ -26,8 +26,8 @@
#ifdef USE_LLVM
#include "ravijit.h"
#include "ravi_llvm.h"
#include "ravijit.h"
#ifdef __cplusplus
extern "C" {
@ -62,9 +62,9 @@ extern "C" {
#endif
#include <array>
#include <atomic>
#include <iterator>
#include <type_traits>
#include <atomic>
namespace ravi {
@ -97,7 +97,6 @@ enum LuaTypeCode {
// All Lua types are gathered here
struct LuaLLVMTypes {
LuaLLVMTypes(llvm::LLVMContext &context);
void dump();
@ -335,71 +334,97 @@ struct LuaLLVMTypes {
llvm::MDNode *tbaa_Table_metatable;
};
class RAVI_API RaviJITStateImpl;
class RAVI_API RaviJITState;
class RAVI_API RaviJITModule;
class RAVI_API RaviJITFunction;
// Represents a JITed or JITable function
// Each function gets its own module and execution engine - this
// may change in future
// The advantage is that we can drop the function when the corresponding
// Lua object is garbage collected - with MCJIT this is not possible
// to do at function level
class RAVI_API RaviJITFunctionImpl : public RaviJITFunction {
// The function is tracked by RaviJITState so we need to
// tell RaviJITState when this function dies
RaviJITStateImpl *owner_;
class RAVI_API RaviJITStateFactory {
public:
static std::unique_ptr<RaviJITState> newJITState();
};
// Unique name for the function
std::string name_;
class RAVI_API RaviJITModule {
RaviJITState *owner_;
// The execution engine responsible for compiling the
// module
llvm::ExecutionEngine *engine_;
// Module within which the function will be defined
// The LLVM Module within which the functions will be defined
llvm::Module *module_;
// The llvm Function definition
llvm::Function *function_;
// List of JIT functions in this module
// We need this so that we can update the functions
// post compilation
std::vector<RaviJITFunction *> functions_;
// Pointer to compiled function - this is only set when
// the function
void *ptr_;
public:
RaviJITModule(RaviJITState *owner);
~RaviJITModule();
public:
RaviJITFunctionImpl(RaviJITStateImpl *owner, llvm::FunctionType *type,
llvm::GlobalValue::LinkageTypes linkage,
const std::string &name);
virtual ~RaviJITFunctionImpl();
llvm::Module *module() const { return module_; }
llvm::ExecutionEngine *engine() const { return engine_; }
RaviJITState *owner() const { return owner_; }
void dump();
void dumpAssembly();
// Compile the function if not already compiled and
// return pointer to function
virtual void *compile(bool doDump = false);
int addFunction(RaviJITFunction *f);
void removeFunction(RaviJITFunction *f);
void runpasses(bool dumpAsm = false);
void compileFunctions(bool doDump = false);
// Add declaration for an extern function that is not
// loaded dynamically - i.e., is part of the the executable
// and therefore not visible at runtime by name
virtual llvm::Function *addExternFunction(llvm::FunctionType *type,
void *address,
const std::string &name);
virtual const std::string &name() const { return name_; }
virtual llvm::Function *function() const { return function_; }
virtual llvm::Module *module() const { return module_; }
virtual llvm::ExecutionEngine *engine() const { return engine_; }
virtual RaviJITState *owner() const;
virtual void dump();
virtual void dumpAssembly();
void runpasses(bool dumpAsm = false);
llvm::Function *addExternFunction(llvm::FunctionType *type, void *address,
const std::string &name);
};
// Ravi's JIT State
// All of the JIT information is held here
class RAVI_API RaviJITStateImpl : public RaviJITState {
// Represents a JITed or JITable function
class RAVI_API RaviJITFunction {
// The Module in which this function lives
std::shared_ptr<RaviJITModule> module_;
// Unique name for the function
std::string name_;
// ID allocated by the module to this function
int id_;
// The llvm Function definition
llvm::Function *function_;
// Pointer to compiled function
void *ptr_;
// map of names to functions
std::map<std::string, RaviJITFunction *> functions_;
// The Lua Proto associated with this function
Proto *proto_;
public:
RaviJITFunction(Proto *prototype, std::shared_ptr<RaviJITModule> module,
llvm::FunctionType *type,llvm::GlobalValue::LinkageTypes linkage, const std::string &name);
~RaviJITFunction();
const std::string &name() const { return name_; }
llvm::Function *function() const { return function_; }
llvm::Module *module() const { return module_->module(); }
llvm::ExecutionEngine *engine() const { return module_->engine(); }
RaviJITState *owner() const { return module_->owner(); }
void setFunctionPtr();
void dump() { module_->dump(); }
void dumpAssembly() { module_->dumpAssembly(); }
int getId() const { return id_; }
void setId(int id) { id_ = id; }
llvm::Function *addExternFunction(llvm::FunctionType *type, void *address,
const std::string &name) {
return module_->addExternFunction(type, address, name);
}
};
// Ravi's JIT State
// All of the JIT information is held here
class RAVI_API RaviJITState {
llvm::LLVMContext *context_;
// The triple represents the host target
@ -433,19 +458,9 @@ class RAVI_API RaviJITStateImpl : public RaviJITState {
// instruction; this is expensive!
bool tracehook_enabled_;
public:
RaviJITStateImpl();
virtual ~RaviJITStateImpl();
// Create a function of specified type and linkage
virtual RaviJITFunction *
createFunction(llvm::FunctionType *type,
llvm::GlobalValue::LinkageTypes linkage,
const std::string &name);
// Stop tracking the named function - note that
// the function is assumed to be destroyed by the user
void deleteFunction(const std::string &name);
public:
RaviJITState();
~RaviJITState();
void addGlobalSymbol(const std::string &name, void *address);
@ -459,13 +474,11 @@ public:
void set_enabled(bool value) { enabled_ = value; }
int get_optlevel() const { return opt_level_; }
void set_optlevel(int value) {
if (value >= 0 && value <= 3)
opt_level_ = value;
if (value >= 0 && value <= 3) opt_level_ = value;
}
int get_sizelevel() const { return size_level_; }
void set_sizelevel(int value) {
if (value >= 0 && value <= 2)
size_level_ = value;
if (value >= 0 && value <= 2) size_level_ = value;
}
int get_mincodesize() const { return min_code_size_; }
void set_mincodesize(int value) {
@ -518,8 +531,8 @@ struct RaviBranchDef {
// This structure holds stuff we need when compiling a single
// function
struct RaviFunctionDef {
RaviJITStateImpl *jitState;
RaviJITFunctionImpl *raviF;
RaviJITState *jitState;
RaviJITFunction *raviF;
llvm::Function *f;
llvm::BasicBlock *entry;
llvm::Value *L;
@ -589,7 +602,7 @@ struct RaviFunctionDef {
std::vector<RaviBranchDef> jmp_targets;
// Load pointer to proto
llvm::Value *proto; // gep
llvm::Value *proto; // gep
llvm::Instruction *proto_ptr;
// Obtain pointer to Proto->k
@ -598,11 +611,11 @@ struct RaviFunctionDef {
llvm::Instruction *k_ptr;
// Load L->ci
llvm::Value *L_ci; // This is the GEP for L->ci
llvm::Value *L_ci; // This is the GEP for L->ci
llvm::Instruction *ci_val;
// Pointer to ci->u.l.base
llvm::Value *Ci_base; // This is the GEP for ci->u.l.base
llvm::Value *Ci_base; // This is the GEP for ci->u.l.base
llvm::Instruction *base_ptr;
// Pointer to LClosure
@ -612,14 +625,14 @@ struct RaviFunctionDef {
// This class is responsible for compiling Lua byte code
// to LLVM IR
class RaviCodeGenerator {
public:
RaviCodeGenerator(RaviJITStateImpl *jitState);
public:
RaviCodeGenerator(RaviJITState *jitState);
// Compile given function if possible
// 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, ravi_compile_options_t *options);
bool compile(lua_State *L, Proto *p, std::shared_ptr<RaviJITModule> module, ravi_compile_options_t *options);
// We can only compile a subset of op codes
// and not all features are supported
@ -633,8 +646,8 @@ public:
// Argument will be named L
// Initial BasicBlock will be created
// int func(lua_State *L) {
std::unique_ptr<RaviJITFunctionImpl>
create_function(llvm::IRBuilder<> &builder, RaviFunctionDef *def);
std::unique_ptr<RaviJITFunction> create_function(Proto *p, std::shared_ptr<RaviJITModule> module, llvm::IRBuilder<> &builder,
RaviFunctionDef *def);
// Save proto->code[pc] into savedpc
void emit_update_savedpc(RaviFunctionDef *def, int pc);
@ -692,10 +705,9 @@ public:
// The Lua typecode to check must be in lua_typecode
// The return value is a boolean type as a result of
// integer comparison result which is i1 in LLVM
llvm::Value *
emit_is_not_value_of_type(RaviFunctionDef *def, llvm::Value *value_type,
LuaTypeCode lua_typecode,
const char *varname = "value.not.typeof");
llvm::Value *emit_is_not_value_of_type(
RaviFunctionDef *def, llvm::Value *value_type, LuaTypeCode lua_typecode,
const char *varname = "value.not.typeof");
// emit code for (LClosure *)ci->func->value_.gc
llvm::Instruction *emit_gep_ci_func_value_gc_asLClosure(RaviFunctionDef *def);
@ -783,7 +795,8 @@ public:
llvm::Value *emit_table_get_array(RaviFunctionDef *def, llvm::Value *table);
llvm::Value *emit_table_no_metamethod(RaviFunctionDef *def, llvm::Value *table, TMS event);
llvm::Value *emit_table_no_metamethod(RaviFunctionDef *def,
llvm::Value *table, TMS event);
llvm::Instruction *emit_load_reg_s(RaviFunctionDef *def, llvm::Value *rb);
@ -997,19 +1010,24 @@ public:
void emit_GETTABLE_I(RaviFunctionDef *def, int A, int B, int C, int pc);
void emit_finish_GETTABLE(RaviFunctionDef *def, llvm::Value *phi, llvm::Value *t, llvm::Value *ra, llvm::Value *rb, llvm::Value *rc);
void emit_finish_GETTABLE(RaviFunctionDef *def, llvm::Value *phi,
llvm::Value *t, llvm::Value *ra, llvm::Value *rb,
llvm::Value *rc);
void emit_SELF(RaviFunctionDef *def, int A, int B, int C, int pc);
void emit_SELF_S(RaviFunctionDef *def, int A, int B, int C, int pc, TString *key);
void emit_SELF_S(RaviFunctionDef *def, int A, int B, int C, int pc,
TString *key);
void emit_common_GETTABLE_S(RaviFunctionDef *def, int A, int B, int C, TString *key);
void emit_common_GETTABLE_S(RaviFunctionDef *def, int A, int B, int C,
TString *key);
void emit_GETUPVAL(RaviFunctionDef *def, int A, int B, int pc);
void emit_SETUPVAL(RaviFunctionDef *def, int A, int B, int pc);
void emit_SETUPVAL_Specific(RaviFunctionDef *def, int A, int B, int pc, OpCode op, llvm::Function *f);
void emit_SETUPVAL_Specific(RaviFunctionDef *def, int A, int B, int pc,
OpCode op, llvm::Function *f);
void emit_GETTABUP(RaviFunctionDef *def, int A, int B, int C, int pc);
@ -1088,10 +1106,10 @@ public:
void emit_bitwise_shiftl(RaviFunctionDef *def, llvm::Value *ra, int B,
lua_Integer y);
private:
RaviJITStateImpl *jitState_;
char temp_[31]; // for name
int id_; // for name
private:
RaviJITState *jitState_;
char temp_[31]; // for name
int id_; // for name
};
}
@ -1100,7 +1118,7 @@ struct ravi_State {
ravi::RaviCodeGenerator *code_generator;
};
#define RaviJIT(L) ((ravi::RaviJITStateImpl *)G(L)->ravi_state->jit)
#define RaviJIT(L) ((ravi::RaviJITState *)G(L)->ravi_state->jit)
#define RAVI_CODEGEN_FORPREP2 0

@ -52,7 +52,7 @@ static const luaL_Reg loadedlibs[] = {
{LUA_DBLIBNAME, luaopen_debug},
{LUA_RAVILIBNAME, raviopen_llvmjit},
#ifdef USE_LLVM
{LUA_LLVMLIBNAME, raviopen_llvmluaapi},
//{LUA_LLVMLIBNAME, raviopen_llvmluaapi},
#endif
#if defined(LUA_COMPAT_BITLIB)
{LUA_BITLIBNAME, luaopen_bit32},

@ -30,7 +30,7 @@ RaviBranchDef::RaviBranchDef()
ilimit(nullptr), istep(nullptr), iidx(nullptr), flimit(nullptr),
fstep(nullptr), fidx(nullptr) {}
RaviCodeGenerator::RaviCodeGenerator(RaviJITStateImpl *jitState)
RaviCodeGenerator::RaviCodeGenerator(RaviJITState *jitState)
: jitState_(jitState), id_(1) {
temp_[0] = 0;
}
@ -935,16 +935,16 @@ bool RaviCodeGenerator::canCompile(Proto *p) {
return true;
}
std::unique_ptr<RaviJITFunctionImpl>
RaviCodeGenerator::create_function(llvm::IRBuilder<> &builder,
std::unique_ptr<RaviJITFunction>
RaviCodeGenerator::create_function(Proto *p, std::shared_ptr<RaviJITModule> module,
llvm::IRBuilder<> &builder,
RaviFunctionDef *def) {
LuaLLVMTypes *types = jitState_->types();
std::unique_ptr<ravi::RaviJITFunctionImpl> func =
std::unique_ptr<RaviJITFunctionImpl>(
(RaviJITFunctionImpl *)jitState_->createFunction(
types->jitFunctionT, llvm::Function::ExternalLinkage,
unique_function_name()));
std::unique_ptr<ravi::RaviJITFunction> func =
std::unique_ptr<RaviJITFunction>(
new RaviJITFunction(p, module, types->jitFunctionT, llvm::Function::ExternalLinkage,
unique_function_name()));
if (!func)
return func;
@ -1292,7 +1292,8 @@ RaviCodeGenerator::emit_gep_upval_value(RaviFunctionDef *def,
return emit_gep(def, "value", pupval, 0, 2);
}
void RaviCodeGenerator::compile(lua_State *L, Proto *p,
bool RaviCodeGenerator::compile(lua_State *L, Proto *p,
std::shared_ptr<RaviJITModule> module,
ravi_compile_options_t *options) {
bool doDump = options ? options->dump_level != 0 : 0;
bool doVerify = options ? options->verification_level != 0 : 0;
@ -1300,7 +1301,7 @@ void RaviCodeGenerator::compile(lua_State *L, Proto *p,
options ? options->omit_array_get_range_check != 0 : 0;
if (p->ravi_jit.jit_status != RAVI_JIT_NOT_COMPILED || !canCompile(p))
return;
return false;
llvm::LLVMContext &context = jitState_->context();
llvm::IRBuilder<> builder(context);
@ -1327,10 +1328,10 @@ void RaviCodeGenerator::compile(lua_State *L, Proto *p,
lua_lock(L);
}
auto f = create_function(builder, def);
auto f = create_function(p, module, builder, def);
if (!f) {
p->ravi_jit.jit_status = RAVI_JIT_CANT_COMPILE; // can't compile
return;
return false;
}
// The functions constants
@ -1875,17 +1876,11 @@ void RaviCodeGenerator::compile(lua_State *L, Proto *p,
if (doVerify && llvm::verifyFunction(*f->function(), &llvm::errs()))
abort();
ravi::RaviJITFunctionImpl *llvm_func = f.release();
ravi::RaviJITFunction *llvm_func = f.release();
p->ravi_jit.jit_data = reinterpret_cast<void *>(llvm_func);
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 = RAVI_JIT_CANT_COMPILE; // can't compile
delete llvm_func;
p->ravi_jit.jit_data = NULL;
} else {
p->ravi_jit.jit_status = RAVI_JIT_COMPILED;
}
p->ravi_jit.jit_function = nullptr;
p->ravi_jit.jit_status = RAVI_JIT_IR_GENERATED;
return llvm_func != nullptr;
}
void RaviCodeGenerator::scan_jump_targets(RaviFunctionDef *def, Proto *p) {

@ -35,13 +35,11 @@ namespace ravi {
// see below
static std::atomic_int init;
RaviJITState *RaviJITFunctionImpl::owner() const { return owner_; }
// Construct the JIT compiler state
// The JIT compiler state will be attached to the
// lua_State - all compilation activity happens
// in the context of the JIT State
RaviJITStateImpl::RaviJITStateImpl()
RaviJITState::RaviJITState()
: auto_(false), enabled_(true),
opt_level_(2), size_level_(0), min_code_size_(150), min_exec_count_(50),
gc_step_(200), tracehook_enabled_(false) {
@ -64,65 +62,32 @@ RaviJITStateImpl::RaviJITStateImpl()
// format; LLVM 3.7 onwards COEFF is supported
triple_ += "-elf";
#endif
context_ = new llvm::LLVMContext();
types_ = new LuaLLVMTypes(*context_);
}
// Destroy the JIT state freeing up any
// functions that were compiled
RaviJITStateImpl::~RaviJITStateImpl() {
std::vector<RaviJITFunction *> todelete;
for (auto f = std::begin(functions_); f != std::end(functions_); f++) {
todelete.push_back(f->second);
}
// delete all the compiled objects
for (int i = 0; i < todelete.size(); i++) {
delete todelete[i];
}
RaviJITState::~RaviJITState() {
delete types_;
delete context_;
}
void RaviJITStateImpl::addGlobalSymbol(const std::string &name, void *address) {
void RaviJITState::addGlobalSymbol(const std::string &name, void *address) {
llvm::sys::DynamicLibrary::AddSymbol(name, address);
}
void RaviJITStateImpl::dump() {
void RaviJITState::dump() {
types_->dump();
for (auto f : functions_) {
f.second->dump();
}
}
// Allocate a JIT Function of specified type
// and linkage - note at this stage the function has no
// implementation
RaviJITFunction *
RaviJITStateImpl::createFunction(llvm::FunctionType *type,
llvm::GlobalValue::LinkageTypes linkage,
const std::string &name) {
RaviJITFunction *f = new RaviJITFunctionImpl(this, type, linkage, name);
functions_[name] = f;
return f;
}
// Unregister a function - to be used when a function is
// destroyed by the Lua garbage collector
void RaviJITStateImpl::deleteFunction(const std::string &name) {
functions_.erase(name);
// This is called when RaviJITFunction is deleted
}
static std::atomic_int module_id = 1;
RaviJITFunctionImpl::RaviJITFunctionImpl(
RaviJITStateImpl *owner, llvm::FunctionType *type,
llvm::GlobalValue::LinkageTypes linkage, const std::string &name)
: owner_(owner), name_(name), engine_(nullptr), module_(nullptr),
function_(nullptr), ptr_(nullptr) {
// MCJIT treats each module as a compilation unit
// To enable function level life cycle we create a
// module per function
std::string moduleName = "ravi_module_" + name;
RaviJITModule::RaviJITModule(RaviJITState *owner) : owner_(owner), engine_(nullptr), module_(nullptr) {
int myid = module_id++;
char buf[40];
snprintf(buf, sizeof buf, "ravi_module_%d", myid);
std::string moduleName(buf);
module_ = new llvm::Module(moduleName, owner->context());
#if defined(_WIN32) && (!defined(_WIN64) || LLVM_VERSION_MINOR < 7)
// On Windows we get error saying incompatible object format
@ -131,23 +96,6 @@ RaviJITFunctionImpl::RaviJITFunctionImpl(
// -elf as the object format; LLVM 3.7 onwards COEFF is supported
module_->setTargetTriple(owner->triple());
#endif
function_ = llvm::Function::Create(type, linkage, name, module_);
// TODO add stack checks as debug more
// function_->addFnAttr(llvm::Attribute::StackProtectReq);
#if defined(_WIN32)
// TODO On 32-bit Windows we need to force
// 16-byte alignment
// llvm::AttrBuilder attr;
// attr.addStackAlignmentAttr(16);
// function_->addAttributes(
// llvm::AttributeSet::FunctionIndex,
// llvm::AttributeSet::get(owner_->context(),
// llvm::AttributeSet::FunctionIndex, attr));
#endif
#if LLVM_VERSION_MINOR > 5
// LLVM 3.6.0 change
std::unique_ptr<llvm::Module> module(module_);
@ -166,9 +114,7 @@ RaviJITFunctionImpl::RaviJITFunctionImpl(
}
}
RaviJITFunctionImpl::~RaviJITFunctionImpl() {
// Remove this function from parent
owner_->deleteFunction(name_);
RaviJITModule::~RaviJITModule() {
if (engine_)
delete engine_;
else if (module_)
@ -177,49 +123,32 @@ RaviJITFunctionImpl::~RaviJITFunctionImpl() {
delete module_;
}
#if 0
static void addAdditionalRaviPasses(const llvm::PassManagerBuilder &Builder,
llvm::PassManagerBase &PM) {
PM.add(llvm::createLICMPass());
PM.add(llvm::createLoopUnswitchPass());
PM.add(llvm::createLICMPass());
PM.add(llvm::createLoopUnswitchPass());
int
RaviJITModule::addFunction(RaviJITFunction *f) {
int id = functions_.size();
functions_.push_back(f);
return id;
}
static void addAdditionalRaviPasses2(const llvm::PassManagerBuilder &Builder,
llvm::PassManagerBase &PM) {
PM.add(llvm::createInductiveRangeCheckEliminationPass());
void
RaviJITModule::removeFunction(RaviJITFunction *f) {
functions_[f->getId()] = nullptr;
}
#endif
#if 0
// TODO
// Following two functions based upon similar in Clang
static void addAddressSanitizerPasses(const llvm::PassManagerBuilder &Builder,
llvm::PassManagerBase &PM) {
PM.add(llvm::createAddressSanitizerFunctionPass());
PM.add(llvm::createAddressSanitizerModulePass());
}
static void addMemorySanitizerPass(const llvm::PassManagerBuilder &Builder,
llvm::PassManagerBase &PM) {
PM.add(llvm::createMemorySanitizerPass());
// MemorySanitizer inserts complex instrumentation that mostly follows
// the logic of the original code, but operates on "shadow" values.
// It can benefit from re-running some general purpose optimization passes.
if (Builder.OptLevel > 0) {
PM.add(llvm::createEarlyCSEPass());
PM.add(llvm::createReassociatePass());
PM.add(llvm::createLICMPass());
PM.add(llvm::createGVNPass());
PM.add(llvm::createInstructionCombiningPass());
PM.add(llvm::createDeadStoreEliminationPass());
}
RaviJITFunction::RaviJITFunction(
Proto *p, std::shared_ptr<RaviJITModule> module, llvm::FunctionType *type,
llvm::GlobalValue::LinkageTypes linkage, const std::string &name)
: proto_(p), module_(module), name_(name), function_(nullptr), ptr_(nullptr) {
function_ = llvm::Function::Create(type, linkage, name, module_->module());
id_ = module_->addFunction(this);
}
RaviJITFunction::~RaviJITFunction() {
// Remove this function from parent
module_->removeFunction(this);
}
#endif
void RaviJITFunctionImpl::runpasses(bool dumpAsm) {
void RaviJITModule::runpasses(bool dumpAsm) {
#if LLVM_VERSION_MINOR >= 7
using llvm::legacy::FunctionPassManager;
@ -238,27 +167,7 @@ void RaviJITFunctionImpl::runpasses(bool dumpAsm) {
llvm::PassManagerBuilder pmb;
pmb.OptLevel = owner_->get_optlevel();
pmb.SizeLevel = owner_->get_sizelevel();
#if 0
pmb.addExtension(llvm::PassManagerBuilder::EP_LoopOptimizerEnd,
addAdditionalRaviPasses);
pmb.addExtension(llvm::PassManagerBuilder::EP_OptimizerLast,
addAdditionalRaviPasses2);
#endif
#if 0
// TODO - we want to allow instrumentation of JITed code
// TODO - it should be controlled via a flag
// Note that following appears to require linking to some
// additional LLVM libraries
pmb.addExtension(llvm::PassManagerBuilder::EP_OptimizerLast,
addAddressSanitizerPasses);
pmb.addExtension(llvm::PassManagerBuilder::EP_EnabledOnOptLevel0,
addAddressSanitizerPasses);
pmb.addExtension(llvm::PassManagerBuilder::EP_OptimizerLast,
addMemorySanitizerPass);
pmb.addExtension(llvm::PassManagerBuilder::EP_EnabledOnOptLevel0,
addMemorySanitizerPass);
#endif
{
// Create a function pass manager for this engine
std::unique_ptr<FunctionPassManager> FPM(new FunctionPassManager(module_));
@ -281,7 +190,11 @@ void RaviJITFunctionImpl::runpasses(bool dumpAsm) {
#endif
pmb.populateFunctionPassManager(*FPM);
FPM->doInitialization();
FPM->run(*function_);
for (int i = 0; i < functions_.size(); i++) {
if (functions_[i] == nullptr)
continue;
FPM->run(*functions_[i]->function());
}
}
std::string codestr;
@ -328,17 +241,7 @@ void RaviJITFunctionImpl::runpasses(bool dumpAsm) {
llvm::errs() << codestr << "\n";
}
void *RaviJITFunctionImpl::compile(bool doDump) {
if (ptr_)
// Already compiled
return ptr_;
if (!function_ || !engine_)
// Invalid - something went wrong
return NULL;
runpasses();
void RaviJITModule::compileFunctions(bool doDump) {
// Following will generate very verbose dump when machine code is
// produced below
llvm::TargetMachine *TM = engine_->getTargetMachine();
@ -354,12 +257,30 @@ void *RaviJITFunctionImpl::compile(bool doDump) {
// explicitly or a function such as MCJIT::getPointerToFunction
// is called which requires the code to have been generated.
engine_->finalizeObject();
ptr_ = engine_->getPointerToFunction(function_);
return ptr_;
for (int i = 0; i < functions_.size(); i++) {
if (functions_[i] == nullptr)
continue;
functions_[i]->setFunctionPtr();
}
}
void
RaviJITFunction::setFunctionPtr() {
lua_assert(ptr_ == nullptr);
lua_assert(proto_ != nullptr);
ptr_ = engine()->getPointerToFunction(function_);
proto_->ravi_jit.jit_function = (lua_CFunction)ptr_;
lua_assert(proto->ravi_jit.jit_function);
if (proto_->ravi_jit.jit_function == nullptr) {
proto_->ravi_jit.jit_status = RAVI_JIT_CANT_COMPILE; // can't compile
}
else {
proto_->ravi_jit.jit_status = RAVI_JIT_COMPILED;
}
}
llvm::Function *
RaviJITFunctionImpl::addExternFunction(llvm::FunctionType *type, void *address,
RaviJITModule::addExternFunction(llvm::FunctionType *type, void *address,
const std::string &name) {
llvm::Function *f = llvm::Function::Create(
type, llvm::Function::ExternalLinkage, name, module_);
@ -373,17 +294,17 @@ RaviJITFunctionImpl::addExternFunction(llvm::FunctionType *type, void *address,
return f;
}
void RaviJITFunctionImpl::dump() { module_->dump(); }
void RaviJITModule::dump() { module_->dump(); }
// Dumps the machine code
// Will execute the passes as required by currently set
// optimzation level; this may or may not match the actual
// JITed code which would have used the optimzation level set at the
// time of compilation
void RaviJITFunctionImpl::dumpAssembly() { runpasses(true); }
void RaviJITModule::dumpAssembly() { runpasses(true); }
std::unique_ptr<RaviJITState> RaviJITStateFactory::newJITState() {
return std::unique_ptr<RaviJITState>(new RaviJITStateImpl());
return std::unique_ptr<RaviJITState>(new RaviJITState());
}
}
@ -396,9 +317,9 @@ int raviV_initjit(struct lua_State *L) {
if (G->ravi_state != NULL)
return -1;
ravi_State *jit = (ravi_State *)calloc(1, sizeof(ravi_State));
jit->jit = new ravi::RaviJITStateImpl();
jit->jit = new ravi::RaviJITState();
jit->code_generator =
new ravi::RaviCodeGenerator((ravi::RaviJITStateImpl *)jit->jit);
new ravi::RaviCodeGenerator((ravi::RaviJITState *)jit->jit);
G->ravi_state = jit;
return 0;
}
@ -448,8 +369,12 @@ int raviV_compile(struct lua_State *L, struct Proto *p,
doCompile = true;
}
}
if (doCompile)
G->ravi_state->code_generator->compile(L, p, options);
if (doCompile) {
auto module = std::make_shared<ravi::RaviJITModule>(G->ravi_state->jit);
G->ravi_state->code_generator->compile(L, p, module, options);
module->runpasses();
module->compileFunctions();
}
return p->ravi_jit.jit_status == RAVI_JIT_COMPILED;
}

@ -139,7 +139,7 @@ struct ContextHolder {
* Lifetime of this is tied to the Lua instance so
* no need to garbage collect
*/
ravi::RaviJITStateImpl *jitState;
ravi::RaviJITState *jitState;
};
/* garbage collected */
@ -169,7 +169,7 @@ struct FunctionTypeHolder {
/* garbage collected */
struct MainFunctionHolder {
ravi::RaviJITFunctionImpl *func;
ravi::RaviJITFunction *func;
lua_CFunction compiled_func;
llvm::Value *arg1;
};
@ -232,7 +232,7 @@ static void alloc_LLVM_type(lua_State *L, llvm::Type *t) {
tt->type = t;
}
static void alloc_LLVM_context(lua_State *L, ravi::RaviJITStateImpl *jit) {
static void alloc_LLVM_context(lua_State *L, ravi::RaviJITState *jit) {
ContextHolder *h = (ContextHolder *)lua_newuserdata(L, sizeof(ContextHolder));
raviU_getmetatable(L, LLVM_context);
lua_setmetatable(L, -2);
@ -302,7 +302,7 @@ static void alloc_LLVM_phinode(lua_State *L, llvm::PHINode *phi) {
}
static MainFunctionHolder *alloc_LLVM_mainfunction(lua_State *L,
ravi::RaviJITStateImpl *jit,
ravi::RaviJITState *jit,
llvm::FunctionType *type,
const char *name) {
MainFunctionHolder *h =
@ -312,7 +312,7 @@ static MainFunctionHolder *alloc_LLVM_mainfunction(lua_State *L,
h->arg1 = nullptr;
raviU_getmetatable(L, LLVM_mainfunction);
lua_setmetatable(L, -2);
h->func = (ravi::RaviJITFunctionImpl *)jit->createFunction(
h->func = (ravi::RaviJITFunction *)jit->createFunction(
type, llvm::Function::ExternalLinkage, name);
return h;
}
@ -721,8 +721,8 @@ static int func_compile(lua_State *L) {
return 1;
}
typedef int (*decl_func)(lua_State *L, ravi::RaviJITStateImpl *jit,
ravi::RaviJITFunctionImpl *f);
typedef int (*decl_func)(lua_State *L, ravi::RaviJITState *jit,
ravi::RaviJITFunction *f);
typedef struct {
const char *name;
decl_func f;

@ -163,6 +163,7 @@ extern "C" int mytest(RaviGCObject *obj) {
return obj->b1;
}
#if 0
// This version of the test calls mytest() rather than
// printf() as in test1(). Also we use RaviJITState and related
// infrastructure
@ -240,6 +241,7 @@ int test2() {
printf("The answer is %d\n", ans);
return ans == 42 ? 0 : 1;
}
#endif
int main() {
@ -251,7 +253,7 @@ int main() {
int failure_count = 0;
failure_count += test1();
failure_count += test2();
// failure_count += test2();
return failure_count != 0 ? 1 : 0;
}

Loading…
Cancel
Save