add API to enable JIT, set optlevel and sizelevel; set default auto mode to false

pull/81/head v0.1
Dibyendu Majumdar 9 years ago
parent 3c7539c3ca
commit 15c466561b

@ -75,15 +75,18 @@ I am currently working on JIT compilation of Ravi using LLVM. As of now not all
There are two modes of JIT compilation.
* auto mode - in this mode the compiler decides when to compile a Lua function. The current implementation is very simple - any Lua function call is is checked to see if the bytecodes contained in it can be compiled. If this is true then the function is compiled. Because of this simplistic behaviour performance will be degraded so user should disable auto compilation and instead compile specific functions using the API described below.
* manual mode - in this mode user must explicitly request compilation.
* manual mode - in this mode user must explicitly request compilation. This is the default mode.
A JIT api is available with following functions:
* ``ravi.auto([b])`` - returns setting of auto compilation; also sets the new setting if ``b`` is supplied
* ``ravi.jit([b])`` - returns enabled setting of JIT compiler; also enables/disables the JIT compiler; defaults to true
* ``ravi.auto([b])`` - returns setting of auto compilation; also sets the new setting if ``b`` is supplied; defaults to false
* ``ravi.compile(func)`` - compiles a Lua function if possible, returns ``true`` if compilation was successful
* ``ravi.iscompiled(func)`` - returns the JIT status of a function
* ``ravi.dumplua(func)`` - dumps the Lua bytecode of the function
* ``ravi.dumpllvm(func)`` - dumps the LLVM IR of the compiled function (only if function was compiled)
* ``ravi.optlevel([n])`` - sets LLVM optimization level (0, 1, 2, 3); defaults to 2
* ``ravi.sizelevel([n])`` - sets LLVM size level (0, 1, 2); defaults to 0
Compatibility with Lua
----------------------

@ -345,6 +345,14 @@ class RAVI_API RaviJITStateImpl : public RaviJITState {
// Should we auto compile what we can?
bool auto_;
// Is JIT enabled
bool enabled_;
// Optimizer level (LLVM PassManagerBuilder)
int opt_level_;
// Size level (LLVM PassManagerBuilder)
int size_level_;
public:
RaviJITStateImpl();
virtual ~RaviJITStateImpl();
@ -367,6 +375,12 @@ public:
const std::string &triple() const { return triple_; }
bool is_auto() const { return auto_; }
void set_auto(bool value) { auto_ = value; }
bool is_enabled() const { return enabled_; }
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; }
int get_sizelevel() const { return size_level_; }
void set_sizelevel(int value) { if (value >= 0 && value <= 2) size_level_ = value; }
};
// To optimise fornum loops

@ -120,6 +120,12 @@ public:
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;
protected:
RaviJITState() {}
private:

@ -1,3 +1,5 @@
ravi.auto(true)
local z,x,y
-- test 1

@ -75,15 +75,18 @@ I am currently working on JIT compilation of Ravi using LLVM. As of now not all
There are two modes of JIT compilation.
* auto mode - in this mode the compiler decides when to compile a Lua function. The current implementation is very simple - any Lua function call is is checked to see if the bytecodes contained in it can be compiled. If this is true then the function is compiled. Because of this simplistic behaviour performance will be degraded so user should disable auto compilation and instead compile specific functions using the API described below.
* manual mode - in this mode user must explicitly request compilation.
* manual mode - in this mode user must explicitly request compilation. This is the default mode.
A JIT api is available with following functions:
* ``ravi.auto([b])`` - returns setting of auto compilation; also sets the new setting if ``b`` is supplied
* ``ravi.jit([b])`` - returns enabled setting of JIT compiler; also enables/disables the JIT compiler; defaults to true
* ``ravi.auto([b])`` - returns setting of auto compilation; also sets the new setting if ``b`` is supplied; defaults to false
* ``ravi.compile(func)`` - compiles a Lua function if possible, returns ``true`` if compilation was successful
* ``ravi.iscompiled(func)`` - returns the JIT status of a function
* ``ravi.dumplua(func)`` - dumps the Lua bytecode of the function
* ``ravi.dumpllvm(func)`` - dumps the LLVM IR of the compiled function (only if function was compiled)
* ``ravi.optlevel([n])`` - sets LLVM optimization level (0, 1, 2, 3); defaults to 2
* ``ravi.sizelevel([n])`` - sets LLVM size level (0, 1, 2); defaults to 0
Compatibility with Lua
----------------------

@ -16,13 +16,14 @@ The LLVM JIT implementation is in following sources:
* ravijit.cpp - basic LLVM infrastructure and Ravi API definition
* ravi_llvmtypes.cpp - contains LLVM type definitions for Lua objects
* ravi_llvmcodegen.cpp - LLVM JIT compiler - main driver for compiling Lua bytecodes into LLVM IR, also contains implementations of opcodes like OP_JMP
* ravi_llvmload.cpp - implements OP_LOADK and OP_MOVE, and related operations
* ravi_llvmcodegen.cpp - LLVM JIT compiler - main driver for compiling Lua bytecodes into LLVM IR
* ravi_llvmload.cpp - implements OP_LOADK and OP_MOVE, and related operations, also OP_LOADBOOL
* ravi_llvmcomp.cpp - implements OP_EQ, OP_LT, OP_LE, OP_TEST and OP_TESTSET.
* ravi_llvmreturn.cpp - implements OP_RETURN
* ravi_llvmforprep.cpp - implements OP_FORPREP
* ravi_llvmforloop.cpp - implements OP_FORLOOP
* ravi_llvmarith1.cpp - implements various type specialized arithmetic operations - these are Ravi extensions
* ravi_llvmarith2.cpp - implements Lua opcodes such as OP_ADD, OP_SUB, OP_MUL, OP_DIV
* ravi_llvmcall.cpp - implements OP_CALL
* ravi_llvmtable.cpp - implements OP_GETTABLE, OP_SETTABLE etc. table operations
* ravi_llvmarith2.cpp - implements Lua opcodes such as OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_POW, OP_IDIV, OP_MOD, OP_UNM
* ravi_llvmcall.cpp - implements OP_CALL, OP_JMP
* ravi_llvmtable.cpp - implements OP_GETTABLE, OP_SETTABLE and various other table operations, OP_SELF, and also upvalue operations
* ravi_llvmrest.cpp - OP_CLOSURE, OP_VARARG, OP_CONCAT

@ -29,7 +29,9 @@ static std::atomic_int init;
RaviJITState *RaviJITFunctionImpl::owner() const { return owner_; }
RaviJITStateImpl::RaviJITStateImpl() : context_(llvm::getGlobalContext()), auto_(true) {
RaviJITStateImpl::RaviJITStateImpl()
: context_(llvm::getGlobalContext()), auto_(false), enabled_(true),
opt_level_(2), size_level_(0) {
// Unless following three lines are not executed then
// ExecutionEngine cannot be created
// This should ideally be an atomic check but because LLVM docs
@ -142,7 +144,7 @@ RaviJITFunctionImpl::~RaviJITFunctionImpl() {
void *RaviJITFunctionImpl::compile() {
//module_->dump();
// module_->dump();
// Create a function pass manager for this engine
llvm::FunctionPassManager *FPM = new llvm::FunctionPassManager(module_);
@ -159,8 +161,8 @@ void *RaviJITFunctionImpl::compile() {
FPM->add(new llvm::DataLayoutPass(*engine_->getDataLayout()));
#endif
llvm::PassManagerBuilder pmb;
pmb.OptLevel = 1;
pmb.SizeLevel = 0;
pmb.OptLevel = owner_->get_optlevel();
pmb.SizeLevel = owner_->get_sizelevel();
pmb.populateFunctionPassManager(*FPM);
FPM->doInitialization();
FPM->run(*function_);
@ -251,6 +253,9 @@ int raviV_compile(struct lua_State *L, struct Proto *p, int manual_request) {
global_State *G = G(L);
if (G->ravi_state == NULL)
return 0;
if (!G->ravi_state->jit->is_enabled()) {
return 0;
}
if (G->ravi_state->jit->is_auto() || manual_request)
G->ravi_state->code_generator->compile(L, p);
return p->ravi_jit.jit_status == 2;
@ -331,16 +336,64 @@ static int ravi_auto(lua_State *L) {
lua_pushboolean(L, 0);
else
lua_pushboolean(L, G->ravi_state->jit->is_auto());
if (n == 1)
if (n == 1 && G->ravi_state)
G->ravi_state->jit->set_auto(value);
return 1;
}
static int ravi_jitenable(lua_State *L) {
global_State *G = G(L);
int n = lua_gettop(L);
bool value = false;
if (n == 1)
value = lua_toboolean(L, 1);
if (G->ravi_state == NULL)
lua_pushboolean(L, 0);
else
lua_pushboolean(L, G->ravi_state->jit->is_enabled());
if (n == 1 && G->ravi_state)
G->ravi_state->jit->set_enabled(value);
return 1;
}
static int ravi_optlevel(lua_State *L) {
global_State *G = G(L);
int n = lua_gettop(L);
int value = 1;
if (n == 1)
value = lua_tointeger(L, 1);
if (G->ravi_state == NULL)
lua_pushinteger(L, 0);
else
lua_pushinteger(L, G->ravi_state->jit->get_optlevel());
if (n == 1 && G->ravi_state)
G->ravi_state->jit->set_optlevel(value);
return 1;
}
static int ravi_sizelevel(lua_State *L) {
global_State *G = G(L);
int n = lua_gettop(L);
int value = 0;
if (n == 1)
value = lua_tointeger(L, 1);
if (G->ravi_state == NULL)
lua_pushinteger(L, 0);
else
lua_pushinteger(L, G->ravi_state->jit->get_sizelevel());
if (n == 1 && G->ravi_state)
G->ravi_state->jit->set_sizelevel(value);
return 1;
}
static const luaL_Reg ravilib[] = {{"iscompiled", ravi_is_compiled},
{"compile", ravi_compile},
{"dumplua", ravi_dump_luacode},
{"dumpllvm", ravi_dump_llvmir},
{"auto", ravi_auto},
{"jit", ravi_jitenable},
{"optlevel", ravi_optlevel},
{"sizelevel", ravi_sizelevel},
{NULL, NULL}};
LUAMOD_API int raviopen_llvmjit(lua_State *L) {

@ -122,44 +122,44 @@ int main(int argc, const char *argv[])
{
int failures = 0;
//
failures += test_luacompexec1("function arrayaccess (); local x: integer[] = {5}; return x[1]; end; assert(ravi.compile(arrayaccess)); return arrayaccess()", 5);
failures += test_luacompexec1("function cannotload (msg, a,b); assert(not a and string.find(b, msg)); end; ravi.compile(cannotload); return 1", 1);
failures += test_luacompexec1("function z(); local a = 5; a = a + 1; return a; end; ravi.compile(z); return z()", 6);
failures += test_luacompexec1("function z(x); x[1] = 5; return x[1]; end; ravi.compile(z); return z({})", 5);
failures += test_luacompexec1("function z(x,y) return x<y end; ravi.compile(z); return not z(2,1)", 1);
failures += test_luacompexec1("local function x(); local d:number = 5.0; return d+5 == 5+d and d-5 == 5-d and d*5 == 5*d; end; local y = x(); return y", 1);
failures += test_luacompexec1("function x(f); local i : integer, j : integer = f(); return i + j; end; return ravi.compile(x)", 1);
failures += test_luacompexec1("local function z(a); print(a); return a+1; end; local function x(yy); local j = 5; j = yy(j); return j; end; local y = x(z); return y", 6);
failures += test_luacompexec1("local function z(a,p); p(a); return 6; end; local function x(yy,p); local j = 5; j = yy(j,p); return j; end; local y = x(z,print); return y", 6);
failures += test_luacompexec1("local function x(yy); local j = 5; yy(j); return j; end; local y = x(print); return y", 5);
failures += test_luacompexec1("local function x(); local i, j:integer; j=0; for i=1,1000000000 do; j = j+1; end; return j; end; local y = x(); print(y); return y", 1000000000);
failures += test_luacompexec1("local function x(); local j:number; for i=1,1000000000 do; j = j+1; end; return j; end; local y = x(); print(y); return y", 1000000000);
failures += test_luacompexec1("ravi.auto(true); function arrayaccess (); local x: integer[] = {5}; return x[1]; end; assert(ravi.compile(arrayaccess)); return arrayaccess()", 5);
failures += test_luacompexec1("ravi.auto(true); function cannotload (msg, a,b); assert(not a and string.find(b, msg)); end; ravi.compile(cannotload); return 1", 1);
failures += test_luacompexec1("ravi.auto(true); function z(); local a = 5; a = a + 1; return a; end; ravi.compile(z); return z()", 6);
failures += test_luacompexec1("ravi.auto(true); function z(x); x[1] = 5; return x[1]; end; ravi.compile(z); return z({})", 5);
failures += test_luacompexec1("ravi.auto(true); function z(x,y) return x<y end; ravi.compile(z); return not z(2,1)", 1);
failures += test_luacompexec1("ravi.auto(true); local function x(); local d:number = 5.0; return d+5 == 5+d and d-5 == 5-d and d*5 == 5*d; end; local y = x(); return y", 1);
failures += test_luacompexec1("ravi.auto(true); function x(f); local i : integer, j : integer = f(); return i + j; end; return ravi.compile(x)", 1);
failures += test_luacompexec1("ravi.auto(true); local function z(a); print(a); return a+1; end; local function x(yy); local j = 5; j = yy(j); return j; end; local y = x(z); return y", 6);
failures += test_luacompexec1("ravi.auto(true); local function z(a,p); p(a); return 6; end; local function x(yy,p); local j = 5; j = yy(j,p); return j; end; local y = x(z,print); return y", 6);
failures += test_luacompexec1("ravi.auto(true); local function x(yy); local j = 5; yy(j); return j; end; local y = x(print); return y", 5);
failures += test_luacompexec1("ravi.auto(true); local function x(); local i, j:integer; j=0; for i=1,1000000000 do; j = j+1; end; return j; end; local y = x(); print(y); return y", 1000000000);
failures += test_luacompexec1("ravi.auto(true); local function x(); local j:number; for i=1,1000000000 do; j = j+1; end; return j; end; local y = x(); print(y); return y", 1000000000);
failures += test_luacompexec1("local function x(); local j = 0; for i=2,6,3 do; j = i; end; return j; end; local y = x(); print(y); return y", 5);
failures += test_luacompexec1("local function x(); local j = 0; for i=2.0,6.0,3.0 do; j = i; end; return j; end; local y = x(); print(y); return y", 5);
failures += test_luacompexec1("local function x(); local a=5; return 1004,2; end; local y; y = x(); print(y); return y", 1004);
failures += test_luacompexec1("local function x(); if 1 == 2 then; return 5.0; end; return 1.0; end; local z = x(); print(z); return z", 1);
failures += test_luacompexec1("local function x(y); if y == 1 then; return 1.0; elseif y == 5 then; return 2.0; else; return 3.0; end; end; local z = x(5); print(z); return z", 2);
failures += test_luacompexec1("local function x(y); if y == 1 then; return 1.0; elseif y == 5 then; return 2.0; else; return 3.0; end; end; local z = x(4); print(z); return z", 3);
failures += test_luacompexec1("local function x(y,z); if y == 1 then; if z == 1 then; return 99.0; else; return z; end; elseif y == 5 then; return 2.0; else; return 3.0; end; end; local z = x(1,1); print(z); return z", 99);
failures += test_luacompexec1("ravi.auto(true); local function x(); local j = 0; for i=2,6,3 do; j = i; end; return j; end; local y = x(); print(y); return y", 5);
failures += test_luacompexec1("ravi.auto(true); local function x(); local j = 0; for i=2.0,6.0,3.0 do; j = i; end; return j; end; local y = x(); print(y); return y", 5);
failures += test_luacompexec1("ravi.auto(true); local function x(); local a=5; return 1004,2; end; local y; y = x(); print(y); return y", 1004);
failures += test_luacompexec1("ravi.auto(true); local function x(); if 1 == 2 then; return 5.0; end; return 1.0; end; local z = x(); print(z); return z", 1);
failures += test_luacompexec1("ravi.auto(true); local function x(y); if y == 1 then; return 1.0; elseif y == 5 then; return 2.0; else; return 3.0; end; end; local z = x(5); print(z); return z", 2);
failures += test_luacompexec1("ravi.auto(true); local function x(y); if y == 1 then; return 1.0; elseif y == 5 then; return 2.0; else; return 3.0; end; end; local z = x(4); print(z); return z", 3);
failures += test_luacompexec1("ravi.auto(true); local function x(y,z); if y == 1 then; if z == 1 then; return 99.0; else; return z; end; elseif y == 5 then; return 2.0; else; return 3.0; end; end; local z = x(1,1); print(z); return z", 99);
failures += test_luacompexec1("local x:integer[] = {1}; local i:integer = 1; local d:integer = x[i]; x[i] = 5; return d*x[i];", 5);
failures += test_luacompexec1("local function x(); local a:number = 1.0; return a+127 == 128.0; end; local y = x(); return y", 1);
failures += test_luacompexec1("local function x(); local a:number = 1.0; return a+128 == 129.0; end; local y = x(); return y", 1);
failures += test_luacompexec1("local function x(); local a:number = 1.0; return 127+a == 128.0; end; local y = x(); return y", 1);
failures += test_luacompexec1("local function x(); local a:number = 1.0; return 128+a == 129.0; end; local y = x(); return y", 1);
failures += test_luacompexec1("local function x(); local a:number = 1.0; return a+1.0 == 1.0+a; end; local y = x(); return y", 1);
failures += test_luacompexec1("local function x(); local a:integer = 1; return a+127 == 128; end; local y = x(); return y", 1);
failures += test_luacompexec1("local function x(); local a:integer = 1; return a+128 == 129; end; local y = x(); return y", 1);
failures += test_luacompexec1("local function x(); local a:integer = 1; return 127+a == 128; end; local y = x(); return y", 1);
failures += test_luacompexec1("local function x(); local a:integer = 1; return 128+a == 129; end; local y = x(); return y", 1);
failures += test_luacompexec1("local function x(); local a:integer = 1; return a+1 == 1+a; end; local y = x(); return y", 1);
failures += test_luacomp1("local t = {}; local da : number[] = {}; da=t[1];") == 1 ? 0 : 1;
failures += test_luacompexec1("local function tryme(x); print(#x); return x; end; local da: number[] = { 5, 6 }; da[1] = 42; da = tryme(da); return da[1];", 42);
failures += test_luacompexec1("ravi.auto(true); local function x(); local a:number = 1.0; return a+127 == 128.0; end; local y = x(); return y", 1);
failures += test_luacompexec1("ravi.auto(true); local function x(); local a:number = 1.0; return a+128 == 129.0; end; local y = x(); return y", 1);
failures += test_luacompexec1("ravi.auto(true); local function x(); local a:number = 1.0; return 127+a == 128.0; end; local y = x(); return y", 1);
failures += test_luacompexec1("ravi.auto(true); local function x(); local a:number = 1.0; return 128+a == 129.0; end; local y = x(); return y", 1);
failures += test_luacompexec1("ravi.auto(true); local function x(); local a:number = 1.0; return a+1.0 == 1.0+a; end; local y = x(); return y", 1);
failures += test_luacompexec1("ravi.auto(true); local function x(); local a:integer = 1; return a+127 == 128; end; local y = x(); return y", 1);
failures += test_luacompexec1("ravi.auto(true); local function x(); local a:integer = 1; return a+128 == 129; end; local y = x(); return y", 1);
failures += test_luacompexec1("ravi.auto(true); local function x(); local a:integer = 1; return 127+a == 128; end; local y = x(); return y", 1);
failures += test_luacompexec1("ravi.auto(true); local function x(); local a:integer = 1; return 128+a == 129; end; local y = x(); return y", 1);
failures += test_luacompexec1("ravi.auto(true); local function x(); local a:integer = 1; return a+1 == 1+a; end; local y = x(); return y", 1);
failures += test_luacompexec1("ravi.auto(true); local function tryme(x); print(#x); return x; end; local da: number[] = { 5, 6 }; da[1] = 42; da = tryme(da); return da[1];", 42);
/* following should fail as x is a number[] */
failures += test_luacompexec1("local function tryme(x); print(#x); x[1] = 'junk'; return x; end; local da: number[] = {}; da[1] = 42; da = tryme(da); return da[1];", 42) == 1 ? 0 : 1;
failures += test_luacompexec1("for i=1,10 do; end; return 0", 0);
failures += test_luacompexec1("ravi.auto(true); local function tryme(x); print(#x); x[1] = 'junk'; return x; end; local da: number[] = {}; da[1] = 42; da = tryme(da); return da[1];", 42) == 1 ? 0 : 1;
failures += test_luacomp1("local t = {}; local da : number[] = {}; da=t[1];") == 1 ? 0 : 1;
failures += test_luacomp1("local a : integer[] = {}");
failures += test_luacompexec1("for i=1,10 do; end; return 0", 0);
failures += test_luacompexec1("local a : number[], j:number = {}; for i=1,10 do; a[i] = i; j = j + a[i]; end; return j", 55);
failures += test_luacompexec1("local a:integer[] = {}; local i:integer; a[1] = i+5; i = a[1]; return i", 5);
failures += test_luacompexec1("local function tryme(); local i,j = 5,6; return i,j; end; local i:integer, j:integer = tryme(); return i+j", 11);

Loading…
Cancel
Save