Merge branch 'master' into ravi-distro

pull/167/head
Dibyendu Majumdar 5 years ago
commit 460d32f15f

@ -9,11 +9,11 @@ AlignEscapedNewlinesLeft: true
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: true

@ -0,0 +1,8 @@
# These are supported funding model platforms
github: dibyendumajumdar # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
custom: # Replace with a single custom sponsorship URL

@ -6,25 +6,18 @@ env:
compiler:
- gcc
cache: ccache
dist: xenial
addons:
apt:
sources:
- llvm-toolchain-precise
- ubuntu-toolchain-r-test
packages:
- clang-3.7
- g++-5
- gcc-5
- g++
- gcc
- ccache
install:
- if [ "$CXX" = "g++" ]; then export CXX="ccache g++-5" CC="ccache gcc-5"; fi
- if [ "$CXX" = "clang++" ]; then export CXX="ccache clang++-3.7" CC="ccache clang-3.7"; fi
- curl https://cmake.org/files/v3.4/cmake-3.4.0-Linux-x86_64.tar.gz | tar -xzf -
- curl http://releases.llvm.org/6.0.1/clang+llvm-6.0.1-x86_64-linux-gnu-ubuntu-14.04.tar.xz | tar -xJf -
- curl http://releases.llvm.org/6.0.1/clang+llvm-6.0.1-x86_64-linux-gnu-ubuntu-16.04.tar.xz | tar -xJf -
script:
- if [ "$CXX" = "g++" ]; then export CXX="ccache g++-5" CC="ccache gcc-5"; fi
- if [ "$CXX" = "clang++" ]; then export CXX="ccache clang++-3.7" CC="ccache clang-3.7"; fi
- mkdir $TRAVIS_BUILD_DIR/build
- cd $TRAVIS_BUILD_DIR/build && $TRAVIS_BUILD_DIR/cmake-3.4.0-Linux-x86_64/bin/cmake -DCMAKE_BUILD_TYPE=Debug -DLLVM_DIR=$TRAVIS_BUILD_DIR/clang+llvm-6.0.1-x86_64-linux-gnu-ubuntu-14.04/lib/cmake/llvm -G "Unix Makefiles" -DLLVM_JIT=ON ..
- cd $TRAVIS_BUILD_DIR/build && $TRAVIS_BUILD_DIR/cmake-3.4.0-Linux-x86_64/bin/cmake -DCMAKE_BUILD_TYPE=Debug -DLLVM_DIR=$TRAVIS_BUILD_DIR/clang+llvm-6.0.1-x86_64-linux-gnu-ubuntu-16.04/lib/cmake/llvm -G "Unix Makefiles" -DLLVM_JIT=ON ..
- cd $TRAVIS_BUILD_DIR/build && make
- cd $TRAVIS_BUILD_DIR/lua-tests && sh ./run_travis_tests.sh $TRAVIS_BUILD_DIR/build/ravi

@ -30,7 +30,10 @@ if (ASM_VM)
# For now we switch to static build
# TODO A fix is needed to ensure that in shared library the asm functions are resolved
set(STATIC_BUILD ON)
# LTESTS messes with global state and breaks the ASMVM dispatch table
set(LTESTS OFF)
set(LLVM_JIT OFF)
set(OMR_JIT OFF)
endif()
if (STATIC_BUILD)
@ -421,58 +424,55 @@ set(NOJIT_RAVI_SRCS
${DMR_C_JIT_SRCS}
src/ravi_nojit.c)
# We always build a static library without JIT so that
# we can create some default executables
add_library(libravinojit_static
${NOJIT_RAVI_SRCS})
set_target_properties(libravinojit_static PROPERTIES PREFIX "") # As we already prefix with lib
target_link_libraries(libravinojit_static ${EXTRA_LIBRARIES})
# Create a simple NoJIT version of statically linked ravi
# This is sometimes useful in other projects that just need a Lua commandline
# but do not care about the shared library
add_executable(ravi_s
src/lua.c)
target_link_libraries(ravi_s libravinojit_static)
# Ravi VSCode Debug adapter
set(RAVI_DEBUGGER_TARGET ravidebug)
add_executable(${RAVI_DEBUGGER_TARGET}
vscode-debugger/src/ravidebug.c
vscode-debugger/src/json.c
vscode-debugger/src/protocol.c)
target_link_libraries(${RAVI_DEBUGGER_TARGET} libravinojit_static)
# Tests for VSCode Debug Adapter
add_executable(testravidebug
vscode-debugger/src/testravidebug.c
vscode-debugger/src/json.c
vscode-debugger/src/protocol.c)
target_link_libraries(testravidebug libravinojit_static)
# Simple VM tests
add_executable(test_vm tests/test_vm.c)
target_link_libraries(test_vm ${LIBRAVI_NAME})
if (LLVM_JIT)
# LLVM playground
add_executable(test_llvm tests/test_llvm.cpp)
set_target_properties(test_llvm PROPERTIES COMPILE_DEFINITIONS "USE_LLVM=1")
target_link_libraries(test_llvm ${LIBRAVI_NAME})
endif ()
add_executable(test_misc tests/test_misc.c)
if (NOT ASM_VM)
set(RAVI_STATICEXEC_TARGET ravi_s)
# We always build a static library without JIT so that
# we can create some default executables
add_library(libravinojit_static
${NOJIT_RAVI_SRCS})
set_target_properties(libravinojit_static PROPERTIES PREFIX "") # As we already prefix with lib
target_link_libraries(libravinojit_static ${EXTRA_LIBRARIES})
# Create a simple NoJIT version of statically linked ravi
# This is sometimes useful in other projects that just need a Lua commandline
# but do not care about the shared library
add_executable(ravi_s
src/lua.c)
target_link_libraries(ravi_s libravinojit_static)
# Ravi VSCode Debug adapter
set(RAVI_DEBUGGER_TARGET ravidebug)
add_executable(${RAVI_DEBUGGER_TARGET}
vscode-debugger/src/ravidebug.c
vscode-debugger/src/json.c
vscode-debugger/src/protocol.c)
target_link_libraries(${RAVI_DEBUGGER_TARGET} libravinojit_static)
# Tests for VSCode Debug Adapter
add_executable(testravidebug
vscode-debugger/src/testravidebug.c
vscode-debugger/src/json.c
vscode-debugger/src/protocol.c)
target_link_libraries(testravidebug libravinojit_static)
add_test(TestRaviDebug testravidebug)
add_executable(test_vm tests/test_vm.c)
target_link_libraries(test_vm ${LIBRAVI_NAME})
add_test(TestVM test_vm)
else()
# Simple VM tests
add_executable(test_asmvm tests/test_asmvm.c)
target_link_libraries(test_asmvm ${LIBRAVI_NAME})
add_test(TestRaviDebug testravidebug)
if (LLVM_JIT)
add_test(TestLLVM test_llvm)
endif ()
add_test(TestVM test_vm)
add_test(TestMisc test_misc)
add_test(TestVM test_asmvm)
endif()
install(FILES ${LUA_HEADERS}
DESTINATION include/ravi)
install(TARGETS ${LIBRAVI_NAME} ravi ${RAVI_DEBUGGER_TARGET} ravi_s
install(TARGETS ${LIBRAVI_NAME} ravi ${RAVI_DEBUGGER_TARGET} ${RAVI_STATICEXEC_TARGET}
RUNTIME DESTINATION bin
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib)

@ -34,7 +34,7 @@ Features
* `LLVM <http://www.llvm.org/>`_ powered JIT compiler
* `Eclipse OMR <https://github.com/dibyendumajumdar/nj>`_ powered JIT compiler
* Built-in C pre-processor, parser and JIT compiler
* A `distribution with batteries <https://github.com/dibyendumajumdar/ravi-distro>`_.
* A `distribution with batteries <https://github.com/dibyendumajumdar/Suravi>`_.
Documentation
=============
@ -47,17 +47,17 @@ Documentation
Lua Goodies
===========
* `An Introduction to Lua <http://the-ravi-programming-language.readthedocs.io/en/latest/lua-introduction.html>`_ attempts to provide a quick overview of Lua for folks coming from other languages.
* `Lua 5.3 Bytecode Reference <http://the-ravi-programming-language.readthedocs.io/en/latest/lua_bytecode_reference.html>`_ is my attempt to bring up to date the `Lua 5.1 Bytecode Reference <http://luaforge.net/docman/83/98/ANoFrillsIntroToLua51VMInstructions.pdf>`_.
* `Lua 5.3 Bytecode Reference <http://the-ravi-programming-language.readthedocs.io/en/latest/lua_bytecode_reference.html>`_ is my attempt to bring up to date the `Lua 5.1 Bytecode Reference <http://luaforge.net/docman/83/98/ANoFrillsIntroToLua51VMInstructions.pdf>`_.
Compatibility with Lua
======================
Ravi should be able to run all Lua 5.3 programs in interpreted mode, but following should be noted:
Ravi should be able to run all Lua 5.3 programs in interpreted mode, but following should be noted:
* Ravi supports optional typing and enhanced types such as arrays (described above). Programs using these features cannot be run by standard Lua. However all types in Ravi can be passed to Lua functions; operations on Ravi arrays within Lua code will be subject to restrictions as described in the section above on arrays.
* Ravi supports optional typing and enhanced types such as arrays (described above). Programs using these features cannot be run by standard Lua. However all types in Ravi can be passed to Lua functions; operations on Ravi arrays within Lua code will be subject to restrictions as described in the section above on arrays.
* Values crossing from Lua to Ravi will be subjected to typechecks should these values be assigned to typed variables.
* Upvalues cannot subvert the static typing of local variables (issue #26) when types are annotated.
* Certain Lua limits are reduced due to changed byte code structure. These are described below.
* Ravi uses an extended bytecode which means it is not compatible with Lua 5.3 bytecode.
* Ravi uses an extended bytecode which means it is not compatible with Lua 5.3 bytecode.
+-----------------+-------------+-------------+
| Limit name | Lua value | Ravi value |
@ -80,19 +80,21 @@ When JIT compilation is enabled there are following additional constraints:
History
=======
* 2015
* 2015
- Implemented JIT compilation using LLVM
- Implemented libgccjit based alternative JIT (now discontinued)
* 2016
- Implemented debugger for Ravi and Lua 5.3 for `Visual Studio Code <https://github.com/dibyendumajumdar/ravi/tree/master/vscode-debugger>`_
* 2017
- Embedded C compiler using dmrC project (C JIT compiler)
* 2016
- Implemented debugger for Ravi and Lua 5.3 for `Visual Studio Code <https://github.com/dibyendumajumdar/ravi/tree/master/vscode-debugger>`_
* 2017
- Embedded C compiler using dmrC project (C JIT compiler)
- Additional type-annotations
* 2018
* 2018
- Implemented Eclipse OMR JIT backend
- Created `Ravi with batteries <https://github.com/dibyendumajumdar/ravi-distro>`_.
- Created `Ravi with batteries <https://github.com/dibyendumajumdar/Suravi>`_.
* 2019 (Plan)
- New parser, type checker and code generator
- Release Ravi 1.0
License
=======
MIT License for LLVM version.

@ -3,5 +3,5 @@ cd llvm64
rem pre LLVM 3.9
rem cmake -DCMAKE_INSTALL_PREFIX=c:\ravi -G "Visual Studio 14 Win64" -DLLVM_JIT=ON -DLLVM_DIR=c:\LLVM37\share\llvm\cmake ..
rem cmake -DCMAKE_INSTALL_PREFIX=c:\ravi -G "Visual Studio 15 2017 Win64" -DLLVM_JIT=ON -DLLVM_DIR=c:\d\LLVM40_64\lib\cmake\llvm ..
cmake -DCMAKE_INSTALL_PREFIX=c:\Software\ravi -G "Visual Studio 15 2017 Win64" -DSTATIC_BUILD=ON -DLLVM_JIT=ON -DLLVM_DIR=c:\Software\llvm501r\lib\cmake\llvm ..
cmake -DCMAKE_INSTALL_PREFIX=c:\Software\ravi -G "Visual Studio 15 2017 Win64" -DSTATIC_BUILD=ON -DLLVM_JIT=ON -DLLVM_DIR=c:\Software\llvm601r\lib\cmake\llvm ..
cd ..

@ -1,4 +1,4 @@
mkdir nojit64
cd nojit64
cmake -DCMAKE_INSTALL_PREFIX=c:\Software\ravi -DCMAKE_BUILD_TYPE=Debug -DSTATIC_BUILD=OFF -G "Visual Studio 15 2017 Win64" ..
cmake -DCMAKE_INSTALL_PREFIX=c:\Software\ravi -DCMAKE_BUILD_TYPE=Release -DSTATIC_BUILD=OFF -G "Visual Studio 15 2017 Win64" ..
cd ..

@ -1,4 +1,5 @@
mkdir buildllvm
cd buildllvm
#cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM/share/llvm/cmake ..
cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM5/lib/cmake/llvm ..
#cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM5/lib/cmake/llvm ..
cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/Software/ravi -DLLVM_DIR=$HOME/Software/llvm801/lib/cmake/llvm ..

@ -38,7 +38,8 @@ typedef enum BinOpr {
/** RAVI change */
typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_TO_INTEGER,
OPR_TO_NUMBER, OPR_TO_INTARRAY, OPR_TO_NUMARRAY, OPR_TO_TABLE, OPR_TO_STRING, OPR_TO_CLOSURE, OPR_TO_TYPE, OPR_NOUNOPR } UnOpr;
OPR_TO_NUMBER, OPR_TO_INTARRAY, OPR_TO_NUMARRAY, OPR_TO_TABLE, OPR_TO_STRING,
OPR_TO_CLOSURE, OPR_TO_TYPE, OPR_NOUNOPR } UnOpr;
/* get (pointer to) instruction of given 'expdesc' */
#define getinstruction(fs,e) ((fs)->f->code[(e)->u.info])

@ -41,6 +41,7 @@
** 0 - Lua function
** 1 - light C function
** 2 - regular C function (closure)
** 4 - fast light C dunction (Ravi extension)
*/
/* Variant tags for functions */
@ -145,6 +146,7 @@ typedef struct lua_TValue {
#define novariant(x) ((x) & 0x0F)
/* type tag of a TValue (bits 0-3 for tags + variant bits 4-6) */
/* 7F is 0111 1111 */
#define ttype(o) (rttype(o) & 0x7F)
/* type tag of a TValue with no variants (bits 0-3) */
@ -239,6 +241,9 @@ typedef struct lua_TValue {
#define setfvalue(obj,x) \
{ TValue *io=(obj); val_(io).f=(x); settt_(io, LUA_TLCF); }
/* The Fast C function call type is encoded as two
bytes. The Hi Byte holds a function tag. The Lo Byte
holds the Lua typecode */
#define setfvalue_fastcall(obj, x, tag) \
{ \
TValue *io = (obj); \
@ -246,7 +251,7 @@ typedef struct lua_TValue {
val_(io).p = (x); \
settt_(io, ((tag << 8) | RAVI_TFCF)); \
}
#define getfcf_tag(typecode) (typecode >> 8)
#define setpvalue(obj,x) \
{ TValue *io=(obj); val_(io).p=(x); settt_(io, LUA_TLIGHTUSERDATA); }
@ -594,10 +599,10 @@ typedef enum RaviArrayModifer {
/** RAVI extension */
typedef struct RaviArray {
char *data;
unsigned int len; /* RAVI len specialization */
unsigned int size; /* amount of memory allocated */
lu_byte array_type; /* RAVI specialization */
char *data; /* Note that the array data is 0-based so this holds 1+Lua length items */
unsigned int len; /* RAVI len specialization, holds real length which is 1+Lua length */
unsigned int size; /* amount of memory allocated */
lu_byte array_type; /* RAVI specialization */
lu_byte array_modifier; /* Flags that affect how the array is handled */
} RaviArray;
@ -637,7 +642,9 @@ typedef struct Table {
*/
#define luaO_nilobject (&luaO_nilobject_)
/* Internal assembler functions. Never call these directly from C. */
/* Internal assembler functions. Never call these directly from C.
Note that such functions do not follow calling conventions and
are only used by ASM VM to implement bytecodes */
typedef void(*ASMFunction)(void);

@ -26,6 +26,24 @@
** 'tobefnz': all objects ready to be finalized;
** 'fixedgc': all objects that are not to be collected (currently
** only small strings, such as reserved words).
**
** Moreover, there is another set of lists that control gray objects.
** These lists are linked by fields 'gclist'. (All objects that
** can become gray have such a field. The field is not the same
** in all objects, but it always has this name.) Any gray object
** must belong to one of these lists, and all objects in these lists
** must be gray:
**
** 'gray': regular gray objects, still waiting to be visited.
** 'grayagain': objects that must be revisited at the atomic phase.
** That includes
** - black objects got in a write barrier;
** - all kinds of weak tables during propagation phase;
** - all threads.
** 'weak': tables with weak values to be cleared;
** 'ephemeron': ephemeron tables with white->white entries;
** 'allweak': tables with weak keys and/or weak values to be cleared.
** The last three lists are used only during the atomic phase.
*/
@ -160,7 +178,7 @@ typedef struct global_State {
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
/* RAVI additions */
ravi_State *ravi_state;
ASMFunction dispatch[NUM_OPCODES];
ASMFunction dispatch[NUM_OPCODES]; /* Dispatch table for ASM VM - wip */
ravi_Writeline ravi_writeline;
ravi_Writestring ravi_writestring;
ravi_Writestringerror ravi_writestringerror;
@ -172,6 +190,7 @@ typedef struct global_State {
#endif
} global_State;
/* Offset of the ASM VM dispatch table */
#define DISPATCH_OFFSET ((int)offsetof(global_State, dispatch))
/*

@ -77,27 +77,33 @@ required to get to a node in the hash table
#endif
#if defined(RAVI_ENABLED)
/*
** search function for short strings
*/
#if !RAVI_USE_INLINE_SHORTSTR_TGET
LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
#else
LUAI_FUNC const TValue *luaH_getshortstr_continue(Table *t, TString *key, Node *n);
static RAVI_ALWAYS_INLINE const TValue *luaH_getshortstr(Table *t, TString *key) {
/* We inline the lookup in first two slots */
Node *n = hashstr(t, key);
lua_assert(key->tt == LUA_TSHRSTR);
for (;;) { /* check whether 'key' is somewhere in the chain */
const TValue *k = gkey(n);
if (ttisshrstring(k) && eqshrstr(tsvalue(k), key))
return gval(n); /* that's it */
else {
int nx = gnext(n);
if (nx == 0)
return luaO_nilobject; /* not found */
n += nx;
}
}
const TValue *k = gkey(n);
if (ttisshrstring(k) && eqshrstr(tsvalue(k), key))
return gval(n); /* that's it */
int nx = gnext(n);
if (nx == 0)
return luaO_nilobject; /* not found */
n += nx;
k = gkey(n);
if (ttisshrstring(k) && eqshrstr(tsvalue(k), key))
return gval(n); /* that's it */
nx = gnext(n);
if (nx == 0)
return luaO_nilobject; /* not found */
/* Okay continue search slowly */
return luaH_getshortstr_continue(t, key, n);
}
#else
LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
#endif
LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
@ -197,8 +203,8 @@ LUAI_FUNC const TValue *raviH_slice_parent(lua_State *L, TValue *slice);
raviH_set_float(L, t, ukey, (value)); \
}
LUAI_FUNC void raviH_get_number_array_rawdata(lua_State *L, Table *t, lua_Number **startp, lua_Number **endp);
LUAI_FUNC void raviH_get_integer_array_rawdata(lua_State *L, Table *t, lua_Integer **startp, lua_Integer **endp);
LUAI_FUNC void raviH_get_number_array_rawdata(lua_State *L, Table *t, Ravi_NumberArray *data);
LUAI_FUNC void raviH_get_integer_array_rawdata(lua_State *L, Table *t, Ravi_IntegerArray *data);
#if defined(LUA_DEBUG)
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);

@ -23,7 +23,7 @@
#define LUA_VERSION "Ravi " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#define LUA_COPYRIGHT LUA_RELEASE "\nCopyright (C) 1994-2018 Lua.org, PUC-Rio\nPortions Copyright (C) 2015-2018 Dibyendu Majumdar"
#define LUA_COPYRIGHT LUA_RELEASE "\nCopyright (C) 1994-2019 Lua.org, PUC-Rio\nPortions Copyright (C) 2015-2019 Dibyendu Majumdar"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes, Dibyendu Majumdar"
@ -549,9 +549,13 @@ struct lua_Debug {
LUA_API void (ravi_pushcfastcall)(lua_State *L, void *ptr, int tag);
#define RAVI_TFCF_EXP 1
#define RAVI_TFCF_LOG 2
#define RAVI_TFCF_D_D 3
/* Allowed tags - subject to change. Max value is 128. Note that
each tag requires special handling in ldo.c */
enum {
RAVI_TFCF_EXP = 1,
RAVI_TFCF_LOG = 2,
RAVI_TFCF_D_D = 3,
};
/* Create an integer array (specialization of Lua table)
* of given size and initialize array with supplied initial value
@ -590,10 +594,24 @@ LUA_API int ravi_is_integer_array(lua_State *L, int idx);
/* Get the raw data associated with the number array at idx.
* Note that Ravi arrays have an extra element at offset 0 - this
* function returns a pointer to &data[0]. The number of
* array elements is returned in len.
* array elements is returned in length.
*/
typedef struct {
lua_Number *data;
unsigned int length;
} Ravi_NumberArray;
LUA_API void ravi_get_number_array_rawdata(lua_State *L, int idx, Ravi_NumberArray *array_data);
/* Get the raw data associated with the integer array at idx.
* Note that Ravi arrays have an extra element at offset 0 - this
* function returns a pointer to &data[0]. The number of
* array elements is returned in length.
*/
LUA_API lua_Number *ravi_get_number_array_rawdata(lua_State *L, int idx, size_t *len);
LUA_API lua_Integer *ravi_get_integer_array_rawdata(lua_State *L, int idx, size_t *len);
typedef struct {
lua_Integer *data;
unsigned int length;
} Ravi_IntegerArray;
LUA_API void ravi_get_integer_array_rawdata(lua_State *L, int idx, Ravi_IntegerArray *array_data);
/* API to set the output functions used by Lua / Ravi
* This allows the default implementations to be overridden
@ -638,7 +656,6 @@ LUA_API void ravi_set_debuglevel(int level);
#define RAVI_DEBUG_STACK(p) if ((ravi_parser_debug & 8) != 0) {p;} else {}
#define RAVI_ENABLED 1
#define RAVI_BYTECODE_PROFILING_ENABLED 0

@ -824,6 +824,7 @@
#define RAVI_USE_NEWHASH 1
#define RAVI_USE_INLINE_SHORTSTR_TGET 1
#define RAVI_USE_LLVM_BRANCH_WEIGHTS 1
/* If following is defined as true then LLVM instructions emitted for arithmetic ops
priority floating point ops, else default is to prioritise integer ops */

@ -41,7 +41,6 @@
/* Select native target if no target defined. */
#ifndef RAVI__TARGET
#if defined(__i386) || defined(__i386__) || defined(_M_IX86)
#error "No support for this architecture (yet)"
#define RAVI__TARGET RAVI__ARCH_X86
#elif defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
#define RAVI__TARGET RAVI__ARCH_X64

@ -27,7 +27,7 @@
#include "llvm/Config/llvm-config.h"
#if (LLVM_VERSION_MAJOR < 3 || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5)
#if (LLVM_VERSION_MAJOR < 3 || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5 || LLVM_VERSION_MAJOR == 7)
#error Unsupported LLVM version
#endif
@ -37,6 +37,12 @@
#define USE_ORC_JIT 0
#endif
#if LLVM_VERSION_MAJOR >= 8 && !defined(_WIN32)
#define USE_ORCv2_JIT 1
#else
#define USE_ORCv2_JIT 0
#endif
// In lua.c we include this just to get version numbers
// We cannot have C++ headers in that case
#ifdef __cplusplus
@ -71,7 +77,7 @@
#include "llvm/Support/FormattedStream.h"
#if USE_ORC_JIT
#if USE_ORC_JIT || USE_ORCv2_JIT
#include "llvm/ADT/STLExtras.h"
#include "llvm/ExecutionEngine/JITSymbol.h"
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
@ -87,6 +93,12 @@
#include "llvm/Support/Error.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/Scalar/GVN.h"
#if LLVM_VERSION_MAJOR >= 8
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
#include "llvm/ExecutionEngine/Orc/Legacy.h"
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
#endif
#endif
#include <algorithm>

@ -389,43 +389,76 @@ class RaviJITStateFactory {
// All of the JIT information is held here
class RaviJITState {
friend class RaviJITModule;
#if USE_ORCv2_JIT
std::unique_ptr<llvm::orc::ExecutionSession> ES;
std::unique_ptr<llvm::orc::RTDyldObjectLinkingLayer> ObjectLayer;
std::unique_ptr<llvm::orc::IRCompileLayer> CompileLayer;
std::unique_ptr<llvm::orc::IRTransformLayer> OptimizeLayer;
std::unique_ptr<llvm::DataLayout> DL;
std::unique_ptr<llvm::orc::MangleAndInterner> Mangle;
std::unique_ptr<llvm::orc::ThreadSafeContext> Ctx;
std::unique_ptr<llvm::TargetMachine> TM;
#elif USE_ORC_JIT
// The LLVM Context
llvm::LLVMContext *context_;
std::unique_ptr<llvm::LLVMContext> context_;
#if USE_ORC_JIT
// From LLVM version5 onwards we use the new ORC apis
// The main benefit is that memory management is tighter,
// all the IR in modules get released after compilation
// MCJIT is also likely to be removed at some time in
// future so we needed to migrate anyway
// We don't use ORC apis in earlier versions because
// the apis have changed over the releases so it
// We don't use ORC apis in earlier versions because
// the apis have changed over the releases so it
// is simpler to use them in 5.0 and above.
// The ORC usage here is heavily based upon the kaleidoscope
// sample, with some adjustments.
#if LLVM_VERSION_MAJOR >= 8
using ObjectLayerT = llvm::orc::LegacyRTDyldObjectLinkingLayer;
using CompileLayerT = llvm::orc::LegacyIRCompileLayer<ObjectLayerT, llvm::orc::SimpleCompiler>;
using OptimizeFunction = std::function<std::unique_ptr<llvm::Module>(std::unique_ptr<llvm::Module>)>;
using OptimizerLayerT = llvm::orc::LegacyIRTransformLayer<CompileLayerT, OptimizeFunction>;
using ModuleHandle = llvm::orc::VModuleKey;
using CODLayerT = llvm::orc::LegacyCompileOnDemandLayer<OptimizerLayerT>;
#else
using ObjectLayerT = llvm::orc::RTDyldObjectLinkingLayer;
using CompileLayerT =
llvm::orc::IRCompileLayer<ObjectLayerT, llvm::orc::SimpleCompiler>;
using OptimizeFunction = std::function<std::shared_ptr<llvm::Module>(
std::shared_ptr<llvm::Module>)>;
using OptimizerLayerT =
llvm::orc::IRTransformLayer<CompileLayerT, OptimizeFunction>;
using CompileLayerT = llvm::orc::IRCompileLayer<ObjectLayerT, llvm::orc::SimpleCompiler>;
using OptimizeFunction = std::function<std::shared_ptr<llvm::Module>(std::shared_ptr<llvm::Module>)>;
using OptimizerLayerT = llvm::orc::IRTransformLayer<CompileLayerT, OptimizeFunction>;
using ModuleHandle = OptimizerLayerT::ModuleHandleT;
#endif
std::unique_ptr<llvm::TargetMachine> TM;
std::unique_ptr<llvm::DataLayout> DL;
std::unique_ptr<ObjectLayerT> ObjectLayer;
std::unique_ptr<CompileLayerT> CompileLayer;
std::unique_ptr<OptimizerLayerT> OptimizeLayer;
#if LLVM_VERSION_MAJOR >= 8
std::map<ModuleHandle, std::shared_ptr<llvm::orc::SymbolResolver> > Resolvers;
std::shared_ptr<llvm::orc::SymbolStringPool> StringPool;
std::unique_ptr<llvm::orc::ExecutionSession> ES;
std::unique_ptr<llvm::orc::JITCompileCallbackManager> CompileCallbackManager;
std::unique_ptr<CODLayerT> CompileOnDemandLayer;
#endif
#else
// Not ORC_JIT
// The LLVM Context
std::unique_ptr<llvm::LLVMContext> context_;
#endif // USE_ORCv2_JIT
// The triple represents the host target
std::string triple_;
// Lua type definitions
LuaLLVMTypes *types_;
std::unique_ptr<LuaLLVMTypes> types_;
// Should we auto compile what we can?
unsigned int auto_ : 1;
@ -438,7 +471,7 @@ class RaviJITState {
// Size level (LLVM PassManagerBuilder)
unsigned int size_level_ : 2;
// Verbosity
unsigned int verbosity_ : 3;
@ -449,7 +482,9 @@ class RaviJITState {
// Enable extra validation such as IR verification
// May slow down compilation
unsigned int validation_ : 1;
unsigned int use_dmrc_ : 1;
// Flag to control calls to collect
int gcstep_;
@ -462,7 +497,7 @@ class RaviJITState {
// Count of modules allocated
// Used to debug module deallocation
size_t allocated_modules_;
// flag to help avoid recursion
int compiling_;
@ -470,19 +505,50 @@ class RaviJITState {
RaviJITState();
~RaviJITState();
#if USE_ORC_JIT
#if USE_ORCv2_JIT
llvm::LLVMContext &context() { return *Ctx->getContext(); }
llvm::Expected<llvm::orc::ThreadSafeModule> optimizeModule(llvm::orc::ThreadSafeModule TSM,
const llvm::orc::MaterializationResponsibility &R);
llvm::Error addModule(std::unique_ptr<llvm::Module> M);
llvm::Expected<llvm::JITEvaluatedSymbol> findSymbol(llvm::StringRef Name) {
return ES->lookup({&ES->getMainJITDylib()}, (*Mangle)(Name.str()));
}
const llvm::DataLayout &getDataLayout() const { return *DL; }
#elif USE_ORC_JIT
#if LLVM_VERSION_MAJOR >= 8
std::unique_ptr<llvm::Module> optimizeModule(std::unique_ptr<llvm::Module> M);
#else
std::shared_ptr<llvm::Module> optimizeModule(std::shared_ptr<llvm::Module> M);
#endif
llvm::TargetMachine &getTargetMachine() { return *TM; }
ModuleHandle addModule(std::unique_ptr<llvm::Module> M);
llvm::JITSymbol findSymbol(const std::string Name);
llvm::JITSymbol findSymbol(const std::string &Name);
void removeModule(ModuleHandle H);
llvm::LLVMContext &context() { return *context_; }
#else
// Not ORC JIT
llvm::LLVMContext &context() { return *context_; }
#endif
void addGlobalSymbol(const std::string &name, void *address);
void dump();
llvm::LLVMContext &context() { return *context_; }
LuaLLVMTypes *types() const { return types_; }
LuaLLVMTypes *types() const { return types_.get(); }
const std::string &triple() const { return triple_; }
bool is_auto() const { return auto_; }
void set_auto(bool value) { auto_ = value; }
@ -490,42 +556,40 @@ class RaviJITState {
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_verbosity() const { return verbosity_; }
void set_verbosity(int value) {
if (value >= 0 && value <= 3) verbosity_ = value;
if (value >= 0 && value <= 3)
verbosity_ = 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_; }
int get_validation() const { return validation_; }
void set_validation(bool value) { validation_ = value; }
int get_gcstep() const { return gcstep_; }
void set_gcstep(int value) {
gcstep_ = value > 0 ? value : gcstep_;
}
void set_gcstep(int value) { gcstep_ = value > 0 ? value : gcstep_; }
bool is_tracehook_enabled() const { return tracehook_enabled_; }
void set_tracehook_enabled(bool value) { tracehook_enabled_ = value; }
void incr_allocated_modules() { allocated_modules_++; }
void decr_allocated_modules() { allocated_modules_--; }
size_t allocated_modules() const { return allocated_modules_; }
int get_compiling_flag() const { return compiling_ > 0; }
void set_compiling_flag(bool value) {
if (value)
void set_compiling_flag(bool value) {
if (value)
compiling_++;
else
compiling_--;
compiling_--;
}
int is_use_dmrc() const { return use_dmrc_; }
};
// A wrapper for LLVM Module
@ -534,14 +598,13 @@ class RaviJITModule {
// The Context that owns this module
RaviJITState *owner_;
#if !USE_ORC_JIT
#if USE_ORCv2_JIT
// The LLVM Module within which the functions will be defined
llvm::Module *module_;
std::unique_ptr<llvm::Module> module_;
#elif USE_ORC_JIT
// The execution engine responsible for compiling the
// module
llvm::ExecutionEngine *engine_;
#else
// The LLVM Module within which the functions will be defined
std::unique_ptr<llvm::Module> module_;
@ -549,6 +612,16 @@ class RaviJITModule {
// then a handle is used to refer to it rather than the
// module, as the module may have been deleted by then
RaviJITState::ModuleHandle module_handle_;
#else
// The LLVM Module within which the functions will be defined
llvm::Module *module_;
// The execution engine responsible for compiling the
// module
llvm::ExecutionEngine *engine_;
#endif
// List of JIT functions in this module
@ -563,13 +636,14 @@ class RaviJITModule {
RaviJITModule(RaviJITState *owner);
~RaviJITModule();
#if !USE_ORC_JIT
#if !USE_ORC_JIT && !USE_ORCv2_JIT
llvm::Module *module() const { return module_; }
llvm::ExecutionEngine *engine() const { return engine_; }
#else
// Note that this can return nullptr
// Note that this can return nullptr
llvm::Module *module() const { return module_.get(); }
#endif
RaviJITState *owner() const { return owner_; }
void dump();
void dumpAssembly();
@ -596,8 +670,7 @@ class RaviJITModule {
// 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
llvm::Function *addExternFunction(llvm::FunctionType *type, void *address,
const std::string &name);
llvm::Function *addExternFunction(llvm::FunctionType *type, void *address, const std::string &name);
};
// Represents a JITed or JITable function
@ -629,14 +702,9 @@ class RaviJITFunction {
lua_CFunction *func_ptrptr_;
public:
RaviJITFunction(lua_CFunction *p,
const std::shared_ptr<RaviJITModule> &module,
llvm::FunctionType *type,
llvm::GlobalValue::LinkageTypes linkage,
const std::string &name);
RaviJITFunction(lua_CFunction *p,
const std::shared_ptr<RaviJITModule> &module,
const std::string &name);
RaviJITFunction(lua_CFunction *p, const std::shared_ptr<RaviJITModule> &module, llvm::FunctionType *type,
llvm::GlobalValue::LinkageTypes linkage, const std::string &name);
RaviJITFunction(lua_CFunction *p, const std::shared_ptr<RaviJITModule> &module, const std::string &name);
~RaviJITFunction();
@ -645,7 +713,7 @@ class RaviJITFunction {
// Note that this can return nullptr
llvm::Module *module() const { return module_->module(); }
std::shared_ptr<RaviJITModule> raviModule() const { return module_; }
#if !USE_ORC_JIT
#if !USE_ORC_JIT && !USE_ORCv2_JIT
llvm::ExecutionEngine *engine() const { return module_->engine(); }
#endif
RaviJITState *owner() const { return module_->owner(); }
@ -658,8 +726,7 @@ class RaviJITFunction {
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) {
llvm::Function *addExternFunction(llvm::FunctionType *type, void *address, const std::string &name) {
return module_->addExternFunction(type, address, name);
}
};
@ -815,8 +882,13 @@ class RaviCodeGenerator {
// 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
bool compile(lua_State *L, Proto *p, std::shared_ptr<RaviJITModule> module,
ravi_compile_options_t *options);
bool alt_compile(lua_State *L, Proto *p, std::shared_ptr<RaviJITModule> module, ravi_compile_options_t *options);
// 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
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
@ -830,30 +902,22 @@ class RaviCodeGenerator {
// Argument will be named L
// Initial BasicBlock will be created
// int func(lua_State *L) {
std::unique_ptr<RaviJITFunction> create_function(
Proto *p, std::shared_ptr<RaviJITModule> module,
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);
llvm::CallInst *CreateCall1(llvm::IRBuilder<> *builder, llvm::Value *func,
llvm::Value *arg1);
llvm::CallInst *CreateCall2(llvm::IRBuilder<> *builder, llvm::Value *func,
llvm::Value *arg1, llvm::Value *arg2);
llvm::CallInst *CreateCall3(llvm::IRBuilder<> *builder, llvm::Value *func,
llvm::Value *arg1, llvm::Value *arg2,
llvm::CallInst *CreateCall1(llvm::IRBuilder<> *builder, llvm::Value *func, llvm::Value *arg1);
llvm::CallInst *CreateCall2(llvm::IRBuilder<> *builder, llvm::Value *func, llvm::Value *arg1, llvm::Value *arg2);
llvm::CallInst *CreateCall3(llvm::IRBuilder<> *builder, llvm::Value *func, llvm::Value *arg1, llvm::Value *arg2,
llvm::Value *arg3);
llvm::CallInst *CreateCall4(llvm::IRBuilder<> *builder, llvm::Value *func,
llvm::Value *arg1, llvm::Value *arg2,
llvm::CallInst *CreateCall4(llvm::IRBuilder<> *builder, llvm::Value *func, llvm::Value *arg1, llvm::Value *arg2,
llvm::Value *arg3, llvm::Value *arg4);
llvm::CallInst *CreateCall5(llvm::IRBuilder<> *builder, llvm::Value *func,
llvm::Value *arg1, llvm::Value *arg2,
llvm::Value *arg3, llvm::Value *arg4,
llvm::Value *arg5);
llvm::CallInst *CreateCall5(llvm::IRBuilder<> *builder, llvm::Value *func, llvm::Value *arg1, llvm::Value *arg2,
llvm::Value *arg3, llvm::Value *arg4, llvm::Value *arg5);
void attach_branch_weights(RaviFunctionDef *def, llvm::Instruction *ins,
uint32_t true_branch, uint32_t false_branch);
void attach_branch_weights(RaviFunctionDef *def, llvm::Instruction *ins, uint32_t true_branch, uint32_t false_branch);
void emit_raise_lua_error(RaviFunctionDef *def, const char *str);
@ -864,28 +928,23 @@ class RaviCodeGenerator {
llvm::Instruction *emit_load_proto_sizep(RaviFunctionDef *def);
// Store lua_Number or lua_Integer
llvm::Instruction *emit_store_local_n(RaviFunctionDef *def, llvm::Value *src,
llvm::Value *dest);
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);
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);
// Test if value type is of specific Lua type
// Value_type should have been obtained by emit_load_type()
// 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_value_of_type(RaviFunctionDef *def,
llvm::Value *value_type,
LuaTypeCode lua_typecode,
llvm::Value *emit_is_value_of_type(RaviFunctionDef *def, llvm::Value *value_type, LuaTypeCode lua_typecode,
const char *varname = "value.typeof");
// Test if value type is NOT of specific Lua type
@ -893,9 +952,8 @@ class RaviCodeGenerator {
// 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");
// Test if value type is NOT of specific Lua type class
// i.e. variants are ignore
@ -903,30 +961,23 @@ class RaviCodeGenerator {
// 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_class(
RaviFunctionDef *def, llvm::Value *value_type, int lua_typecode,
const char *varname = "value.not.typeof");
llvm::Value *emit_is_not_value_of_type_class(RaviFunctionDef *def, llvm::Value *value_type, int lua_typecode,
const char *varname = "value.not.typeof");
// emit code for LClosure *cl = clLvalue(ci->func)
// this is same as:
// emit code for (LClosure *)ci->func->value_.gc
llvm::Instruction *emit_gep_ci_func_value_gc_asLClosure(RaviFunctionDef *def);
llvm::Value *emit_gep(RaviFunctionDef *def, const char *name, llvm::Value *s,
int arg1);
llvm::Value *emit_gep(RaviFunctionDef *def, const char *name, llvm::Value *s,
int arg1, int arg2);
llvm::Value *emit_gep(RaviFunctionDef *def, const char *name, llvm::Value *s,
int arg1, int arg2, int arg3);
llvm::Value *emit_gep(RaviFunctionDef *def, const char *name,
llvm::Value *ptr, llvm::Value *arg1, int arg2,
llvm::Value *emit_gep(RaviFunctionDef *def, const char *name, llvm::Value *s, int arg1);
llvm::Value *emit_gep(RaviFunctionDef *def, const char *name, llvm::Value *s, int arg1, int arg2);
llvm::Value *emit_gep(RaviFunctionDef *def, const char *name, llvm::Value *s, int arg1, int arg2, int arg3);
llvm::Value *emit_gep(RaviFunctionDef *def, const char *name, llvm::Value *ptr, llvm::Value *arg1, int arg2,
int arg3);
llvm::Value *emit_gep(RaviFunctionDef *def, const char *name,
llvm::Value *ptr, llvm::Value *arg1, int arg2);
llvm::Value *emit_gep(RaviFunctionDef *def, const char *name, llvm::Value *ptr, llvm::Value *arg1, int arg2);
// emit code for &ptr[offset]
llvm::Value *emit_array_get(RaviFunctionDef *def, llvm::Value *ptr,
int offset);
llvm::Value *emit_array_get(RaviFunctionDef *def, llvm::Value *ptr, int offset);
// emit code to load pointer L->ci->u.l.base
void emit_load_base(RaviFunctionDef *def);
@ -975,73 +1026,57 @@ class RaviCodeGenerator {
// Gets the size of the hash table
// This is the sizenode() macro in lobject.h
llvm::Value *emit_table_get_hashsize(RaviFunctionDef *def,
llvm::Value *table);
llvm::Value *emit_table_get_hashsize(RaviFunctionDef *def, llvm::Value *table);
// Gets the location of the hash node for given string key
// return value is the offset into the node array
llvm::Value *emit_table_get_hashstr(RaviFunctionDef *def, llvm::Value *table,
TString *key);
llvm::Value *emit_table_get_hashstr(RaviFunctionDef *def, llvm::Value *table, TString *key);
// Gets access to the Table's node array (t->node)
llvm::Value *emit_table_get_nodearray(RaviFunctionDef *def,
llvm::Value *table);
llvm::Value *emit_table_get_nodearray(RaviFunctionDef *def, llvm::Value *table);
// Given a pointer to table's node array (node = t->node) and
// the location of the hashed key (index), this method retrieves the
// type of the value stored at the node - return value is of type int
// and is the type information stored in TValue->tt field.
llvm::Value *emit_table_get_keytype(RaviFunctionDef *def, llvm::Value *node,
llvm::Value *index);
llvm::Value *emit_table_get_keytype(RaviFunctionDef *def, llvm::Value *node, llvm::Value *index);
// Given a pointer to table's node array (node = t->node) and
// the location of the hashed key (index), this method retrieves the
// the string value stored at the node - return value is of type TString*
llvm::Value *emit_table_get_strkey(RaviFunctionDef *def, llvm::Value *node,
llvm::Value *index);
llvm::Value *emit_table_get_strkey(RaviFunctionDef *def, llvm::Value *node, llvm::Value *index);
// Given a pointer to table's node array (node = t->node) and
// the location of the hashed key (index), this method retrieves the
// the pointer to value stored at the node - return value is of type TValue*
llvm::Value *emit_table_get_value(RaviFunctionDef *def, llvm::Value *node,
llvm::Value *index);
llvm::Value *emit_table_get_value(RaviFunctionDef *def, llvm::Value *node, llvm::Value *index);
// Gets the size of the table's array part
llvm::Value *emit_table_get_arraysize(RaviFunctionDef *def,
llvm::Value *table);
llvm::Value *emit_table_get_arraysize(RaviFunctionDef *def, llvm::Value *table);
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);
// emit code to load pointer to int array
llvm::Instruction *emit_load_reg_h_intarray(RaviFunctionDef *def,
llvm::Instruction *ra);
llvm::Instruction *emit_load_reg_h_intarray(RaviFunctionDef *def, llvm::Instruction *ra);
// emit code to load pointer to double array
llvm::Instruction *emit_load_reg_h_floatarray(RaviFunctionDef *def,
llvm::Instruction *ra);
llvm::Instruction *emit_load_reg_h_floatarray(RaviFunctionDef *def, llvm::Instruction *ra);
// emit code to store lua_Number value into register
void emit_store_reg_n(RaviFunctionDef *def, llvm::Value *value,
llvm::Value *dest_ptr);
void emit_store_reg_n_withtype(RaviFunctionDef *def, llvm::Value *value,
llvm::Value *dest_ptr);
void emit_store_reg_n(RaviFunctionDef *def, llvm::Value *value, llvm::Value *dest_ptr);
void emit_store_reg_n_withtype(RaviFunctionDef *def, llvm::Value *value, llvm::Value *dest_ptr);
// emit code to store lua_Integer value into register
void emit_store_reg_i(RaviFunctionDef *def, llvm::Value *value,
llvm::Value *dest_ptr);
void emit_store_reg_i_withtype(RaviFunctionDef *def, llvm::Value *value,
llvm::Value *dest_ptr);
void emit_store_reg_i(RaviFunctionDef *def, llvm::Value *value, llvm::Value *dest_ptr);
void emit_store_reg_i_withtype(RaviFunctionDef *def, llvm::Value *value, llvm::Value *dest_ptr);
// emit code to store bool value into register
void emit_store_reg_b(RaviFunctionDef *def, llvm::Value *value,
llvm::Value *dest_ptr);
void emit_store_reg_b_withtype(RaviFunctionDef *def, llvm::Value *value,
llvm::Value *dest_ptr);
void emit_store_reg_b(RaviFunctionDef *def, llvm::Value *value, llvm::Value *dest_ptr);
void emit_store_reg_b_withtype(RaviFunctionDef *def, llvm::Value *value, llvm::Value *dest_ptr);
// emit code to set the type in the register
void emit_store_type_(RaviFunctionDef *def, llvm::Value *value, int type);
@ -1050,12 +1085,10 @@ class RaviCodeGenerator {
llvm::Instruction *emit_load_type(RaviFunctionDef *def, llvm::Value *value);
// emit code to load the array type
llvm::Instruction *emit_load_ravi_arraytype(RaviFunctionDef *def,
llvm::Value *value);
llvm::Instruction *emit_load_ravi_arraytype(RaviFunctionDef *def, llvm::Value *value);
// emit code to load the array length
llvm::Instruction *emit_load_ravi_arraylength(RaviFunctionDef *def,
llvm::Value *value);
llvm::Instruction *emit_load_ravi_arraylength(RaviFunctionDef *def, llvm::Value *value);
// TValue assign
void emit_assign(RaviFunctionDef *def, llvm::Value *ra, llvm::Value *rb);
@ -1064,25 +1097,20 @@ class RaviCodeGenerator {
llvm::Value *emit_gep_upvals(RaviFunctionDef *def, int offset);
// Load the &upvals[offset] -> result is UpVal*
llvm::Instruction *emit_load_pupval(RaviFunctionDef *def,
llvm::Value *ppupval);
llvm::Instruction *emit_load_pupval(RaviFunctionDef *def, llvm::Value *ppupval);
// Get &upval->v
llvm::Value *emit_gep_upval_v(RaviFunctionDef *def,
llvm::Instruction *pupval);
llvm::Value *emit_gep_upval_v(RaviFunctionDef *def, llvm::Instruction *pupval);
// Load upval->v
llvm::Instruction *emit_load_upval_v(RaviFunctionDef *def,
llvm::Instruction *pupval);
llvm::Instruction *emit_load_upval_v(RaviFunctionDef *def, llvm::Instruction *pupval);
// Get &upval->value -> result is TValue *
llvm::Value *emit_gep_upval_value(RaviFunctionDef *def,
llvm::Instruction *pupval);
llvm::Value *emit_gep_upval_value(RaviFunctionDef *def, llvm::Instruction *pupval);
// isnil(reg) || isboolean(reg) && reg.value == 0
// !(isnil(reg) || isboolean(reg) && reg.value == 0)
llvm::Value *emit_boolean_testfalse(RaviFunctionDef *def, llvm::Value *reg,
bool donot);
llvm::Value *emit_boolean_testfalse(RaviFunctionDef *def, llvm::Value *reg, bool donot);
llvm::Instruction *emit_tointeger(RaviFunctionDef *def, llvm::Value *reg);
@ -1099,14 +1127,12 @@ class RaviCodeGenerator {
void debug_printf1(RaviFunctionDef *def, const char *str, llvm::Value *arg1);
void debug_printf2(RaviFunctionDef *def, const char *str, llvm::Value *arg1,
llvm::Value *arg2);
void debug_printf2(RaviFunctionDef *def, const char *str, llvm::Value *arg1, llvm::Value *arg2);
void debug_printf3(RaviFunctionDef *def, const char *str, llvm::Value *arg1,
llvm::Value *arg2, llvm::Value *arg3);
void debug_printf3(RaviFunctionDef *def, const char *str, llvm::Value *arg1, llvm::Value *arg2, llvm::Value *arg3);
void debug_printf4(RaviFunctionDef *def, const char *str, llvm::Value *arg1,
llvm::Value *arg2, llvm::Value *arg3, llvm::Value *arg4);
void debug_printf4(RaviFunctionDef *def, const char *str, llvm::Value *arg1, llvm::Value *arg2, llvm::Value *arg3,
llvm::Value *arg4);
void emit_dump_stack(RaviFunctionDef *def, const char *str);
void emit_dump_stacktop(RaviFunctionDef *def, const char *str);
@ -1139,19 +1165,15 @@ class RaviCodeGenerator {
void emit_LOADBOOL(RaviFunctionDef *def, int A, int B, int C, int j, int pc);
// Code size priority so go via function calls
void emit_ARITH_calls(RaviFunctionDef *def, int A, int B, int C, OpCode op,
TMS tms, int pc);
void emit_ARITH_calls(RaviFunctionDef *def, int A, int B, int C, OpCode op, TMS tms, int pc);
// integer arith priority over floating
void emit_ARITH_intpriority(RaviFunctionDef *def, int A, int B, int C,
OpCode op, TMS tms, int pc);
void emit_ARITH_intpriority(RaviFunctionDef *def, int A, int B, int C, OpCode op, TMS tms, int pc);
// floating arith priority over integer
void emit_ARITH_floatpriority(RaviFunctionDef *def, int A, int B, int C,
OpCode op, TMS tms, int pc);
void emit_ARITH_floatpriority(RaviFunctionDef *def, int A, int B, int C, OpCode op, TMS tms, int pc);
inline void emit_ARITH(RaviFunctionDef *def, int A, int B, int C, OpCode op,
TMS tms, int pc) {
inline void emit_ARITH(RaviFunctionDef *def, int A, int B, int C, OpCode op, TMS tms, int pc) {
#if RAVI_USE_LLVM_ARITH_FLOATPRIORITY
emit_ARITH_floatpriority(def, A, B, C, op, tms, pc);
#else
@ -1207,11 +1229,9 @@ class RaviCodeGenerator {
void emit_JMP(RaviFunctionDef *def, int A, int j, int pc);
void emit_iFORPREP(RaviFunctionDef *def, int A, int sBx, int step_one,
int pc);
void emit_iFORPREP(RaviFunctionDef *def, int A, int sBx, int step_one, int pc);
void emit_iFORLOOP(RaviFunctionDef *def, int A, int sBx, RaviBranchDef &b,
int step_one, int pc);
void emit_iFORLOOP(RaviFunctionDef *def, int A, int sBx, RaviBranchDef &b, int step_one, int pc);
void emit_FORPREP(RaviFunctionDef *def, int A, int sBx, int pc);
@ -1219,8 +1239,7 @@ class RaviCodeGenerator {
void emit_FORPREP2(RaviFunctionDef *def, int A, int sBx, int pc);
void emit_FORLOOP2(RaviFunctionDef *def, int A, int sBx, RaviBranchDef &b,
int pc);
void emit_FORLOOP2(RaviFunctionDef *def, int A, int sBx, RaviBranchDef &b, int pc);
void emit_MOVE(RaviFunctionDef *def, int A, int B, int pc);
@ -1248,36 +1267,29 @@ class RaviCodeGenerator {
void emit_GETTABLE(RaviFunctionDef *def, int A, int B, int C, int pc);
void emit_GETTABLE_S(RaviFunctionDef *def, int A, int B, int C, int pc,
TString *key);
void emit_GETTABLE_S(RaviFunctionDef *def, int A, int B, int C, int pc, TString *key);
void emit_GETFIELD(RaviFunctionDef *def, int A, int B, int C, int pc,
TString *key);
void emit_GETFIELD(RaviFunctionDef *def, int A, int B, int C, int pc, TString *key);
void emit_GETI(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,
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_TABLE_SELF_SK(RaviFunctionDef *def, int A, int B, int C, int pc,
TString *key);
void emit_TABLE_SELF_SK(RaviFunctionDef *def, int A, int B, int C, int pc, TString *key);
void emit_SELF_SK(RaviFunctionDef *def, int A, int B, int C, int pc);
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_common_GETTABLE_S_(RaviFunctionDef *def, int A, llvm::Value *rb,
int C, TString *key);
void emit_common_GETTABLE_S_(RaviFunctionDef *def, int A, llvm::Value *rb, 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);
@ -1304,41 +1316,33 @@ class RaviCodeGenerator {
// A, B, C must be operands of the OP_EQ/OP_LT/OP_LE instructions
// j must be the jump target (offset of the code to which we need to jump to)
// jA must be the A operand of the jump instruction
void emit_EQ(RaviFunctionDef *def, int A, int B, int C, int j, int jA,
llvm::Constant *callee, OpCode opCode, int pc);
void emit_EQ(RaviFunctionDef *def, int A, int B, int C, int j, int jA, llvm::Constant *callee, OpCode opCode, int pc);
// OP_TEST is followed by a OP_JMP instruction - both are handled
// together
// A, B, C must be operands of the OP_TEST instruction
// j must be the jump target (offset of the code to which we need to jump to)
// jA must be the A operand of the jump instruction
void emit_TEST(RaviFunctionDef *def, int A, int B, int C, int j, int jA,
int pc);
void emit_TEST(RaviFunctionDef *def, int A, int B, int C, int j, int jA, int pc);
// OP_TESTSET is followed by a OP_JMP instruction - both are handled
// together
// A, B, C must be operands of the OP_TESTSET instruction
// j must be the jump target (offset of the code to which we need to jump to)
// jA must be the A operand of the jump instruction
void emit_TESTSET(RaviFunctionDef *def, int A, int B, int C, int j, int jA,
int pc);
void emit_TESTSET(RaviFunctionDef *def, int A, int B, int C, int j, int jA, int pc);
void emit_TFORCALL(RaviFunctionDef *def, int A, int B, int C, int j, int jA,
int pc);
void emit_TFORCALL(RaviFunctionDef *def, int A, int B, int C, int j, int jA, int pc);
void emit_TFORLOOP(RaviFunctionDef *def, int A, int j, int pc);
void emit_FARRAY_GET(RaviFunctionDef *def, int A, int B, int C,
bool omitArrayGetRangeCheck, int pc);
void emit_FARRAY_GET(RaviFunctionDef *def, int A, int B, int C, bool omitArrayGetRangeCheck, int pc);
void emit_IARRAY_GET(RaviFunctionDef *def, int A, int B, int C,
bool omitArrayGetRangeCheck, int pc);
void emit_IARRAY_GET(RaviFunctionDef *def, int A, int B, int C, bool omitArrayGetRangeCheck, int pc);
void emit_FARRAY_SET(RaviFunctionDef *def, int A, int B, int C,
bool known_int, int pc);
void emit_FARRAY_SET(RaviFunctionDef *def, int A, int B, int C, bool known_int, int pc);
void emit_IARRAY_SET(RaviFunctionDef *def, int A, int B, int C,
bool known_float, int pc);
void emit_IARRAY_SET(RaviFunctionDef *def, int A, int B, int C, bool known_float, int pc);
void emit_MOVEIARRAY(RaviFunctionDef *def, int A, int B, int pc);
@ -1346,24 +1350,19 @@ class RaviCodeGenerator {
void emit_MOVETAB(RaviFunctionDef *def, int A, int B, int pc);
void emit_TOARRAY(RaviFunctionDef *def, int A, int array_type_expected,
const char *errmsg, int pc);
void emit_TOARRAY(RaviFunctionDef *def, int A, int array_type_expected, const char *errmsg, int pc);
void emit_BITWISE_BINARY_OP(RaviFunctionDef *def, OpCode op, int A, int B,
int C, int pc);
void emit_BITWISE_BINARY_OP(RaviFunctionDef *def, OpCode op, int A, int B, int C, int pc);
void emit_BITWISE_SHIFT_OP(RaviFunctionDef *def, OpCode op, int A, int B,
int C, int pc);
void emit_BITWISE_SHIFT_OP(RaviFunctionDef *def, OpCode op, int A, int B, int C, int pc);
void emit_BNOT_I(RaviFunctionDef *def, int A, int B, int pc);
void emit_BOR_BXOR_BAND(RaviFunctionDef *def, OpCode op, int A, int B, int C,
int pc);
void emit_BOR_BXOR_BAND(RaviFunctionDef *def, OpCode op, int A, int B, int C, int pc);
void emit_BNOT(RaviFunctionDef *def, int A, int B, int pc);
void emit_bitwise_shiftl(RaviFunctionDef *def, llvm::Value *ra, int B,
lua_Integer y);
void emit_bitwise_shiftl(RaviFunctionDef *def, llvm::Value *ra, int B, lua_Integer y);
private:
RaviJITState *jitState_;

@ -90,7 +90,7 @@ end
function()
return
--[binary expr start]
--[unary expr start]
--[unary expr start] any
-
0
--[unary expr end]
@ -107,7 +107,7 @@ function()
--[binary expr start]
3
^
--[unary expr start]
--[unary expr start] any
-
1
--[unary expr end]
@ -145,7 +145,7 @@ function()
return
--[binary expr start]
--[primary start]
--[unary expr start]
--[unary expr start] any
-
2
--[unary expr end]
@ -169,7 +169,7 @@ function()
--[binary expr start]
--[primary start]
--[binary expr start]
--[unary expr start]
--[unary expr start] any
-
--[binary expr start]
3
@ -192,7 +192,7 @@ end
function()
return
--[binary expr start]
--[unary expr start]
--[unary expr start] any
-
3
--[unary expr end]
@ -209,7 +209,7 @@ function()
--[binary expr start]
--[binary expr start]
--[binary expr start]
--[unary expr start]
--[unary expr start] any
-
--[primary start]
--[binary expr start]
@ -221,10 +221,10 @@ function()
8
--[binary expr end]
+
--[unary expr start]
--[unary expr start] any
-
--[primary start]
--[unary expr start]
--[unary expr start] any
-
1
--[unary expr end]
@ -256,7 +256,7 @@ function()
--[binary expr start]
--[binary expr start]
--[binary expr start]
--[unary expr start]
--[unary expr start] any
-
--[primary start]
--[binary expr start]
@ -268,10 +268,10 @@ function()
8
--[binary expr end]
+
--[unary expr start]
--[unary expr start] any
-
--[primary start]
--[unary expr start]
--[unary expr start] any
-
1
--[unary expr end]
@ -320,11 +320,11 @@ end
]]
function()
return
--[unary expr start]
--[unary expr start] any
~
--[primary start]
--[binary expr start]
--[unary expr start]
--[unary expr start] any
~
4080
--[unary expr end]
@ -340,11 +340,11 @@ end
]]
function()
return
--[unary expr start]
--[unary expr start] any
~
--[unary expr start]
--[unary expr start] any
~
--[unary expr start]
--[unary expr start] number
-
100024.0000000000000000
--[unary expr end]
@ -368,7 +368,7 @@ function()
--[binary expr end]
--[primary end]
<<
--[unary expr start]
--[unary expr start] any
-
4
--[unary expr end]
@ -449,7 +449,7 @@ function()
--[binary expr start]
2.0000000000000000
^
--[unary expr start]
--[unary expr start] any
-
2
--[unary expr end]
@ -463,14 +463,14 @@ function()
--[binary expr end]
and
--[binary expr start]
--[unary expr start]
--[unary expr start] any
-
--[binary expr start]
2
^
--[unary expr start]
--[unary expr start] any
-
--[unary expr start]
--[unary expr start] any
-
2
--[unary expr end]
@ -478,11 +478,11 @@ function()
--[binary expr end]
--[unary expr end]
==
--[unary expr start]
--[unary expr start] any
-
--[unary expr start]
--[unary expr start] any
-
--[unary expr start]
--[unary expr start] any
-
4
--[unary expr end]
@ -499,7 +499,7 @@ function()
return
--[binary expr start]
--[binary expr start]
--[unary expr start]
--[unary expr start] any
not
nil
--[unary expr end]
@ -507,7 +507,7 @@ function()
2
--[binary expr end]
and
--[unary expr start]
--[unary expr start] any
not
--[primary start]
--[binary expr start]
@ -536,7 +536,7 @@ function()
--[binary expr start]
--[binary expr start]
--[binary expr start]
--[unary expr start]
--[unary expr start] any
-
3
--[unary expr end]
@ -567,7 +567,7 @@ function()
--[binary expr start]
--[binary expr start]
--[binary expr start]
--[unary expr start]
--[unary expr start] any
-
--[binary expr start]
2
@ -576,7 +576,7 @@ function()
--[binary expr end]
--[unary expr end]
==
--[unary expr start]
--[unary expr start] any
-
4
--[unary expr end]
@ -585,7 +585,7 @@ function()
--[binary expr start]
--[binary expr start]
--[primary start]
--[unary expr start]
--[unary expr start] any
-
2
--[unary expr end]
@ -626,7 +626,7 @@ function()
--[binary expr start]
--[binary expr start]
--[binary expr start]
--[unary expr start]
--[unary expr start] any
-
3
--[unary expr end]
@ -639,7 +639,7 @@ function()
and
--[binary expr start]
--[binary expr start]
--[unary expr start]
--[unary expr start] any
-
3
--[unary expr end]
@ -702,7 +702,7 @@ end
function()
return
--[binary expr start]
--[unary expr start]
--[unary expr start] any
not
--[primary start]
--[binary expr start]
@ -897,7 +897,7 @@ function()
--[binary expr start]
--[binary expr start]
--[binary expr start]
--[unary expr start]
--[unary expr start] any
-
3
--[unary expr end]
@ -939,7 +939,7 @@ function()
--[binary expr start]
--[binary expr start]
--[primary start]
--[unary expr start]
--[unary expr start] any
-
3
--[unary expr end]
@ -1000,7 +1000,7 @@ end
]]
function()
return
--[unary expr start]
--[unary expr start] any
not
--[primary start]
--[binary expr start]
@ -1101,7 +1101,7 @@ function()
return
--[binary expr start]
--[binary expr start]
--[unary expr start]
--[unary expr start] any
-
--[primary start]
--[binary expr start]
@ -1112,7 +1112,7 @@ function()
--[primary end]
--[unary expr end]
==
--[unary expr start]
--[unary expr start] any
-
1
--[unary expr end]
@ -1130,12 +1130,12 @@ function()
+
--[primary start]
--[binary expr start]
--[unary expr start]
--[unary expr start] any
-
1.2500000000000000
--[unary expr end]
or
--[unary expr start]
--[unary expr start] any
-
4
--[unary expr end]
@ -1311,6 +1311,7 @@ function()
x --global symbol ?
=
function()
--locals i
for
i --local symbol ?
=
@ -1339,3 +1340,126 @@ function()
end
--
--[[function x() local a=1; function y() return function() return a end end; end
]]
function()
x --global symbol ?
=
function()
--locals a
local
--[symbols]
a --local symbol ?
--[expressions]
1
y --global symbol ?
=
function()
--upvalues a
return
function()
--upvalues a
return
--[primary start]
a --upvalue ?
--[primary end]
end
end
end
end
--
--[[return @integer 1
]]
function()
return
--[unary expr start] integer
@integer
1
--[unary expr end]
end
--
--[[return @string "hello"
]]
function()
return
--[unary expr start] string
@string
'hello'
--[unary expr end]
end
--
--[[return @table {}
]]
function()
return
--[unary expr start] table
@table
{ --[table constructor start] table
} --[table constructor end]
--[unary expr end]
end
--
--[[return @integer[] {}
]]
function()
return
--[unary expr start] integer[]
@integer[]
{ --[table constructor start] integer[]
} --[table constructor end]
--[unary expr end]
end
--
--[[return @number[] {}
]]
function()
return
--[unary expr start] number[]
@number[]
{ --[table constructor start] number[]
} --[table constructor end]
--[unary expr end]
end
--
--[[return @closure function() end
]]
function()
return
--[unary expr start] closure
@closure
function()
end
--[unary expr end]
end
--
--[[return @number 54.4
]]
function()
return
--[unary expr start] number
@number
54.3999999999999986
--[unary expr end]
end
--
--[[return @User.Type a
]]
function()
return
--[unary expr start] User.Type
@<usertype>
--[primary start]
a --global symbol ?
--[primary end]
--[unary expr end]
end
--

@ -67,4 +67,15 @@ dotest 'return ((2<3) or 1) == true and (2<3 and 4) == 4'
dotest 'return (x>y) and x or y == 2'
dotest 'return (x>y) and x or y == 2'
dotest 'function x() for i = 1, 10 do; print(i); end end'
dotest 'function x() for i = 1, 10 do; print(i); end end'
dotest 'function x() local a=1; function y() return function() return a end end; end'
dotest 'return @integer 1'
dotest 'return @string "hello"'
dotest 'return @table {}'
dotest 'return @integer[] {}'
dotest 'return @number[] {}'
dotest 'return @closure function() end'
dotest 'return @number 54.4'
dotest 'return @User.Type a'

@ -0,0 +1,313 @@
function()
return
function()
--locals a, y, a, z
local
--[symbols]
a --local symbol ?
--[expressions]
1
local
--[symbols]
y --local symbol function
--[expressions]
function()
--upvalues a
return
function()
--upvalues a
return
--[primary start]
a --upvalue ?
--[primary end]
end
end
local
--[symbols]
a --local symbol ?
--[expressions]
5
local
--[symbols]
z --local symbol function
--[expressions]
function()
--upvalues a
return
function()
--upvalues a
return
--[primary start]
a --upvalue ?
--[primary end]
end
end
return
--[primary start]
y --local symbol function
--[primary end]
,
--[primary start]
z --local symbol function
--[primary end]
end
end
function()
return
function(
a --local symbol ?
,
b --local symbol ?
,
c --local symbol ?
,
d --local symbol ?
,
e --local symbol ?
)
--locals a, b, c, d, e
if
--[binary expr start]
--[primary start]
a --local symbol ?
--[primary end]
==
--[primary start]
b --local symbol ?
--[primary end]
--[binary expr end]
then
goto l1
elseif
--[binary expr start]
--[primary start]
a --local symbol ?
--[primary end]
==
--[primary start]
c --local symbol ?
--[primary end]
--[binary expr end]
then
goto l2
elseif
--[binary expr start]
--[primary start]
a --local symbol ?
--[primary end]
==
--[primary start]
d --local symbol ?
--[primary end]
--[binary expr end]
then
goto l2
else
if
--[binary expr start]
--[primary start]
a --local symbol ?
--[primary end]
==
--[primary start]
e --local symbol ?
--[primary end]
--[binary expr end]
then
goto l3
else
goto l3
end
end
::l1::
::l2::
::l3::
::l4::
end
end
function()
return
function(
a --local symbol ?
)
--locals a
while
--[binary expr start]
--[primary start]
a --local symbol ?
--[primary end]
<
10
--[binary expr end]
do
--[expression statement start]
--[var list start]
--[primary start]
a --local symbol ?
--[primary end]
= --[var list end]
--[expression list start]
--[binary expr start]
--[primary start]
a --local symbol ?
--[primary end]
+
1
--[binary expr end]
--[expression list end]
--[expression statement end]
end
end
end
function()
return
function(
a --local symbol ?
)
--locals a
::L2::
if
--[unary expr start] any
not
--[primary start]
--[binary expr start]
--[primary start]
a --local symbol ?
--[primary end]
<
10
--[binary expr end]
--[primary end]
--[unary expr end]
then
goto L1
end
--[expression statement start]
--[var list start]
--[primary start]
a --local symbol ?
--[primary end]
= --[var list end]
--[expression list start]
--[binary expr start]
--[primary start]
a --local symbol ?
--[primary end]
+
1
--[binary expr end]
--[expression list end]
--[expression statement end]
goto L2
::L1::
end
end
function()
return
function()
--[expression statement start]
--[expression list start]
--[primary start]
function()
end
--[primary end]
--[suffix list start]
--[function call start]
(
{ --[table constructor start] table
--[indexed assign start]
--[value start]
--[primary start]
f --global symbol ?
--[primary end]
--[suffix list start]
--[function call start]
(
)
--[function call end]
--[suffix list end]
--[value end]
--[indexed assign end]
} --[table constructor end]
)
--[function call end]
--[suffix list end]
--[expression list end]
--[expression statement end]
end
end
function()
return
function()
--locals sum, j, k
local
--[symbols]
sum --local symbol ?
for
j --local symbol ?
=
1
,
500
do
--[expression statement start]
--[var list start]
--[primary start]
sum --local symbol ?
--[primary end]
= --[var list end]
--[expression list start]
0.0000000000000000
--[expression list end]
--[expression statement end]
for
k --local symbol ?
=
1
,
10000
do
--[expression statement start]
--[var list start]
--[primary start]
sum --local symbol ?
--[primary end]
= --[var list end]
--[expression list start]
--[binary expr start]
--[primary start]
sum --local symbol ?
--[primary end]
+
--[binary expr start]
1.0000000000000000
/
--[primary start]
--[binary expr start]
--[primary start]
k --local symbol ?
--[primary end]
*
--[primary start]
k --local symbol ?
--[primary end]
--[binary expr end]
--[primary end]
--[binary expr end]
--[binary expr end]
--[expression list end]
--[expression statement end]
end
end
return
--[primary start]
sum --local symbol ?
--[primary end]
end
end

@ -0,0 +1,76 @@
local function doast(str)
local x, msg = ast.parse(str)
if not x then error(msg) end
print(x:tostring())
end
local str =
[[return function()
local a = 1
local function y()
return function()
return a
end
end
local a = 5
local function z()
return function()
return a
end
end
return y, z
end
]]
doast(str)
str =
[[return function (a, b, c, d, e)
if a == b then goto l1
elseif a == c then goto l2
elseif a == d then goto l2
else if a == e then goto l3
else goto l3
end
end
::l1:: ::l2:: ::l3:: ::l4::
end
]]
doast(str)
str =
[[return function (a) while a < 10 do a = a + 1 end end
]]
doast(str)
-- Note that the while loop above is supposed to ultimately
-- generate same code as below
str=
[[return function (a) ::L2:: if not(a < 10) then goto L1 end; a = a + 1;
goto L2; ::L1:: end
]]
doast(str)
str=
[[return function ()
(function () end){f()}
end
]]
doast(str)
str=
[[return function ()
local sum
for j = 1,500 do
sum = 0.0
for k = 1,10000 do
sum = sum + 1.0/(k*k)
end
end
return sum
end
]]
doast(str)

@ -0,0 +1,37 @@
-- Copyright vnmakarov see https://github.com/vnmakarov/mir/issues/2
local function sieve()
local i: integer, k: integer, prime: integer, count: integer
local flags: integer[] = table.intarray(8190)
for iter=0,100000 do
count = 0
for i=0,8190 do
flags[i] = 1
end
for i=0,8190 do
if flags[i] == 1 then
prime = i + i + 3;
for k = i + prime, 8190, prime do
flags[k] = 0
end
count = count + 1
end
end
end
return count
end
if ravi.jit() then
print('JIT ON')
ravi.optlevel(2)
ravi.compile(sieve, {omitArrayGetRangeCheck=1})
end
-- ravi.dumplua(sieve)
-- ravi.dumpir(sieve)
local t1 = os.clock()
local count = sieve()
local t2 = os.clock()
print("time taken ", t2-t1)
print(count)
assert(count == 1899)

@ -0,0 +1,29 @@
-- Copyright vnmakarov see https://github.com/vnmakarov/mir/issues/2
local function sieve()
local i, k, prime, count
local flags = {}
for iter=0,100000 do
count = 0
for i=0,8190 do
flags[i] = 1
end
for i=0,8190 do
if flags[i] == 1 then
prime = i + i + 3;
for k = i + prime, 8190, prime do
flags[k] = 0
end
count = count + 1
end
end
end
return count
end
local t1 = os.clock()
local count = sieve()
local t2 = os.clock()
print("time taken ", t2-t1)
print(count)
assert(count == 1899)

@ -11,6 +11,7 @@ Key Features of Lua
* Lua versions matter
* Lua is dynamically typed like Python
* By default variables in Lua are global unless declared local
* Lua has no line terminators
* There is a single complex / aggregate type called a 'table', which combines hash table/map and array features
* Functions in Lua are values stored in variables; in particular functions do not have names
* Globals in Lua are just values stored in a special Lua table
@ -83,6 +84,19 @@ There are some exceptions to the rule:
* the iterator variables declared in a ``for`` loop are implicitly local.
* function parameters are local to the function
Lua has no line terminators
===========================
Strictly speaking you can terminate Lua statements using ``;``. However it is not necessary except in some cases to avoid ambiguity.
This design has some consequences that took me by surprise::
local x y = 5
Above creates a local variable ``x`` and sets a global ``y`` to ``5``. Because it actually parses as::
local x
y = 5
The 'table' type
================
Lua's only complex / aggregate data type is a table. Tables are used for many things in Lua, even internally within Lua.

@ -101,7 +101,7 @@ represented by 2*max), which is half the maximum for the corresponding
unsigned argument.
Note that B and C operands need to have an extra bit compared to A.
This is because B and A can reference registers or constants, and the
This is because B and C can reference registers or constants, and the
extra bit is used to decide which one. But A always references registers
so it doesn't need the extra bit.

@ -15,7 +15,7 @@ For building Ravi with JIT options please read on.
Build Dependencies
==================
* `CMake <https://cmake.org/>`_ is required for more advanced builds
* `CMake <https://cmake.org/>`_ is required
* On Windows you will need Visual Studio 2017 Community edition
* LLVM versions >= 3.5
@ -23,7 +23,8 @@ LLVM JIT Backend
================
Following versions of LLVM work with Ravi.
* LLVM 3.7, 3.8, 3.9, 4.0, 5.0, 6.0
* LLVM 3.7, 3.8, 3.9, 4.0, 5.0, 6.0, 8.0.1
* LLVM 7.0 was skipped because of unstable ORC api changes
* LLVM 3.5 and 3.6 should also work but have not been recently tested
Unless otherwise noted the instructions below should work for LLVM 3.9 and later.
@ -31,56 +32,54 @@ Unless otherwise noted the instructions below should work for LLVM 3.9 and later
Since LLVM 5.0 Ravi has begun to use the new ORC JIT apis. These apis are more memory efficient
compared to the MCJIT apis because they release the Module IR as early as possible, whereas with
MCJIT the Module IR hangs around as long as the compiled code is held. Because of this significant
improvement, I recommend using LLVM 5.0 and above.
improvement, I recommend using the latest version of LLVM.
Building LLVM on Windows
------------------------
I built LLVM from source. I used the following sequence from the VS2017 command window::
cd \github\llvm
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=c:\LLVM -DLLVM_TARGETS_TO_BUILD="X86" -G "Visual Studio 15 2017 Win64" ..
cmake -DCMAKE_INSTALL_PREFIX=c:\Software\llvm801 -DLLVM_TARGETS_TO_BUILD="X86" -G "Visual Studio 15 2017 Win64" ..
I then opened the generated solution in VS2017 and performed a INSTALL build from there. Above will build the 64-bit version of LLVM libraries. To build a 32-bit version omit the ``Win64`` parameter.
.. note:: Note that if you perform a Release build of LLVM then you will also need to do a Release build of Ravi otherwise you will get link errors.
.. note:: Note that if you perform a **Release** build of LLVM then you will also need to do a **Release** build of Ravi otherwise you will get link errors. Ditto for **Debug** builds.
Building LLVM on Ubuntu
-----------------------
On Ubuntu I found that the official LLVM distributions don't work with CMake. The CMake config files appear to be broken.
So I ended up downloading and building LLVM from source and that worked. The approach is similar to that described for MAC OS X below.
Building LLVM on Ubuntu or Redhat
---------------------------------
The approach is similar to that described for MAC OS X below.
Building LLVM on MAC OS X
-------------------------
I am using Max OSX El Capitan. Pre-requisites are XCode 7.x and CMake.
I am using Max OSX Mojave. Pre-requisites are XCode and CMake.
Ensure cmake is on the path.
Assuming that LLVM source has been extracted to ``$HOME/llvm-3.7.0.src`` I follow these steps::
Assuming that LLVM source has been extracted to ``$HOME/llvm-8.0.1.src`` I follow these steps::
cd llvm-3.7.0.src
cd $HOME/llvm-8.0.1.src
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$HOME/LLVM -DLLVM_TARGETS_TO_BUILD="X86" ..
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$HOME/Software//llvm801 -DLLVM_TARGETS_TO_BUILD="X86" ..
make install
Building Ravi with LLVM JIT backend enabled
-------------------------------------------
I am developing Ravi using Visual Studio 2017 Community Edition on Windows 10 64bit, gcc on Unbuntu 64-bit, and clang/Xcode on MAC OS X. I was also able to successfully build a Ubuntu version on Windows 10 using the newly released Ubuntu/Linux sub-system for Windows 10.
I am developing Ravi using Visual Studio 2017 Community Edition on Windows 10 64bit, gcc on Linux 64-bit, and clang/Xcode on MAC OS X. I was also able to successfully build a Ubuntu version on Windows 10 using the newly released Ubuntu/Linux sub-system for Windows 10.
.. note:: Location of cmake files prior to LLVM 3.9 was ``$LLVM_INSTALL_DIR/share/llvm/cmake``.
Assuming that LLVM has been installed as described above, then on Windows I invoke the cmake config as follows::
cd build
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=c:\ravi -DLLVM_DIR=c:\LLVM\lib\cmake\llvm -G "Visual Studio 15 2017 Win64" ..
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=c:\Software\ravi -DLLVM_DIR=c:\Software\llvm801\lib\cmake\llvm -G "Visual Studio 15 2017 Win64" ..
I then open the solution in VS2017 and do a build from there.
On Ubuntu I use::
cd build
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM/lib/cmake/llvm -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" ..
make
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/Software/ravi -DLLVM_DIR=$HOME/Software/llvm801/lib/cmake/llvm -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" ..
make install
Note that on a clean install of Ubuntu 15.10 I had to install following packages:
@ -91,13 +90,13 @@ Note that on a clean install of Ubuntu 15.10 I had to install following packages
On MAC OS X I use::
cd build
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM/lib/cmake/llvm -DCMAKE_BUILD_TYPE=Release -G "Xcode" ..
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/Software/ravi -DLLVM_DIR=$HOME/Software/llvm801/lib/cmake/llvm -DCMAKE_BUILD_TYPE=Release ..
make install
I open the generated project in Xcode and do a build from there. You can also use the command line build tools if you wish - generate the make files in the same way as for Linux.
Building without JIT
====================
You can omit ``-DLLVM_JIT=ON`` and ``OMR_JIT=ON`` options to build Ravi with a null JIT implementation.
You can omit ``-DLLVM_JIT=ON`` options to build Ravi with a null JIT implementation.
Building Static Libraries
=========================

@ -14,22 +14,22 @@ There will be several phases:
temporaries and locals in separate ranges.
4. Next phase will be linearize the instructions - during this phase the loops, if statements etc will get translated to equivalent of
conditional and unconditional jumps.
5. We could at this stage generate byte code and finish. Initially maybe we will stop here.
5. In the first phase we will stop here, generate byte code and finish.
6. The next phase will be translate into basic blocks.
7. Following that we will construct a CFG, perform dominator analysis and convert to SSA form.
8. Hopefully as a result of above we can do some simple optimizations and then emit the bytecode at the end.
Some other things
-----------------
1. locals that are used as up-values or passed or overwritten by function calls should be marked as having 'escaped'.
1. Locals that are used as up-values or passed or overwritten by function calls should be marked as having 'escaped'.
Having this knowledge will enable backend JIT to use the stack for values that cannot escape.
2. during code generation it will be good to know which registers are type constant - i.e. their types do not change. register allocation
2. During code generation it will be good to know which registers are type constant - i.e. their types do not change. register allocation
should be designed / implemented so that we try to avoid over-writing type data where possible. This will allow backend JIT
to generate more optimized code.
Current Status
--------------
We have a parser implementation that can convert Ravi source to an abstract syntax tree (AST).
Static type checking is not yet implemented.
We have a parser implementation that can convert Ravi source to an abstract syntax tree (AST). Static type checking is being worked on. Progress is very slow but things are moving every now and then when I get time.
For examples of how to call the parser please see `ravi-tests/ravi_test_ast.lua <https://github.com/dibyendumajumdar/ravi/blob/master/ravi-tests/ravi_test_ast.lua>`_.
For examples of how to call the parser please see `ravi-tests/ravi_test_ast.lua <https://github.com/dibyendumajumdar/ravi/blob/master/ravi-tests/ravi_test_ast.lua>`_ and `ravi-tests\ravi_test_ast2.lua <https://github.com/dibyendumajumdar/ravi/blob/master/ravi-tests/ravi_test_ast2.lua>`_. If you run these scripts the parse AST will be dumped to stdout.

@ -34,7 +34,7 @@ Features
* `LLVM <http://www.llvm.org/>`_ powered JIT compiler
* `Eclipse OMR <https://github.com/dibyendumajumdar/nj>`_ powered JIT compiler
* Built-in C pre-processor, parser and JIT compiler
* A `distribution with batteries <https://github.com/dibyendumajumdar/ravi-distro>`_.
* A `distribution with batteries <https://github.com/dibyendumajumdar/Suravi>`_.
Documentation
=============
@ -90,7 +90,10 @@ History
- Additional type-annotations
* 2018
- Implemented Eclipse OMR JIT backend
- Created `Ravi with batteries <https://github.com/dibyendumajumdar/ravi-distro>`_.
- Created `Ravi with batteries <https://github.com/dibyendumajumdar/Suravi>`_.
* 2019 (Plan)
- New parser, type checker and code generator
- Release Ravi 1.0
License
=======

@ -7,7 +7,7 @@
PLAT= none
#CC= gcc -std=gnu99
CFLAGS= -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_COMPAT_5_1 $(SYSCFLAGS) $(MYCFLAGS) -I../include -I../dmr_c/src -I../dmr_c/null-backend
CFLAGS= -O2 -Wall -Wextra -DNDEBUG -fomit-frame-pointer -DLUA_COMPAT_5_2 -DLUA_COMPAT_5_1 $(SYSCFLAGS) $(MYCFLAGS) -I../include -I../dmr_c/src -I../dmr_c/null-backend
CXXFLAGS=$(CFLAGS) -fno-rtti -Wno-sign-compare -std=c++14 -fno-exceptions -I../include
LDFLAGS= $(SYSLDFLAGS) $(MYLDFLAGS)
LIBS= -lm $(SYSLIBS) $(MYLIBS)

@ -851,28 +851,24 @@ LUA_API int ravi_is_integer_array(lua_State *L, int idx) {
/* Get the raw data associated with the number array at idx.
* Note that Ravi arrays have an extra element at offset 0 - this
* function returns a pointer to &data[0] - bear in mind that
* function returns a pointer to &data[0]
*/
LUA_API lua_Number* ravi_get_number_array_rawdata(lua_State *L, int idx, size_t *len) {
LUA_API void ravi_get_number_array_rawdata(lua_State *L, int idx, Ravi_NumberArray *data) {
StkId o = index2addr(L, idx);
lua_assert(ttisfarray(o));
lua_Number *startp, *endp;
raviH_get_number_array_rawdata(L, hvalue(o), &startp, &endp);
*len = (endp - startp);
return startp;
if (!ttisfarray(o))
luaG_runerror(L, "number[] required");
raviH_get_number_array_rawdata(L, hvalue(o), data);
}
/* Get the raw data associated with the number array at idx.
* Note that Ravi arrays have an extra element at offset 0 - this
* function returns a pointer to &data[0] - bear in mind that
*/
LUA_API lua_Integer* ravi_get_integer_array_rawdata(lua_State *L, int idx, size_t *len) {
* Note that Ravi arrays have an extra element at offset 0 - this
* function returns a pointer to &data[0]
*/
LUA_API void ravi_get_integer_array_rawdata(lua_State *L, int idx, Ravi_IntegerArray *data) {
StkId o = index2addr(L, idx);
lua_assert(ttisiarray(o));
lua_Integer *startp, *endp;
raviH_get_integer_array_rawdata(L, hvalue(o), &startp, &endp);
*len = (endp - startp);
return startp;
if (!ttisiarray(o))
luaG_runerror(L, "integer[] required");
raviH_get_integer_array_rawdata(L, hvalue(o), data);
}
/* Create a slice of an existing array

@ -517,7 +517,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults, int op_call) {
case RAVI_TFCF: {
int nargs = L->top - func - 1;
int tt = rttype(func);
int sig = tt >> 8; /* Extract the function signature*/
int sig = getfcf_tag(tt); /* Extract the function signature */
switch (sig) {
case RAVI_TFCF_LOG:
case RAVI_TFCF_EXP:
@ -538,7 +538,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults, int op_call) {
case RAVI_TFCF_LOG: v = log(arg); break;
default: {
double(*f)(double) = fcfvalue(func);
double v = f(arg);
v = f(arg);
break;
}
}
@ -579,7 +579,9 @@ static void stackerror (lua_State *L) {
}
#ifdef RAVI_USE_ASMVM
/* following is a temporary solution to decide whether we can use ASM VM */
/* following is a temporary solution to decide whether we can use ASM VM.
The symbol ravi_luaV_interp() is generated by the VMBuilder component.
*/
extern int ravi_luaV_interp(lua_State * L);
int asvm_compatible(Proto *p) {
static unsigned char opcodes_supported[NUM_OPCODES] = {

@ -598,7 +598,8 @@ const TValue *luaH_getint (Table *t, lua_Integer key) {
}
}
#if !defined(RAVI_ENABLED)
#if !RAVI_USE_INLINE_SHORTSTR_TGET
/* RAVI Change - we have split this into two parts - an inline part and a continue part */
/*
** search function for short strings
*/
@ -617,6 +618,19 @@ const TValue *luaH_getshortstr (Table *t, TString *key) {
}
}
}
#else
/* Continue search from n */
const TValue *luaH_getshortstr_continue(Table *t, TString *key, Node *n) {
for (;;) { /* check whether 'key' is somewhere in the chain starting from next node after n */
int nx = gnext(n);
if (nx == 0)
return luaO_nilobject; /* not found */
n += nx;
const TValue *k = gkey(n);
if (ttisshrstring(k) && eqshrstr(tsvalue(k), key))
return gval(n); /* that's it */
}
}
#endif
/*
@ -877,20 +891,18 @@ Table *raviH_new_number_array(lua_State *L, unsigned int len,
return t;
}
void raviH_get_number_array_rawdata(lua_State *L, Table *t, lua_Number **startp, lua_Number **endp) {
void raviH_get_number_array_rawdata(lua_State *L, Table *t, Ravi_NumberArray *data) {
(void)L;
lua_assert(t->ravi_array.array_type == RAVI_TARRAYFLT);
lua_Number *data = (lua_Number *)t->ravi_array.data;
*startp = data;
*endp = data + t->ravi_array.len;
data->data = (lua_Number *)t->ravi_array.data;
data->length = t->ravi_array.len;
}
void raviH_get_integer_array_rawdata(lua_State *L, Table *t, lua_Integer **startp, lua_Integer **endp) {
void raviH_get_integer_array_rawdata(lua_State *L, Table *t, Ravi_IntegerArray *data) {
(void)L;
lua_assert(t->ravi_array.array_type == RAVI_TARRAYINT);
lua_Integer *data = (lua_Integer *)t->ravi_array.data;
*startp = data;
*endp = data + t->ravi_array.len;
data->data = (lua_Integer *)t->ravi_array.data;
data->length = t->ravi_array.len;
}
static const char *key_orig_table = "Originaltable";

@ -47,7 +47,7 @@
#ifdef USE_LLVM
#define ravi_xstringify(s) ravi_stringify(s)
#define ravi_stringify(s) #s
#define RAVI_OPTION_STRING3 " LLVM-" LLVM_VERSION_STRING " ORC=" ravi_xstringify(USE_ORC_JIT)
#define RAVI_OPTION_STRING3 " LLVM-" LLVM_VERSION_STRING " ORC=" ravi_xstringify(USE_ORC_JIT) " v2=" ravi_xstringify(USE_ORCv2_JIT)
#elif USE_OMRJIT
#define RAVI_OPTION_STRING3 " omrjit"
#else

@ -1605,10 +1605,10 @@ int luaV_execute (lua_State *L) {
vmcase(OP_EQ) {
TValue *rb = RKB(i);
TValue *rc = RKC(i);
int res;
int res;
Protect(
res = luaV_equalobj(L, rb, rc);
)
res = luaV_equalobj(L, rb, rc);
)
if (res != GETARG_A(i))
pc++;
else
@ -1856,7 +1856,7 @@ int luaV_execute (lua_State *L) {
}
h = hvalue(ra);
last = ((c-1)*LFIELDS_PER_FLUSH) + n;
savepc(L); /* in case of allocation errors */
savepc(L); /* in case of allocation errors */
if (h->ravi_array.array_type == RAVI_TTABLE) {
if (last > h->sizearray) /* needs more space? */
luaH_resizearray(L, h, last); /* pre-allocate it at once */

File diff suppressed because it is too large Load Diff

@ -1611,6 +1611,31 @@ static void emit_op_iforprep(struct function *fn, int A, int pc, int step_one, i
membuff_add_fstring(&fn->body, "goto Lbc_%d;\n", pc);
}
static void emit_op_forprep_int(struct function *fn, int A, int pc, int pc1) {
(void)pc1;
if (!fn->locals[A]) {
fn->locals[A] = 1; // Lua can reuse the same forloop vars if loop isn't nested
membuff_add_fstring(&fn->prologue, "lua_Integer i_%d = 0;\n", A);
membuff_add_fstring(&fn->prologue, "lua_Integer limit_%d = 0;\n", A);
membuff_add_fstring(&fn->prologue, "lua_Integer step_%d = 0;\n", A);
}
emit_reg(fn, "ra", A); // init
membuff_add_string(&fn->body, "rb = ra+1; /*limit*/\n");
membuff_add_string(&fn->body, "rc = ra+2; /*step*/\n");
membuff_add_fstring(
&fn->body, "if (ttisinteger(ra) && ttisinteger(rc) && ttisinteger(rb)) {\n", A);
membuff_add_fstring(&fn->body, " limit_%d = ivalue(rb);\n", A);
membuff_add_fstring(&fn->body, " i_%d = ivalue(ra);\n", A);
membuff_add_fstring(&fn->body, " step_%d = ivalue(rc);\n", A);
membuff_add_fstring(&fn->body, " i_%d -= step_%d;\n", A, A);
membuff_add_fstring(&fn->body, " goto Lbc_%d;\n", pc);
membuff_add_string(&fn->body, "}\n");
membuff_add_string(&fn->body, "else {\n");
membuff_add_fstring(&fn->body, " error_code = %d;\n", Error_for_limit_must_be_number);
membuff_add_string(&fn->body, " goto Lraise_error;\n");
membuff_add_string(&fn->body, "}\n");
}
static void emit_op_forprep(struct function *fn, int A, int pc, int pc1) {
(void)pc1;
if (!fn->locals[A]) {
@ -1680,6 +1705,14 @@ static void emit_op_iforloop(struct function *fn, int A, int pc, int step_one, i
A, A, A + 3, A, pc);
}
static void emit_op_forloop_int(struct function *fn, int A, int pc, int pc1) {
(void)pc1;
membuff_add_fstring(&fn->body, "i_%d += step_%d;\n", A, A);
membuff_add_fstring(&fn->body, "if ((0 < step_%d) ? (i_%d <= limit_%d) : (limit_%d <= i_%d)) {\n", A, A, A, A, A);
membuff_add_fstring(&fn->body, " ra = R(%d);\n setivalue(ra, i_%d);\n goto Lbc_%d;\n", A + 3, A, pc);
membuff_add_string(&fn->body, "}\n");
}
static void emit_op_forloop(struct function *fn, int A, int pc, int pc1) {
(void)pc1;
membuff_add_fstring(&fn->body, "if (intloop_%d) {\n", A);

@ -23,6 +23,7 @@
#include <ravijit.h>
#include <ravi_llvmcodegen.h>
#include <ravi_jitshared.h>
#include <dmr_c.h>
namespace ravi {
@ -1306,6 +1307,67 @@ llvm::Value *RaviCodeGenerator::emit_gep_upval_value(
return emit_gep(def, "value", pupval, 0, 2);
}
// Alternative code generator uses dmrC based C front-end
// That the codegen emits C code that is then JIT compiled
// via dmrC and LLVM.
bool RaviCodeGenerator::alt_compile(lua_State *L, Proto *p,
std::shared_ptr<RaviJITModule> module,
ravi_compile_options_t *options) {
if (p->ravi_jit.jit_status != RAVI_JIT_NOT_COMPILED) {
return false;
}
if (module->owner()->get_compiling_flag()) return false;
if (!raviJ_cancompile(p)) {
p->ravi_jit.jit_status = RAVI_JIT_CANT_COMPILE;
return false;
}
auto M = module->module();
LLVMModuleRef moduleRef = llvm::wrap(M);
// Set flag so we can avoid recursive calls
module->owner()->set_compiling_flag(true);
membuff_t buf;
membuff_init(&buf, 4096);
const char *fname = unique_function_name();
if (!raviJ_codegen(L, p, options, fname, &buf)) {
p->ravi_jit.jit_status = RAVI_JIT_CANT_COMPILE;
}
else {
if (options->manual_request && module->owner()->get_verbosity()) {
ravi_writestring(L, buf.buf, strlen(buf.buf));
ravi_writeline(L);
}
char *argv[] = {(char *)fname, NULL};
if (!dmrC_llvmcompile(2, argv, moduleRef, buf.buf)) {
p->ravi_jit.jit_status = RAVI_JIT_CANT_COMPILE;
}
else {
p->ravi_jit.jit_function = nullptr;
std::unique_ptr<ravi::RaviJITFunction> func =
std::unique_ptr<RaviJITFunction>(new RaviJITFunction(&p->ravi_jit.jit_function, module, fname));
if (func->function() == nullptr) {
fprintf(stderr, "LLVM Compilation failed\n");
exit(1);
}
bool doVerify = module->owner()->get_validation() != 0;
if (doVerify && llvm::verifyFunction(*func->function(), &llvm::errs())) {
func->dump();
fprintf(stderr, "LLVM Code Verification failed\n");
exit(1);
}
ravi::RaviJITFunction *llvm_func = func.release();
p->ravi_jit.jit_data = reinterpret_cast<void *>(llvm_func);
p->ravi_jit.jit_status = RAVI_JIT_COMPILED;
}
}
membuff_free(&buf);
module->owner()->set_compiling_flag(false);
return p->ravi_jit.jit_status == RAVI_JIT_COMPILED;
}
bool RaviCodeGenerator::compile(lua_State *L, Proto *p,
std::shared_ptr<RaviJITModule> module,
ravi_compile_options_t *options) {

File diff suppressed because it is too large Load Diff

@ -69,8 +69,7 @@ void raviV_dumpIR(struct lua_State *L, struct Proto *p) {
// and also whether to dump header or body or both
char fname[30];
snprintf(fname, sizeof fname, "jitfunction");
ravi_compile_options_t options = {0, 0, 0};
options.codegen_type = RAVI_CODEGEN_ALL;
ravi_compile_options_t options = {0, 0, 0, RAVI_CODEGEN_ALL};
if (raviJ_codegen(L, p, &options, fname, &buf)) { puts(buf.buf); }
membuff_free(&buf);
}
@ -174,5 +173,6 @@ int raviV_gettraceenabled(struct lua_State *L) {
}
int ravi_compile_C(lua_State *L) {
(void)L;
return 0;
}

@ -0,0 +1,173 @@
#include <ctype.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <inttypes.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lobject.h"
#ifndef RAVI_USE_ASMVM
#error This file can only be compiled with ASMVM
#endif
struct MyValue {
int type;
union {
lua_Integer i;
lua_Number n;
const char *s;
} u;
};
/**
* Compiles the given code and invokes it, passing params to it.
* Checks that the code returns given number of values that match expected
* results. Returns 0 if no error.
*/
static int do_asmvm_test(
const char *code, /* code to compiled and invoked */
int nparams, struct MyValue *params, /* parameters */
int nresults, struct MyValue *expected) /* expected return values */
{
int rc = 0;
lua_State *L;
L = luaL_newstate();
luaL_openlibs(L); /* open standard libraries */
if (luaL_loadbuffer(L, code, strlen(code), "chunk") != 0) {
rc = 1;
fprintf(stderr, "Failed to load chunk: %s\n", lua_tostring(L, -1));
lua_pop(L, 1); /* pop error message from the stack */
goto Lerror;
}
if (lua_pcall(L, 0, 1, 0) != 0) {
rc = 1;
fprintf(stderr, "Failed to run chunk: %s\n", lua_tostring(L, -1));
goto Lerror;
}
if (!lua_isfunction(L, -1)) {
rc = 1;
fprintf(stderr, "Script did not return a function\n");
goto Lerror;
}
for (int i = 0; i < nparams; i++) {
switch (params[i].type) {
case RAVI_TNUMINT:
lua_pushinteger(L, params[i].u.i);
break;
case RAVI_TNUMFLT:
lua_pushnumber(L, params[i].u.n);
break;
case RAVI_TSTRING:
lua_pushstring(L, params[i].u.s);
break;
default:
fprintf(stderr, "Unsupported argument type %d\n", params[i].type);
rc = 1;
goto Lerror;
}
}
if (lua_pcall(L, nparams, nresults, 0) != 0) {
rc = 1;
fprintf(stderr, "Test function failed: %s\n", lua_tostring(L, -1));
goto Lerror;
}
for (int i = nresults - 1, j = -1; i >= 0; i--, j--) {
switch (expected[i].type) {
case RAVI_TNUMINT: {
if (!lua_isinteger(L, j)) {
fprintf(stderr, "Result %d was expected to be integer\n", i + 1);
rc = 1;
goto Lerror;
}
lua_Integer num = lua_tointeger(L, j);
if (num != expected[i].u.i) {
fprintf(stderr, "Result %d was expected to be %d, but got %d\n", i + 1, (int)expected[i].u.i, (int)num);
rc = 1;
goto Lerror;
}
break;
}
case RAVI_TNUMFLT: {
if (!lua_isnumber(L, j)) {
fprintf(stderr, "Result %d was expected to be number\n", i + 1);
rc = 1;
goto Lerror;
}
lua_Number num = lua_tonumber(L, j);
if (num != expected[i].u.n) {
fprintf(stderr, "Result %d was expected to be %g, but got %g\n", i + 1, expected[i].u.n, num);
rc = 1;
goto Lerror;
}
break;
}
case RAVI_TSTRING: {
if (!lua_isstring(L, j)) {
fprintf(stderr, "Result %d was expected to be string\n", i + 1);
rc = 1;
goto Lerror;
}
const char *s = lua_tostring(L, j);
if (strcmp(s, expected[i].u.s) != 0) {
fprintf(stderr, "Result %d was expected to be %s, but got %s\n", i + 1, expected[i].u.s, s);
rc = 1;
goto Lerror;
}
break;
}
default: {
fprintf(stderr, "Result %d has unexpected type\n", i + 1);
rc = 1;
goto Lerror;
}
}
}
Lerror:
lua_close(L);
return rc;
}
static int test_vm()
{
int failures = 0;
struct MyValue args[3];
struct MyValue results[3];
args[0].type = RAVI_TNUMINT; args[0].u.i = 42;
args[1].type = RAVI_TNUMFLT; args[1].u.n = -4.2;
args[2].type = RAVI_TSTRING; args[2].u.s = "hello";
results[0].type = RAVI_TNUMINT; results[0].u.i = 42;
results[1].type = RAVI_TNUMFLT; results[1].u.n = -4.2;
results[2].type = RAVI_TSTRING; results[2].u.s = "hello";
failures = do_asmvm_test("return function() end", 0, NULL, 0, NULL); // OP_RETURN
failures += do_asmvm_test("return function() return 42 end", 0, NULL, 1, results); // OP_LOADK, OP_RETURN
failures += do_asmvm_test("return function() return 42, -4.2 end", 0, NULL, 2, results); // OP_LOADK, OP_RETURN
failures += do_asmvm_test("return function() return 42, -4.2, 'hello' end", 0, NULL, 3, results); // OP_LOADK, OP_RETURN
failures += do_asmvm_test("return function(a) local b = a; return b end", 1, args, 1, results); // OP_MOVE, OP_RETURN
failures += do_asmvm_test("return function(a,c) local b,d = a,c; return b,d end", 2, args, 2, results); // OP_MOVE, OP_RETURN
results[0].u.i = 5;
failures += do_asmvm_test("return function (a) for i=1,5 do a=i; end return a end", 0, NULL, 1, results); // OP_LOADK, OP_MOVE, OP_RETURN, OP_RAVI_FOPREP_I1, OP_RAVI_FORLOOP_I1
results[0].u.i = 3;
failures += do_asmvm_test("return function (a) for i=1,4,2 do a=i; end return a end", 0, NULL, 1, results); // OP_LOADK, OP_MOVE, OP_RETURN, OP_RAVI_FOPREP_IP, OP_RAVI_FORLOOP_IP
return failures;
}
int main()
{
int failures = 0;
failures += test_vm();
if (failures)
printf("FAILED\n");
else
printf("OK\n");
return failures ? 1 : 0;
}

@ -12,8 +12,6 @@
#include "lualib.h"
#include "lobject.h"
#ifndef RAVI_USE_ASMVM
/* test supplied lua code compiles */
static int test_luacomp1(const char *code)
{
@ -31,62 +29,6 @@ static int test_luacomp1(const char *code)
return rc;
}
#if 0
static int test_luacompfile(const char *code)
{
int rc = 0;
lua_State *L;
L = luaL_newstate();
if (luaL_loadfile(L, code) != 0) {
rc = 1;
fprintf(stderr, "%s\n", lua_tostring(L, -1));
lua_pop(L, 1); /* pop error message from the stack */
}
else
ravi_dump_function(L);
lua_close(L);
return rc;
}
/* test supplied lua code compiles */
static int test_luafileexec1(const char *code, int expected)
{
int rc = 0;
lua_State *L;
L = luaL_newstate();
luaL_openlibs(L); /* open standard libraries */
if (luaL_loadfile(L, code) != 0) {
rc = 1;
fprintf(stderr, "%s\n", lua_tostring(L, -1));
lua_pop(L, 1); /* pop error message from the stack */
}
else {
ravi_dump_function(L);
time_t start = time(NULL);
if (lua_pcall(L, 0, 1, 0) != 0) {
rc = 1;
fprintf(stderr, "%s\n", lua_tostring(L, -1));
}
else {
time_t end = time(NULL);
ravi_dump_stack(L, "after executing function");
printf("time taken = %f\n", difftime(end, start));
lua_Integer got = 0;
if (lua_isboolean(L, -1))
got = lua_toboolean(L, -1) ? 1 : 0;
else
got = lua_tointeger(L, -1);
if (got != expected) {
rc = 1;
}
}
}
lua_close(L);
return rc;
}
#endif
/* test supplied lua code compiles */
static int test_luacompexec1(const char *code, int expected)
{
@ -124,152 +66,10 @@ static int test_luacompexec1(const char *code, int expected)
return rc;
}
#else
struct MyValue {
int type;
union {
lua_Integer i;
lua_Number n;
const char *s;
} u;
};
static int do_asmvm_test(const char *code, int nparams, struct MyValue *params, int nresults, struct MyValue *expected)
{
int rc = 0;
lua_State *L;
L = luaL_newstate();
luaL_openlibs(L); /* open standard libraries */
if (luaL_loadbuffer(L, code, strlen(code), "chunk") != 0) {
rc = 1;
fprintf(stderr, "Failed to load chunk: %s\n", lua_tostring(L, -1));
lua_pop(L, 1); /* pop error message from the stack */
goto Lerror;
}
if (lua_pcall(L, 0, 1, 0) != 0) {
rc = 1;
fprintf(stderr, "Failed to run chunk: %s\n", lua_tostring(L, -1));
goto Lerror;
}
if (!lua_isfunction(L, -1)) {
rc = 1;
fprintf(stderr, "Script did not return a function\n");
goto Lerror;
}
for (int i = 0; i < nparams; i++) {
switch (params[i].type) {
case RAVI_TNUMINT:
lua_pushinteger(L, params[i].u.i);
break;
case RAVI_TNUMFLT:
lua_pushnumber(L, params[i].u.n);
break;
case RAVI_TSTRING:
lua_pushstring(L, params[i].u.s);
break;
default:
fprintf(stderr, "Unsupported argument type %d\n", params[i].type);
rc = 1;
goto Lerror;
}
}
if (lua_pcall(L, nparams, nresults, 0) != 0) {
rc = 1;
fprintf(stderr, "Test function failed: %s\n", lua_tostring(L, -1));
goto Lerror;
}
for (int i = nresults - 1, j = -1; i >= 0; i--, j--) {
switch (expected[i].type) {
case RAVI_TNUMINT: {
if (!lua_isinteger(L, j)) {
fprintf(stderr, "Result %d was expected to be integer\n", i + 1);
rc = 1;
goto Lerror;
}
lua_Integer num = lua_tointeger(L, j);
if (num != expected[i].u.i) {
fprintf(stderr, "Result %d was expected to be %d, but got %d\n", i + 1, (int)expected[i].u.i, (int)num);
rc = 1;
goto Lerror;
}
break;
}
case RAVI_TNUMFLT: {
if (!lua_isnumber(L, j)) {
fprintf(stderr, "Result %d was expected to be number\n", i + 1);
rc = 1;
goto Lerror;
}
lua_Number num = lua_tonumber(L, j);
if (num != expected[i].u.n) {
fprintf(stderr, "Result %d was expected to be %g, but got %g\n", i + 1, expected[i].u.n, num);
rc = 1;
goto Lerror;
}
break;
}
case RAVI_TSTRING: {
if (!lua_isstring(L, j)) {
fprintf(stderr, "Result %d was expected to be string\n", i + 1);
rc = 1;
goto Lerror;
}
const char *s = lua_tostring(L, j);
if (strcmp(s, expected[i].u.s) != 0) {
fprintf(stderr, "Result %d was expected to be %s, but got %s\n", i + 1, expected[i].u.s, s);
rc = 1;
goto Lerror;
}
break;
}
default: {
fprintf(stderr, "Result %d has unexpected type\n", i + 1);
rc = 1;
goto Lerror;
}
}
}
Lerror:
lua_close(L);
return rc;
}
static int test_vm()
{
int failures = 0;
struct MyValue args[3];
struct MyValue results[3];
args[0].type = RAVI_TNUMINT; args[0].u.i = 42;
args[1].type = RAVI_TNUMFLT; args[1].u.n = -4.2;
args[2].type = RAVI_TSTRING; args[2].u.s = "hello";
results[0].type = RAVI_TNUMINT; results[0].u.i = 42;
results[1].type = RAVI_TNUMFLT; results[1].u.n = -4.2;
results[2].type = RAVI_TSTRING; results[2].u.s = "hello";
failures = do_asmvm_test("return function() end", 0, NULL, 0, NULL); // OP_RETURN
failures += do_asmvm_test("return function() return 42 end", 0, NULL, 1, results); // OP_LOADK, OP_RETURN
failures += do_asmvm_test("return function() return 42, -4.2 end", 0, NULL, 2, results); // OP_LOADK, OP_RETURN
failures += do_asmvm_test("return function() return 42, -4.2, 'hello' end", 0, NULL, 3, results); // OP_LOADK, OP_RETURN
failures += do_asmvm_test("return function(a) local b = a; return b end", 1, args, 1, results); // OP_MOVE, OP_RETURN
failures += do_asmvm_test("return function(a,c) local b,d = a,c; return b,d end", 2, args, 2, results); // OP_MOVE, OP_RETURN
results[0].u.i = 5;
failures += do_asmvm_test("return function (a) for i=1,5 do a=i; end return a end", 0, NULL, 1, results); // OP_LOADK, OP_MOVE, OP_RETURN, OP_RAVI_FOPREP_I1, OP_RAVI_FORLOOP_I1
results[0].u.i = 3;
failures += do_asmvm_test("return function (a) for i=1,4,2 do a=i; end return a end", 0, NULL, 1, results); // OP_LOADK, OP_MOVE, OP_RETURN, OP_RAVI_FOPREP_IP, OP_RAVI_FORLOOP_IP
return failures;
}
#endif
#ifndef RAVI_USE_ASMVM
static int test_vm()
{
int failures = 0;
//
failures += test_luacomp1("function x() local t : table = {}; t.name = 'd'; end");
failures += test_luacompexec1("function test(); local x: integer = 1; return function (j) x = j; return x; end; end; fn = test(); return fn('55')", 55);
failures += test_luacompexec1("ravi.auto(true); function arrayaccess (); local x: integer[] = {5}; return x[1]; end; assert(ravi.compile(arrayaccess)); return arrayaccess()", 5);
@ -339,8 +139,6 @@ static int test_vm()
return failures;
}
#endif
int main()
{
int failures = 0;

@ -6,3 +6,6 @@ The clang output was generated using::
clang -I ~/github/ravi/include -std=c99 -O3 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_COMPAT_5_1 -DLUA_USE_MACOSX -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk -DRAVI_USE_ASMVM -DRAVI_USE_COMPUTED_GOTO -S -g -c ~/github/ravi/src/lvm.c
The lvm.s was generated as follows:
objdump -d -M intel -S CMakeFiles/libravinojit_static.dir/src/lvm.c.o > lvm.s

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -6,8 +6,8 @@ The overall approach is:
* Create a dispatch table with pointers to the assembler routines; the dispatch table is stored in the Lua global_State structure
but this could change in future
* Each assembler routine will (after completing its action) fetch the next bytecode instruction and jump to the next
assembler routine using the dispatch table
* The assembler routines are C functions - they are part of one whole program. Hence they make assumptions about
assembler routine using the dispatch table (equivalent to computed goto)
* The assembler routines are **not** C functions - they are part of one whole program. Hence they make assumptions about
register usage which will be documented below. The VM as a whole will have a fixed set of register allocations so that most
important information is held in registers.
@ -33,7 +33,7 @@ Using an assembler like yasm has the problem of computing offsets of C structure
Issues with dynasm
------------------
On Windows 64-bit the generated code requires UNWIND information however the mechanism for this was in LuaJIT specific files (buildvm_peobj) and not fully reusable. I have modified this to decouple from LuaJIT. This took some effort because LuaJIT's code
On Windows 64-bit the generated code requires UNWIND information however the mechanism for this was in LuaJIT specific files (buildvm_peobj) and not fully reusable. I have modified this to de-couple from LuaJIT. This took some effort because LuaJIT's code
has numerous magic numbers with no explanation of what the code is doing. Not very helpful for anyone trying to work out what
the code is doing unless you already know what needs doing.
@ -287,12 +287,11 @@ And the epilogue::
As you can see the unwind information basically tells Windows what the epilogue is supposed to be, and where to find the saved
values of the registers.
Building Ravi With New VM
-------------------------
Building Ravi With New ASM VM
-----------------------------
This is only for the brave who want to hack with the code.
To enable the new VM first build and install VMBuilder as described above.
Then build Ravi using the cmake flags ``-DSTATIC_BUILD=ON`` and ``-DASM_VM=ON`` enabled. Don't enable JIT.
Right now the ASM VM is exercised via the ``test_vm`` sub project. The ASM VM is only invoked in special cases, i.e. a function has small number of instructions and only contains supported instructions, and additionally as OP_CALL is not yet implemented, you can only call the new VM via the Lua C api (see test_asmvm() in test_vm.c).
Right now the ASM VM is exercised via the ``test_asmvm`` sub project. The ASM VM is only invoked in special cases, i.e. a function has small number of instructions and only contains supported instructions, and additionally as OP_CALL is not yet implemented, you can only call the new VM via the Lua C api (see `test_asmvm() in test_asmvm.c <https://github.com/dibyendumajumdar/ravi/blob/master/tests/test_asmvm.c>`_).

Loading…
Cancel
Save