Merge branch 'ravi-compiler'

mir-nonssa
Dibyendu Majumdar 4 years ago
commit 71bb74f773

@ -12,6 +12,9 @@ option(STATIC_BUILD "Build static version of Ravi, default is OFF" OFF)
option(COMPUTED_GOTO "Controls whether the interpreter switch will use computed gotos on gcc/clang, default is ON" ON)
option(LTESTS "Controls whether ltests are enabled in Debug mode; note requires Debug build" ON)
option(ASAN "Controls whether address sanitizer should be enabled" OFF)
option(RAVICOMP "Controls whether to link in RaviComp" OFF)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
# By default on non-Windows platforms we enable MIR JIT
if (NOT WIN32
@ -66,6 +69,7 @@ set(C2MIR_SRCS mir/c2mir/c2mir.c)
set(MIR_JIT_SRCS src/ravi_mirjit.c)
set(NO_JIT_SRCS src/ravi_nojit.c)
set(LUA_CMD_SRCS src/lua.c)
set(RAVICOMP_SRCS src/ravi_complib.c)
file(GLOB RAVI_HEADERS "${PROJECT_SOURCE_DIR}/include/*.h")
if (COMPUTED_GOTO AND NOT MSVC)
@ -79,16 +83,15 @@ endif ()
include(CheckCCompilerFlag)
check_c_compiler_flag("-march=native" COMPILER_OPT_ARCH_NATIVE_SUPPORTED)
if (COMPILER_OPT_ARCH_NATIVE_SUPPORTED AND NOT CMAKE_C_FLAGS MATCHES "-march=")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native")
endif ()
if (ASAN)
set(CMAKE_REQUIRED_FLAGS "-fsanitize=address")
check_c_compiler_flag("-fsanitize=address" COMPILER_ASAN_SUPPORTED)
if (COMPILER_ASAN_SUPPORTED AND NOT CMAKE_C_FLAGS_DEBUG MATCHES "-fsanitize=address")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fsanitize=address")
endif()
endif()
endif ()
endif ()
if (LLVM_JIT)
find_package(LLVM REQUIRED CONFIG)
@ -132,15 +135,33 @@ else ()
# CLion seems unable to handle include paths set on sources
include_directories("${CMAKE_SOURCE_DIR}/mir;${CMAKE_SOURCE_DIR}/mir/c2mir")
endif ()
else()
else ()
set(JIT_SRCS ${NO_JIT_SRCS})
endif ()
endif ()
if (RAVICOMP)
# Need MIR_JIT for the compiler add-on
find_package(RaviComp REQUIRED)
set(ADDON_SRCS ${RAVICOMP_SRCS})
set_property(SOURCE ${RAVICOMP_SRCS}
APPEND
PROPERTY INCLUDE_DIRECTORIES ${RAVICOMP_INCLUDE_DIRS})
if (MIR_JIT)
set_property(SOURCE ${RAVICOMP_SRCS}
APPEND
PROPERTY INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/mir;${CMAKE_SOURCE_DIR}/mir/c2mir")
endif ()
if ($ENV{CLION_IDE})
# CLion seems unable to handle include paths set on sources
include_directories(${RAVICOMP_INCLUDE_DIRS})
endif ()
endif ()
# IDE stuff
if (MSVC OR APPLE)
source_group("Ravi Headers" FILES ${RAVI_HEADERS})
source_group("Ravi Source Files" FILES ${LUA_CORE_SRCS} ${LUA_LIB_SRCS} ${JIT_SRCS})
source_group("Ravi Source Files" FILES ${LUA_CORE_SRCS} ${LUA_LIB_SRCS} ${JIT_SRCS} ${ADDON_SRCS})
endif ()
# Misc setup
@ -212,6 +233,7 @@ if (LLVM_JIT)
message(STATUS "LLVM_LIBS ${LLVM_LIBS}")
endif ()
set(LIBRAVI_NAME libravi)
#Main library
@ -219,8 +241,9 @@ add_library(${LIBRAVI_NAME} ${LIBRAVI_BUILD_TYPE}
${RAVI_HEADERS}
${LUA_LIB_SRCS}
${LUA_CORE_SRCS}
${JIT_SRCS})
target_link_libraries(${LIBRAVI_NAME} ${EXTRA_LIBRARIES} ${LLVM_LIBS} ${MIRJIT_LIBRARIES})
${JIT_SRCS}
${ADDON_SRCS})
target_link_libraries(${LIBRAVI_NAME} ${EXTRA_LIBRARIES} ${LLVM_LIBS} ${MIRJIT_LIBRARIES} ${RAVICOMP_LIBRARIES})
# Main Ravi executable
add_executable(ravi ${LUA_CMD_SRCS})
@ -283,6 +306,13 @@ if (NOT STATIC_BUILD)
else ()
set_target_properties(${LIBRAVI_NAME} PROPERTIES PREFIX "")
endif ()
if (RAVICOMP)
set_property(
TARGET ${LIBRAVI_NAME}
APPEND
PROPERTY COMPILE_DEFINITIONS "USE_RAVICOMP=1")
set(USE_RAVICOMP 1)
endif ()
if (APPLE)
set_property(
TARGET ${LIBRAVI_NAME} libravinojit_static

@ -0,0 +1,15 @@
find_path(RAVICOMP_INCLUDE_DIRS ravi_compiler.h
PATHS
c:/Software/ravicomp/include/ravicomp
~/Software/ravicomp/include/ravicomp
NO_DEFAULT_PATH
)
find_library(RAVICOMP_LIBRARIES
NAMES ravicomp
PATHS
c:/Software/ravicomp/lib
~/Software/ravicomp/lib
~/Software/ravicomp/lib64
)

@ -54,8 +54,10 @@ LUAMOD_API int (luaopen_package) (lua_State *L);
#define LUA_RAVILIBNAME "ravi"
LUAMOD_API int (raviopen_jit)(lua_State *L);
#define LUA_ASTLIBNAME "ast"
LUAMOD_API int (raviopen_ast_library)(lua_State *L);
#define LUA_RAVICOMPLIBNAME "compiler"
LUAMOD_API int (raviopen_compiler)(lua_State *L);
/* open all previous libraries */
LUALIB_API void (luaL_openlibs) (lua_State *L);

@ -5,5 +5,6 @@
#cmakedefine USE_LLVM @USE_LLVM@
#cmakedefine USE_OMRJIT @USE_OMRJIT@
#cmakedefine USE_MIRJIT @USE_MIRJIT@
#cmakedefine USE_RAVICOMP @USE_RAVICOMP@
#endif //_REDUKTI_RAVI_CONFIG_H_IN_H

@ -54,6 +54,9 @@ static const luaL_Reg loadedlibs[] = {
{LUA_BITLIBNAME, luaopen_bit32},
#endif
{LUAJIT_BITLIBNAME, luaopen_bit },
#if defined(USE_RAVICOMP)
{LUA_RAVICOMPLIBNAME, raviopen_compiler },
#endif
{NULL, NULL}
};

@ -0,0 +1,263 @@
#include "ravi_api.h"
#define LUA_CORE
#include "ravi_mirjit.h"
#include "lua.h"
#include "lapi.h"
#include "lauxlib.h"
#include "lfunc.h"
#include "lmem.h"
#include "lstring.h"
#include "ltable.h"
#include "lvm.h"
#include <string.h>
struct CompilerContext {
lua_State* L;
ravi_State* jit;
Table* h; /* to avoid collection/reuse strings */
};
static void debug_message(void* context, const char* filename, long long line, const char* message) {
struct CompilerContext* ccontext = (struct CompilerContext*)context;
ravi_writestring(ccontext->L, filename, strlen(filename));
char temp[80];
snprintf(temp, sizeof temp, "%lld: ", line);
ravi_writestring(ccontext->L, temp, strlen(temp));
ravi_writestring(ccontext->L, message, strlen(message));
ravi_writeline(ccontext->L);
}
void error_message(void* context, const char* message) {
struct CompilerContext* ccontext = (struct CompilerContext*)context;
ravi_writestring(ccontext->L, message, strlen(message));
ravi_writeline(ccontext->L);
}
/* Create a new proto and insert it into parent's list of protos */
static Proto* lua_newProto(void* context, Proto* parent) {
struct CompilerContext* ccontext = (struct CompilerContext*)context;
lua_State* L = ccontext->L;
Proto* p = luaF_newproto(L);
assert(parent);
/* FIXME make this more efficient */
int old_size = parent->sizep;
int new_size = parent->sizep + 1;
luaM_reallocvector(L, parent->p, old_size, new_size, Proto*);
parent->p[old_size] = p;
parent->sizep++;
lua_assert(parent->sizep == new_size);
luaC_objbarrier(L, parent, p);
return p;
}
/*
* Based off the Lua lexer code. Strings are anchored in a table initially - eventually
* ending up either in a Proto constant table or some other structure related to
* protos.
*/
TString* intern_string(lua_State* L, Table* h, const char* str, size_t l) {
TValue* o; /* entry for 'str' */
TString* ts = luaS_newlstr(L, str, l); /* create new string */
setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */
o = luaH_set(L, h, L->top - 1);
if (ttisnil(o)) { /* not in use yet? */
/* boolean value does not need GC barrier;
table has no metatable, so it does not need to invalidate cache */
setbvalue(o, 1); /* t[string] = true */
luaC_checkGC(L);
}
else { /* string already present */
ts = tsvalue(keyfromval(o)); /* re-use value previously stored */
}
L->top--; /* remove string from stack */
return ts;
}
/*
** Add constant 'v' to prototype's list of constants (field 'k').
** Use parser's table to cache position of constants in constant list
** and try to reuse constants.
*/
static int add_konstant(lua_State* L, Proto* f, Table* h, TValue* key, TValue* v) {
TValue* idx = luaH_set(L, h, key); /* The k index is cached against the key */
int k, oldsize, newsize;
if (ttisinteger(idx)) { /* is there an integer value index there? */
k = cast_int(ivalue(idx));
/* correct value? (warning: must distinguish floats from integers!) */
if (k >= 0 && k < f->sizek && ttype(&f->k[k]) == ttype(v) && luaV_rawequalobj(&f->k[k], v))
return k; /* reuse index */
}
/* constant not found; create a new entry in Proto->k */
oldsize = k = f->sizek;
newsize = oldsize + 1;
/* numerical value does not need GC barrier;
table has no metatable, so it does not need to invalidate cache */
setivalue(idx, k);
// FIXME make the allocation more efficient
luaM_reallocvector(L, f->k, oldsize, newsize, TValue);
setobj(L, &f->k[k], v); /* record the position k in the table against key */
f->sizek++;
lua_assert(f->sizek == newsize);
luaC_barrier(L, f, v);
return k;
}
/*
** Add a string to list of constants and return its index.
*/
static int add_string_konstant(lua_State* L, Proto* p, Table* h, TString* s) {
TValue o;
setsvalue(L, &o, s);
return add_konstant(L, p, h, &o, &o); /* use string itself as key */
}
/* Create a Lua TString object from a string. Save it so that we can avoid creating same
* string again.
*/
static inline TString* create_luaString(lua_State* L, Table* h, struct string_object* s) {
if (s->userdata == NULL) {
/* Create and save it */
s->userdata = intern_string(L, h, s->str, s->len);
}
return (TString*)s->userdata;
}
/* Add a string constant to Proto and return its index */
static int lua_newStringConstant(void* context, Proto* proto, struct string_object* s) {
struct CompilerContext* ccontext = (struct CompilerContext*)context;
lua_State* L = ccontext->L;
Table* h = ccontext->h;
TString* ts = create_luaString(L, h, s);
return add_string_konstant(L, proto, h, ts);
}
/* Add an upvalue. If the upvalue refers to a local variable in parent proto then idx should contain
* the register for the local variable and instack should be true, else idx should have the index of
* upvalue in parent proto and instack should be false.
*/
static int lua_addUpValue(void* context, Proto* f, struct string_object* name, unsigned idx, int instack, unsigned tc,
struct string_object* usertype) {
ravitype_t typecode = (ravitype_t)tc;
struct CompilerContext* ccontext = (struct CompilerContext*)context;
lua_State* L = ccontext->L;
Table* h = ccontext->h;
int oldsize = f->sizeupvalues;
int newsize = oldsize + 1;
int pos = oldsize;
// checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
// FIXME optimize the allocation
luaM_reallocvector(L, f->upvalues, oldsize, newsize, Upvaldesc);
f->sizeupvalues++;
lua_assert(f->sizeupvalues == newsize);
f->upvalues[pos].instack = cast_byte(instack); /* is the upvalue in parent function's local stack ? */
f->upvalues[pos].idx = cast_byte(idx); /* If instack then parent's local register else parent's upvalue index */
TString* tsname = create_luaString(L, h, name); /* name of the variable */
f->upvalues[pos].name = tsname;
f->upvalues[pos].ravi_type = typecode;
if (usertype != NULL) {
/* User type string goes into the proto's constant table */
int kpos = lua_newStringConstant(context, f, usertype);
f->upvalues[pos].usertype = tsvalue(&f->k[kpos]);
}
else {
f->upvalues[pos].usertype = NULL;
}
luaC_objbarrier(L, f, tsname);
return pos;
}
static void init_C_compiler(void* context) {
struct CompilerContext* ccontext = (struct CompilerContext*)context;
#ifdef USE_MIRJIT
mir_prepare(ccontext->jit->jit, 2);
#endif
}
static void* compile_C(void* context, const char* C_src, unsigned len) {
struct CompilerContext* ccontext = (struct CompilerContext*)context;
fprintf(stdout, "%s\n", C_src);
#ifdef USE_MIRJIT
return mir_compile_C_module(&ccontext->jit->options, ccontext->jit->jit, C_src, "input");
#else
return NULL;
#endif
}
static void finish_C_compiler(void* context) {
struct CompilerContext* ccontext = (struct CompilerContext*)context;
#ifdef USE_MIRJIT
mir_cleanup(ccontext->jit->jit);
#endif
}
static lua_CFunction get_compiled_function(void* context, void* module, const char* name) {
struct CompilerContext* ccontext = (struct CompilerContext*)context;
#if USE_MIRJIT
MIR_module_t M = (MIR_module_t)module;
return (lua_CFunction)mir_get_func(ccontext->jit->jit, M, name);
#else
return NULL;
#endif
}
static void lua_setProtoFunction(void* context, Proto* p, lua_CFunction func) {
p->ravi_jit.jit_function = func;
p->ravi_jit.jit_status = RAVI_JIT_COMPILED;
}
static void lua_setVarArg(void* context, Proto* p) { p->is_vararg = 1; }
static void lua_setNumParams(void* context, Proto* p, unsigned num_params) { p->numparams = cast_byte(num_params); }
static void lua_setMaxStackSize(void *context, Proto *p, unsigned max_stack_size) {
p->maxstacksize = cast_byte(max_stack_size);
}
static int load_and_compile(lua_State* L) {
const char* s = luaL_checkstring(L, 1);
struct CompilerContext ccontext = {.L = L, .jit = G(L)->ravi_state};
LClosure* cl = luaF_newLclosure(L, 1); /* create main closure with 1 up-value for _ENV */
setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */
luaD_inctop(L);
ccontext.h = luaH_new(L); /* create table for string constants */
sethvalue(L, L->top, ccontext.h); /* anchor it */
luaD_inctop(L);
Proto* main_proto = cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p);
struct Ravi_CompilerInterface ravicomp_interface = {.source = s,
.source_len = strlen(s),
.source_name = "input",
.main_proto = main_proto,
.context = &ccontext,
.lua_newProto = lua_newProto,
.lua_newStringConstant = lua_newStringConstant,
.lua_addUpValue = lua_addUpValue,
.lua_setVarArg = lua_setVarArg,
.lua_setProtoFunction = lua_setProtoFunction,
.lua_setNumParams = lua_setNumParams,
.lua_setMaxStackSize = lua_setMaxStackSize,
.init_C_compiler = init_C_compiler,
.compile_C = compile_C,
.finish_C_compiler = finish_C_compiler,
.get_compiled_function = get_compiled_function,
.debug_message = debug_message,
.error_message = error_message};
int rc = raviX_compile(&ravicomp_interface);
L->top--; /* remove table for string constants */
if (rc == 0) {
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
luaF_initupvals(L, cl);
return 1;
}
else {
lua_error(L);
return 0;
}
}
static const luaL_Reg ravilib[] = {{"load", load_and_compile}, {NULL, NULL}};
int(raviopen_compiler)(lua_State* L) {
luaL_newlib(L, ravilib);
return 1;
}

@ -0,0 +1,10 @@
f = compiler.load("return 1, 'hello', 5.6, true")
assert(f and type(f) == 'function')
local x = 4.3
local a,b,c,d,e = f()
assert(a == 1)
assert(b == 'hello')
assert(c == 5.6)
assert(d == true)
assert(x == 4.3)
assert(e == nil)

@ -0,0 +1,8 @@
f = compiler.load("local a, b, c = 4.2, true, 'hi' return a, b, c")
assert(f and type(f) == 'function')
local z = 62
local a,b,c,d = f()
assert(z == 62)
assert(a == 4.2)
assert(b == true)
assert(c == 'hi')

@ -0,0 +1,3 @@
f = compiler.load("local a,b = 1,2 return a or b");
assert(f and type(f) == 'function')
assert(f() == 1)

@ -0,0 +1,3 @@
f = compiler.load("local a,b = 1,2 return a and b");
assert(f and type(f) == 'function')
assert(f() == 2)

@ -0,0 +1,3 @@
f = compiler.load("local a = 2 return 1 or a");
assert(f and type(f) == 'function')
assert(f() == 1)

@ -0,0 +1,3 @@
f = compiler.load("local a = 2 return 1 and a");
assert(f and type(f) == 'function')
assert(f() == 2)
Loading…
Cancel
Save