@ -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)
@ -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)
@ -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
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,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("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[] = {}");