issue #142 removed gcc jit implementation (left on a branch)

nanojit
Dibyendu Majumdar 6 years ago
parent dc258d3724
commit 9fa20358b2

@ -3,7 +3,6 @@ project(Ravi)
enable_language(CXX)
enable_language(C)
enable_language(C)
enable_language(ASM)
enable_testing()
@ -12,23 +11,15 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
# By default JIT is OFF
option(LLVM_JIT "Controls whether LLVM JIT compilation will be enabled, default is OFF" OFF)
option(GCC_JIT "Controls whether GCC JIT compilation will be enabled, default is OFF" OFF)
option(NANO_JIT "Controls whether NanoJIT compilation will be enabled, default is OFF" OFF)
option(STATIC_BUILD "Build static version of Ravi, default is OFF" OFF)
option(EMBEDDED_DMRC "Controls whether the embedded dmrC feature should be enabled, default is OFF" OFF)
option(COMPUTED_GOTO "Controls whether the interpreter switch will use computed gotos on gcc/clang, default is OFF" ON)
option(ASM_VM "Controls whether to use the new VM (not ready yet! so don't turn on)" OFF)
# We cannot link to both LLVM and GCC JIT
if (LLVM_JIT AND GCC_JIT)
message(FATAL_ERROR
"Both LLVM_JIT and GCC_JIT cannot be set to ON at the same time")
elseif (LLVM_JIT AND NANO_JIT)
if (LLVM_JIT AND NANO_JIT)
message(FATAL_ERROR
"Both LLVM_JIT and NANO_JIT cannot be set to ON at the same time")
elseif (GCC_JIT AND NANO_JIT)
message(FATAL_ERROR
"Both GCC_JIT and NANO_JIT cannot be set to ON at the same time")
endif()
if (ASM_VM)
@ -67,23 +58,14 @@ if (COMPUTED_GOTO AND MSVC)
message(WARNING "Computed goto is not available with MSVC")
endif()
if (GCC_JIT)
find_package(GCCJIT REQUIRED)
message(STATUS "Found GCCJIT")
include_directories(${GCCJIT_INCLUDE_DIRS})
add_definitions(-DUSE_GCCJIT)
endif()
if (NANO_JIT)
find_package(NanoJIT REQUIRED)
include_directories(${NANOJITEXTRA_INCLUDE_DIRS})
add_definitions(-DUSE_NANOJIT)
endif()
if (NOT LLVM_JIT AND NOT GCC_JIT AND NOT NANO_JIT)
message(WARNING "Neither LLVM, NanoJIT nor gccjit will be enabled; specify -DLLVM_JIT=ON, -DNANO_JIT=ON or -DGCC_JIT=ON to enable")
if (NOT LLVM_JIT)
message(WARNING "LLVM will not be enabled; specify -DLLVM_JIT=ON to enable")
endif()
if (MSVC)
@ -202,17 +184,10 @@ if (LLVM_JIT)
src/ravi_llvmarith2.cpp src/ravi_llvmtforcall.cpp src/ravi_llvmrest.cpp
src/ravi_llvmluaapi.cpp)
endif ()
if (GCC_JIT)
set(GCC_JIT_SRCS src/ravi_gccjit.c src/ravi_gcctypes.c
src/ravi_gcccodegen.c src/ravi_gccforprep.c src/ravi_gcccomp.c
src/ravi_gccreturn.c src/ravi_gccload.c src/ravi_gccforloop.c
src/ravi_gccarith1.c src/ravi_gcccall.c src/ravi_gcctable.c
src/ravi_gccarith2.c src/ravi_gcctforcall.c src/ravi_gccrest.c)
endif ()
if (NANO_JIT)
set(NANO_JIT_SRCS src/ravi_nanojit.c)
endif()
if (NOT LLVM_JIT AND NOT GCC_JIT AND NOT NANO_JIT)
if (NOT LLVM_JIT AND NOT NANO_JIT)
set(NO_JIT_SRCS src/ravi_nojit.c)
endif()
# define the lua core source files
@ -238,7 +213,7 @@ set(LUA_HEADERS include/lua.h include/luaconf.h include/lualib.h include/lauxlib
if (MSVC OR APPLE)
source_group("Ravi Headers" FILES ${RAVI_HEADERS})
source_group("Ravi Source Files" FILES ${LUA_CORE_SRCS} ${LUA_LIB_SRCS}
${LLVM_JIT_SRCS} ${GCC_JIT_SRCS})
${LLVM_JIT_SRCS})
if (APPLE)
set(EXTRA_LIBRARIES m readline)
endif ()
@ -405,8 +380,6 @@ endif()
if (LLVM_JIT)
set (LIBRAVI_NAME libravillvm)
elseif (GCC_JIT)
set (LIBRAVI_NAME libravigccjit)
elseif (NANO_JIT)
set (LIBRAVI_NAME libravinanojit)
else()
@ -419,7 +392,6 @@ add_library(${LIBRAVI_NAME} ${LIBRAVI_BUILD_TYPE}
${LUA_LIB_SRCS}
${LUA_CORE_SRCS}
${LLVM_JIT_SRCS}
${GCC_JIT_SRCS}
${NANO_JIT_SRCS}
${NO_JIT_SRCS}
${DMR_C_HEADERS}
@ -435,7 +407,7 @@ if (NOT STATIC_BUILD)
set_target_properties(${LIBRAVI_NAME} PROPERTIES PREFIX "")
endif ()
endif()
target_link_libraries(${LIBRAVI_NAME} ${EXTRA_LIBRARIES} ${LLVM_LIBS} ${GCCJIT_LIBRARIES} ${NANOJITEXTRA_LIBRARIES})
target_link_libraries(${LIBRAVI_NAME} ${EXTRA_LIBRARIES} ${LLVM_LIBS} ${NANOJITEXTRA_LIBRARIES})
# Ravi executable
add_executable(ravi src/lua.c)
@ -460,7 +432,7 @@ add_test(TestVM test_vm)
add_test(TestMisc test_misc)
# Build VSCode Debug Adapter for Ravi
if (STATIC_BUILD AND NOT GCC_JIT AND NOT NANO_JIT)
if (STATIC_BUILD AND NOT NANO_JIT)
add_executable(testravidebug vscode-debugger/src/testravidebug.c vscode-debugger/src/json.c vscode-debugger/src/protocol.c)
target_link_libraries(testravidebug ${LIBRAVI_NAME})

@ -24,7 +24,7 @@ Features
* Type specific bytecodes to improve performance
* Compatibility with Lua 5.3 (see Compatibility section below)
* `LLVM <http://www.llvm.org/>`_ powered JIT compiler
* Additionally a `libgccjit <https://gcc.gnu.org/wiki/JIT>`_ based alternative JIT compiler is also available, although this is not currently being worked on
* Additionally a `libgccjit <https://gcc.gnu.org/wiki/JIT>`_ based alternative JIT compiler is also available (on a branch), although this is not currently being worked on
* LLVM bindings exposed in Lua
Recent Work
@ -50,8 +50,6 @@ The LLVM JIT compiler is functional. The Lua and Ravi bytecodes currently implem
Ravi also provides an `LLVM binding <http://the-ravi-programming-language.readthedocs.org/en/latest/llvm-bindings.html>`_; this is still work in progress so please check documentation for the latest status.
There is also a `libgccjit <http://the-ravi-programming-language.readthedocs.org/en/latest/ravi-jit-libgccjit.html>`_ based JIT implementation but this implementation is lagging behind the LLVM based implementation. Further development of this is currently not planned.
Ravi Extensions to Lua 5.3
==========================
@ -508,7 +506,7 @@ I test the build by running a modified version of Lua 5.3.3 test suite. These te
Roadmap
=======
* 2015 - Implemented JIT compilation using LLVM
* 2015 - Implemented libgccjit based alternative JIT
* 2015 - 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 - Main priorities are:

@ -1,3 +0,0 @@
mkdir buildgcc
cd buildgcc
cmake -DCMAKE_BUILD_TYPE=Release -DGCC_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi ..

@ -1,15 +0,0 @@
find_path(GCCJIT_INC libgccjit.h
PATHS
~/local/include
/usr/local/include
)
find_library(GCCJIT_LIB
NAMES gccjit libgccjit
PATHS
~/local/lib
/usr/local/lib/gcc/5
)
set( GCCJIT_INCLUDE_DIRS "${GCCJIT_INC}" )
set( GCCJIT_LIBRARIES "${GCCJIT_LIB}" )

@ -1,776 +0,0 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
#ifndef RAVI_RAVI_GCCJIT_H
#define RAVI_RAVI_GCCJIT_H
#ifdef USE_GCCJIT
#include <libgccjit.h>
#include "ravijit.h"
#ifdef __cplusplus
extern "C" {
#endif
// TODO we probably do not need all the headers
// below
#define LUA_CORE
#include "lprefix.h"
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stddef.h>
#include "lua.h"
#include "ldebug.h"
#include "ldo.h"
#include "lfunc.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"
#include "lvm.h"
typedef enum {
LUA__TNIL = LUA_TNIL,
LUA__TBOOLEAN = LUA_TBOOLEAN,
LUA__TLIGHTUSERDATA = LUA_TLIGHTUSERDATA,
LUA__TNUMBER = LUA_TNUMBER,
LUA__TSTRING = ctb(LUA_TSTRING),
LUA__TTABLE = ctb(LUA_TTABLE),
RAVI__TLTABLE = ctb(LUA_TTABLE),
RAVI__TIARRAY = ctb(RAVI_TIARRAY),
RAVI__TFARRAY = ctb(RAVI_TFARRAY),
LUA__TFUNCTION = ctb(LUA_TFUNCTION),
LUA__TUSERDATA = ctb(LUA_TUSERDATA),
LUA__TTHREAD = ctb(LUA_TTHREAD),
LUA__TLCL = ctb(LUA_TLCL),
LUA__TLCF = LUA_TLCF,
LUA__TCCL = ctb(LUA_TCCL),
LUA__TSHRSTR = ctb(LUA_TSHRSTR),
LUA__TLNGSTR = ctb(LUA_TLNGSTR),
LUA__TNUMFLT = LUA_TNUMFLT,
LUA__TNUMINT = LUA_TNUMINT
} lua_typecode_t;
typedef struct ravi_gcc_context_t ravi_gcc_context_t;
typedef struct ravi_gcc_types_t ravi_gcc_types_t;
typedef struct ravi_gcc_codegen_t ravi_gcc_codegen_t;
struct ravi_State {
ravi_gcc_context_t *jit;
ravi_gcc_codegen_t *code_generator;
};
struct ravi_gcc_types_t {
gcc_jit_type *C_boolT;
gcc_jit_type *C_doubleT;
gcc_jit_type *C_intptr_t;
gcc_jit_type *C_size_t;
gcc_jit_type *C_ptrdiff_t;
gcc_jit_type *C_int64_t;
gcc_jit_type *C_shortT;
gcc_jit_type *C_unsigned_shortT;
gcc_jit_type *C_voidT;
gcc_jit_type *C_pvoidT;
gcc_jit_type *lua_NumberT;
gcc_jit_type *plua_NumberT;
gcc_jit_type *pplua_NumberT;
gcc_jit_type *lua_IntegerT;
gcc_jit_type *plua_IntegerT;
gcc_jit_type *pplua_IntegerT;
// gcc_jit_type *clua_IntegerT;
gcc_jit_type *lua_UnsignedT;
gcc_jit_type *lua_KContextT;
// gcc_jit_function *lua_CFunctionT;
gcc_jit_type *plua_CFunctionT;
// gcc_jit_function *lua_KFunctionT;
gcc_jit_type *plua_KFunctionT;
// gcc_jit_function *lua_HookT;
gcc_jit_type *plua_HookT;
// gcc_jit_function *lua_AllocT;
gcc_jit_type *plua_AllocT;
gcc_jit_type *l_memT;
gcc_jit_type *lu_memT;
gcc_jit_type *tmsT;
gcc_jit_type *lu_byteT;
gcc_jit_type *L_UmaxalignT;
gcc_jit_type *C_charT;
gcc_jit_type *C_pcharT;
gcc_jit_type *C_pconstcharT;
gcc_jit_type *C_intT;
gcc_jit_type *C_pintT;
gcc_jit_type *C_unsigned_intT;
gcc_jit_struct *lua_StateT;
gcc_jit_type *plua_StateT;
gcc_jit_field *lua_State_ci;
gcc_jit_field *lua_State_top;
gcc_jit_struct *global_StateT;
gcc_jit_type *pglobal_StateT;
gcc_jit_struct *ravi_StateT;
gcc_jit_type *pravi_StateT;
gcc_jit_struct *GCObjectT;
gcc_jit_type *pGCObjectT;
gcc_jit_type *ValueT;
gcc_jit_struct *TValueT;
gcc_jit_type *cTValueT;
gcc_jit_type *pTValueT;
gcc_jit_type *pcTValueT;
gcc_jit_field *Value_value;
gcc_jit_field *Value_value_gc;
gcc_jit_field *Value_value_n;
gcc_jit_field *Value_value_i;
gcc_jit_field *Value_value_b;
gcc_jit_field *Value_tt;
gcc_jit_struct *TStringT;
gcc_jit_type *pTStringT;
gcc_jit_type *ppTStringT;
gcc_jit_struct *UdataT;
gcc_jit_struct *RaviArrayT;
gcc_jit_field *RaviArray_len;
gcc_jit_field *RaviArray_data;
gcc_jit_field *RaviArray_array_type;
gcc_jit_struct *TableT;
gcc_jit_type *pTableT;
gcc_jit_type *ppTableT;
gcc_jit_field *Table_ravi_array;
gcc_jit_struct *UpvaldescT;
gcc_jit_type *pUpvaldescT;
gcc_jit_type *ravitype_tT;
gcc_jit_struct *LocVarT;
gcc_jit_type *pLocVarT;
gcc_jit_type *InstructionT;
gcc_jit_type *pInstructionT;
gcc_jit_struct *LClosureT;
gcc_jit_type *pLClosureT;
gcc_jit_type *ppLClosureT;
gcc_jit_type *pppLClosureT;
gcc_jit_type *ClosureT;
gcc_jit_type *pClosureT;
gcc_jit_field *LClosure_p;
gcc_jit_field *LClosure_p_k;
gcc_jit_field *LClosure_upvals;
gcc_jit_struct *RaviJITProtoT;
gcc_jit_struct *ProtoT;
gcc_jit_type *pProtoT;
gcc_jit_type *ppProtoT;
gcc_jit_field *Proto_sizep;
gcc_jit_struct *UpValT;
gcc_jit_type *pUpValT;
gcc_jit_struct *UpVal_u_openT;
gcc_jit_type *UpVal_uT;
gcc_jit_field *UpVal_v;
gcc_jit_field *UpVal_u;
gcc_jit_field *UpVal_u_value;
gcc_jit_struct *CClosureT;
gcc_jit_type *pCClosureT;
gcc_jit_type *TKeyT;
gcc_jit_type *pTKeyT;
gcc_jit_struct *NodeT;
gcc_jit_type *pNodeT;
gcc_jit_struct *lua_DebugT;
gcc_jit_type *plua_DebugT;
gcc_jit_struct *lua_longjumpT;
gcc_jit_type *plua_longjumpT;
gcc_jit_struct *MbufferT;
gcc_jit_struct *stringtableT;
gcc_jit_type *StkIdT;
gcc_jit_struct *CallInfoT;
gcc_jit_struct *CallInfo_cT;
gcc_jit_struct *CallInfo_lT;
gcc_jit_type *CallInfo_uT;
gcc_jit_type *pCallInfoT;
gcc_jit_field *CallInfo_func;
gcc_jit_field *CallInfo_top;
gcc_jit_field *CallInfo_u;
gcc_jit_field *CallInfo_u_l;
gcc_jit_field *CallInfo_u_l_base;
gcc_jit_function *jitFunctionT;
gcc_jit_function *luaD_poscallT;
gcc_jit_function *luaD_precallT;
gcc_jit_function *luaD_callT;
gcc_jit_function *luaF_closeT;
gcc_jit_function *luaT_trybinTMT;
gcc_jit_function *luaG_runerrorT;
gcc_jit_function *luaV_equalobjT;
gcc_jit_function *luaV_lessthanT;
gcc_jit_function *luaV_lessequalT;
gcc_jit_function *luaV_forlimitT;
gcc_jit_function *luaV_tonumberT;
gcc_jit_function *luaV_tointegerT;
gcc_jit_function *luaV_modT;
gcc_jit_function *luaV_objlenT;
gcc_jit_function *luaV_divT;
gcc_jit_function *luaC_upvalbarrierT;
gcc_jit_function *luaV_executeT;
gcc_jit_function *luaV_gettableT;
gcc_jit_function *luaV_settableT;
// Following are functions that handle specific bytecodes
// We cheat for these bytecodes by calling the function that
// implements it
gcc_jit_function *raviV_op_newarrayintT;
gcc_jit_function *raviV_op_newarrayfloatT;
gcc_jit_function *raviV_op_setlistT;
gcc_jit_function *raviV_op_newtableT;
gcc_jit_function *raviV_op_loadnilT;
gcc_jit_function *raviV_op_concatT;
gcc_jit_function *raviV_op_closureT;
gcc_jit_function *raviV_op_varargT;
gcc_jit_function *raviV_op_setupvalT;
gcc_jit_function *raviH_set_intT;
gcc_jit_function *raviH_set_floatT;
gcc_jit_function *printfT;
};
struct ravi_gcc_context_t {
/* parent JIT context - all functions are child contexts
* of this.
*/
gcc_jit_context *context;
gcc_jit_result *parent_result_;
/* Lua type definitions */
ravi_gcc_types_t *types;
/* Should we auto compile what we can? */
bool auto_;
/* Is JIT enabled */
bool enabled_;
/* Optimizer level */
int opt_level_;
/* Size level */
int size_level_;
/* min code size for compilation */
int min_code_size_;
/* min execution count for compilation */
int min_exec_count_;
};
struct ravi_gcc_codegen_t {
ravi_gcc_context_t *ravi;
char temp[31];
int id;
};
// struct ravi_gcc_function_t {
//
// gcc_jit_result *jit_result;
//
//};
typedef struct ravi_branch_def_t {
// this field is used for all branches
gcc_jit_block *jmp;
// These are local variables for a fornum
// loop
gcc_jit_lvalue *ilimit;
gcc_jit_lvalue *istep;
gcc_jit_lvalue *iidx;
gcc_jit_lvalue *flimit;
gcc_jit_lvalue *fstep;
gcc_jit_lvalue *fidx;
} ravi_branch_def_t;
typedef struct ravi_function_def_t {
ravi_gcc_context_t *ravi;
Proto *p;
char name[31];
/* Child context for the function being compiled */
gcc_jit_context *function_context;
gcc_jit_param *L;
gcc_jit_function *jit_function;
gcc_jit_block *entry_block;
struct ravi_branch_def_t **jmp_targets;
/* Currently compiled function's stack frame L->ci */
gcc_jit_lvalue *ci_val;
/* Currently compiled function's stack value L->ci->func
* type is LClosure *
*/
gcc_jit_rvalue *lua_closure;
gcc_jit_lvalue *lua_closure_val;
gcc_jit_lvalue *kOne_luaInteger;
gcc_jit_block *current_block;
bool current_block_terminated;
/* The Lua stack base - this can change during execution so needs to be lvalue
*/
gcc_jit_rvalue *base_ref;
// gcc_jit_lvalue *base;
/* Reference to lua_closure->p - never changes */
gcc_jit_rvalue *proto;
/* The Lua constants list for the function - this never changes */
gcc_jit_rvalue *k;
/* temporary buffer for creating unique names */
char buf[80];
/* counter used for creating unique names */
unsigned int counter;
int dump_ir;
int dump_asm;
int opt_level;
} ravi_function_def_t;
/* Create a new context */
extern ravi_gcc_context_t *ravi_jit_new_context(void);
/* Destroy a context */
extern void ravi_jit_context_free(ravi_gcc_context_t *);
/* Setup Lua types */
extern bool ravi_setup_lua_types(ravi_gcc_context_t *);
extern ravi_gcc_codegen_t *
ravi_jit_new_codegen(ravi_gcc_context_t *global_context);
extern void ravi_jit_codegen_free(ravi_gcc_codegen_t *);
extern bool ravi_jit_has_errored(ravi_gcc_context_t *);
extern void ravi_emit_load_base(ravi_function_def_t *def);
extern gcc_jit_lvalue *ravi_emit_get_register(ravi_function_def_t *def, int A);
extern gcc_jit_lvalue *ravi_emit_get_constant(ravi_function_def_t *def, int Bx);
extern gcc_jit_lvalue *
ravi_emit_get_register_or_constant(ravi_function_def_t *def, int B);
extern void ravi_emit_set_L_top_toreg(ravi_function_def_t *def, int B);
extern void ravi_emit_refresh_L_top(ravi_function_def_t *def);
extern gcc_jit_lvalue *ravi_emit_get_Proto_sizep(ravi_function_def_t *def);
extern gcc_jit_rvalue *ravi_emit_get_upvals(ravi_function_def_t *def,
int offset);
// Get upval->v
extern gcc_jit_lvalue *ravi_emit_load_upval_v(ravi_function_def_t *def,
gcc_jit_rvalue *pupval);
// Get upval->u.value
extern gcc_jit_lvalue *ravi_emit_load_upval_value(ravi_function_def_t *def,
gcc_jit_rvalue *pupval);
extern void ravi_set_current_block(ravi_function_def_t *def,
gcc_jit_block *block);
extern gcc_jit_rvalue *ravi_function_call1_rvalue(ravi_function_def_t *def,
gcc_jit_function *f,
gcc_jit_rvalue *arg1);
extern gcc_jit_rvalue *ravi_function_call2_rvalue(ravi_function_def_t *def,
gcc_jit_function *f,
gcc_jit_rvalue *arg1,
gcc_jit_rvalue *arg2);
extern gcc_jit_rvalue *ravi_function_call3_rvalue(ravi_function_def_t *def,
gcc_jit_function *f,
gcc_jit_rvalue *arg1,
gcc_jit_rvalue *arg2,
gcc_jit_rvalue *arg3);
extern gcc_jit_rvalue *
ravi_function_call4_rvalue(ravi_function_def_t *def, gcc_jit_function *f,
gcc_jit_rvalue *arg1, gcc_jit_rvalue *arg2,
gcc_jit_rvalue *arg3, gcc_jit_rvalue *arg4);
extern gcc_jit_rvalue *
ravi_function_call5_rvalue(ravi_function_def_t *def, gcc_jit_function *f,
gcc_jit_rvalue *arg1, gcc_jit_rvalue *arg2,
gcc_jit_rvalue *arg3, gcc_jit_rvalue *arg4,
gcc_jit_rvalue *arg5);
extern const char *unique_name(ravi_function_def_t *def, const char *prefix,
int pc);
extern gcc_jit_rvalue *ravi_emit_num_stack_elements(ravi_function_def_t *def,
gcc_jit_rvalue *ra);
extern void ravi_emit_struct_assign(ravi_function_def_t *def,
gcc_jit_lvalue *reg_dest,
gcc_jit_lvalue *reg_src);
/* Store an integer value and set type to TNUMINT */
extern gcc_jit_lvalue *ravi_emit_load_reg_i(ravi_function_def_t *def,
gcc_jit_lvalue *reg);
/* Store a number value and set type to TNUMFLT */
extern gcc_jit_lvalue *ravi_emit_load_reg_n(ravi_function_def_t *def,
gcc_jit_lvalue *reg);
/* Get TValue->value_.b */
extern gcc_jit_lvalue *ravi_emit_load_reg_b(ravi_function_def_t *def,
gcc_jit_lvalue *reg);
extern gcc_jit_lvalue *ravi_emit_load_type(ravi_function_def_t *def,
gcc_jit_lvalue *reg);
extern gcc_jit_rvalue *ravi_emit_is_value_of_type(ravi_function_def_t *def,
gcc_jit_rvalue *value_type,
int lua_type);
extern gcc_jit_rvalue *
ravi_emit_is_not_value_of_type(ravi_function_def_t *def,
gcc_jit_rvalue *value_type, int lua_type);
extern gcc_jit_rvalue *
ravi_emit_is_not_value_of_type_class(ravi_function_def_t *def,
gcc_jit_rvalue *value_type, int lua_type);
extern void ravi_emit_store_reg_i_withtype(ravi_function_def_t *def,
gcc_jit_rvalue *ivalue,
gcc_jit_lvalue *reg);
extern void ravi_emit_store_reg_n_withtype(ravi_function_def_t *def,
gcc_jit_rvalue *nvalue,
gcc_jit_lvalue *reg);
extern void ravi_emit_store_reg_b_withtype(ravi_function_def_t *def,
gcc_jit_rvalue *bvalue,
gcc_jit_lvalue *reg);
extern gcc_jit_rvalue *ravi_emit_load_reg_h(ravi_function_def_t *def,
gcc_jit_lvalue *reg);
extern gcc_jit_rvalue *ravi_emit_load_reg_h_floatarray(ravi_function_def_t *def,
gcc_jit_rvalue *h);
extern gcc_jit_rvalue *ravi_emit_load_reg_h_intarray(ravi_function_def_t *def,
gcc_jit_rvalue *h);
extern gcc_jit_lvalue *ravi_emit_load_ravi_arraylength(ravi_function_def_t *def,
gcc_jit_rvalue *h);
extern gcc_jit_lvalue *ravi_emit_load_ravi_arraytype(ravi_function_def_t *def,
gcc_jit_rvalue *h);
extern gcc_jit_rvalue *ravi_emit_array_get(ravi_function_def_t *def,
gcc_jit_rvalue *ptr,
gcc_jit_rvalue *index);
extern gcc_jit_lvalue *ravi_emit_array_get_ptr(ravi_function_def_t *def,
gcc_jit_rvalue *ptr,
gcc_jit_rvalue *index);
extern gcc_jit_rvalue *ravi_emit_comparison(ravi_function_def_t *def,
enum gcc_jit_comparison op,
gcc_jit_rvalue *a,
gcc_jit_rvalue *b);
extern gcc_jit_lvalue *ravi_emit_tonumtype(ravi_function_def_t *def,
gcc_jit_lvalue *reg,
lua_typecode_t tt, int pc);
extern void ravi_emit_conditional_branch(ravi_function_def_t *def,
gcc_jit_rvalue *cond,
gcc_jit_block *true_block,
gcc_jit_block *false_block);
extern void ravi_emit_branch(ravi_function_def_t *def,
gcc_jit_block *target_block);
extern gcc_jit_rvalue *ravi_emit_boolean_testfalse(ravi_function_def_t *def,
gcc_jit_lvalue *reg,
bool negate);
extern void ravi_emit_raise_lua_error(ravi_function_def_t *def,
const char *msg);
extern void ravi_emit_RETURN(ravi_function_def_t *def, int A, int B, int pc);
extern void ravi_emit_LOADK(ravi_function_def_t *def, int A, int Bx, int pc);
extern void ravi_emit_iFORPREP(ravi_function_def_t *def, int A, int pc,
int step_one);
extern void ravi_emit_iFORLOOP(ravi_function_def_t *def, int A, int pc,
ravi_branch_def_t *b, int step_one);
extern void ravi_emit_MOVE(ravi_function_def_t *def, int A, int B);
extern void ravi_emit_MOVEI(ravi_function_def_t *def, int A, int B, int pc);
extern void ravi_emit_MOVEF(ravi_function_def_t *def, int A, int B, int pc);
extern void ravi_emit_LOADNIL(ravi_function_def_t *def, int A, int B, int pc);
extern void ravi_emit_LOADFZ(ravi_function_def_t *def, int A, int pc);
extern void ravi_emit_LOADIZ(ravi_function_def_t *def, int A, int pc);
extern void ravi_emit_LOADBOOL(ravi_function_def_t *def, int A, int B, int C,
int j, int pc);
// implements EQ, LE and LT - by using the supplied lua function to call.
extern void ravi_emit_EQ_LE_LT(ravi_function_def_t *def, int A, int B, int C,
int j, int jA, gcc_jit_function *callee,
const char *opname, OpCode op, int pc);
extern void ravi_emit_JMP(ravi_function_def_t *def, int A, int j, int pc);
// Handle OP_CALL
extern void ravi_emit_CALL(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_GETTABUP(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_SETTABUP(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_SETUPVAL(ravi_function_def_t *def, int A, int B, int pc);
extern void ravi_emit_GETUPVAL(ravi_function_def_t *def, int A, int B, int pc);
extern void ravi_emit_TEST(ravi_function_def_t *def, int A, int B, int C, int j,
int jA, int pc);
extern void ravi_emit_TESTSET(ravi_function_def_t *def, int A, int B, int C,
int j, int jA, int pc);
extern void ravi_emit_NOT(ravi_function_def_t *def, int A, int B, int pc);
extern void ravi_emit_TOFLT(ravi_function_def_t *def, int A, int pc);
extern void ravi_emit_TOINT(ravi_function_def_t *def, int A, int pc);
extern void ravi_emit_CONCAT(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_CLOSURE(ravi_function_def_t *def, int A, int Bx, int pc);
extern void ravi_emit_VARARG(ravi_function_def_t *def, int A, int B, int pc);
extern void ravi_emit_UNMF(ravi_function_def_t *def, int A, int B, int pc);
extern void ravi_emit_UNMI(ravi_function_def_t *def, int A, int B, int pc);
extern void ravi_emit_ADDFF(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_ADDFI(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_ADDII(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_SUBFF(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_SUBFI(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_SUBIF(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_SUBII(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_DIVFF(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_DIVFI(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_DIVIF(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_DIVII(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_MULFF(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_MULFI(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_MULII(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_SELF(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_LEN(ravi_function_def_t *def, int A, int B, int pc);
extern void ravi_emit_SETTABLE(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_GETTABLE(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_NEWTABLE(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_SETLIST(ravi_function_def_t *def, int A, int B, int C,
int pc);
extern void ravi_emit_TFORCALL(ravi_function_def_t *def, int A, int B, int C,
int j, int jA, int pc);
extern void ravi_emit_TFORLOOP(ravi_function_def_t *def, int A, int j, int pc);
extern void ravi_emit_GETTABLE_AI(ravi_function_def_t *def, int A, int B, int C,
int pc, bool omitArrayGetRangeCheck);
extern void ravi_emit_GETTABLE_AF(ravi_function_def_t *def, int A, int B, int C,
int pc, bool omitArrayGetRangeCheck);
extern void ravi_emit_NEWARRAYFLOAT(ravi_function_def_t *def, int A, int pc);
extern void ravi_emit_NEWARRAYINT(ravi_function_def_t *def, int A, int pc);
extern void ravi_emit_TOARRAY(ravi_function_def_t *def, int A,
int array_type_expected, const char *errmsg,
int pc);
extern void ravi_emit_MOVEAI(ravi_function_def_t *def, int A, int B, int pc);
extern void ravi_emit_MOVEAF(ravi_function_def_t *def, int A, int B, int pc);
extern void ravi_emit_SETTABLE_AI_AF(ravi_function_def_t *def, int A, int B,
int C, bool known_tt, lua_typecode_t tt,
int pc);
extern void ravi_emit_ARITH(ravi_function_def_t *def, int A, int B, int C,
OpCode op, TMS tms, int pc);
extern void ravi_dump_rvalue(gcc_jit_rvalue *rv);
extern void ravi_dump_lvalue(gcc_jit_lvalue *lv);
extern void ravi_debug_printf(ravi_function_def_t *def, const char *str);
extern void ravi_debug_printf1(ravi_function_def_t *def, const char *str,
gcc_jit_rvalue *arg1);
extern void ravi_debug_printf2(ravi_function_def_t *def, const char *str,
gcc_jit_rvalue *arg1, gcc_jit_rvalue *arg2);
extern void ravi_debug_printf3(ravi_function_def_t *def, const char *str,
gcc_jit_rvalue *arg1, gcc_jit_rvalue *arg2,
gcc_jit_rvalue *arg3);
extern void ravi_debug_printf4(ravi_function_def_t *def, const char *str,
gcc_jit_rvalue *arg1, gcc_jit_rvalue *arg2,
gcc_jit_rvalue *arg3, gcc_jit_rvalue *arg4);
extern gcc_jit_rvalue *ravi_int_constant(ravi_function_def_t *def, int value);
extern gcc_jit_rvalue *ravi_bool_constant(ravi_function_def_t *def, int value);
extern gcc_jit_rvalue *ravi_lua_Integer_constant(ravi_function_def_t *def,
int value);
extern gcc_jit_rvalue *ravi_lua_Number_constant(ravi_function_def_t *def,
double value);
#ifdef __cplusplus
};
#endif
#endif /* USE_GCCJIT */
#endif /* RAVI_RAVI_GCCJIT_H */

@ -25,7 +25,6 @@ Contents:
llvm-bindings
ravi-benchmarks
ravi-jit-status
ravi-jit-libgccjit
Indices and tables

@ -1,315 +0,0 @@
========================================
JIT Compilation for Ravi using ``libgccjit``
========================================
Introduction
------------
The latest `gcc 5.2 release <http://gcc.gnu.org/>`_ contains a new component called ``libgccjit``. This basically exposes an API via a shared library to the compilation functions within gcc.
I am keen to provide support for this in Ravi. From initial look it seems to contain all the features I need to implement a JIT compiler for Ravi. Obviously having implemented the LLVM version it is going to be a little easier as I can mostly do a port of the LLVM version.
License
-------
Ravi itself is licensed under MIT license (including the code that implements the JIT compiler) - however I think that when linked to ``libgccjit`` the effective license will be GPLv3.
Why another JIT engine?
-----------------------
Well partly as I feel I have a moral obligation to support gcc, given it has been instrumental in bringing about the OpenSource / Free Software ecosystem.
Secondly I am always looking for alternatives that will let me reduce the footprint of Ravi. The ``libgccjit`` is offered as a shared library - this is a great thing. I hate to have to statically link LLVM.
LLVM implementation and ``libgccjit`` implementation will both be kept in sync so that user can choose either option. Right now the LLVM implementation is more advanced and new features are implemented there first and then ported to the ``libgccjit`` implementation.
Building GCC
------------
I am running Ubuntu 14.04 LTS on VMWare virtual machine.
I built gcc 5.2 from source as follows.
1. Extracted gcc-5.2 source to ``~/gcc-5.2.0``.
2. Created a build folder ``~/buildgcc``.
3. Installed various pre-requisites for gcc.
4. Then ran following from inside the build folder::
../gcc-5.2.0/configure --prefix=~/local --enable-host-shared --enable-languages=jit,c++ --disable-bootstrap --disable-multilib
5. Next performed the build as follows::
make
make install
On Mac OSX Yosemite
-------------------
It appears that the `HomeBrew <http://brew.sh/>`_ project supports creating the ``libgccjit 5.2`` library. However the default formula doesn't quite work and needs to be patched for libgccjit to work properly. A patched formula can be found at `here <https://github.com/dibyendumajumdar/ravi/blob/master/patches/gcc.rb>`_. To use the patched version edit the gcc formula and copy the patched version. After that following should build and install gcc 5.2 including the JIT library::
brew install gcc --with-jit --without-multilib
Current Status
--------------
Many bytecodes are now compiled - see below for detailed status. The current version of Ravi passes the Lua test cases using ``libgccjit``.
Building Ravi with ``libgccjit`` on Linux
-------------------------------------
.. warning:: Note that right now the Ravi's ``libgccjit`` based JIT implementation is work in progress - please expect bugs.
You can build Ravi with ``libgccjit`` linked in as follows::
mkdir build
cd build
export LD_LIBRARY_PATH=~/local/lib64:$LD_LIBRARY_PATH
cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=~/local/bin/gcc -DCMAKE_CXX_COMPILER=~/local/bin/g++ -DLLVM_DIR=~/LLVM/share/llvm/cmake -DLLVM_JIT=ON -DGCC_JIT=OFF ..
make
Above assumes that gccjit is installed under ``~/local`` as described in Building GCC section above.
A helloworld test program is built. To run it though you need to ensure that your ``PATH`` and ``LD_LIBRARY_PATH`` variables include ``~/local/bin`` and ``~/local/lib`` respectively.
Initial Observations
--------------------
In terms of packaging ``libgccjit`` consists of a C header file, a C++ header file and one shared library. That is pretty neat as it simplifies the usage.
Setting up of the Lua types is proving easier in ``libgccjit`` due to the fact that Lua uses unions extensively and ``libgccjit`` supports defining union types. This means that most of the Lua types can be translated more naturally. LLVM on the other hand does not support unions so I had to carefully define structs that would match the size of the union, and in the JIT compilation use casts where needed.
JIT Status of Lua/Ravi Bytecodes
---------------------------------
Following is the status as of 4 July 2015.
+-------------------------+----------+--------------------------------------------------+
| name | JITed? | description |
+=========================+==========+==================================================+
| OP_MOVE | YES | R(A) := R(B) |
+-------------------------+----------+--------------------------------------------------+
| OP_LOADK | YES | R(A) := Kst(Bx) |
+-------------------------+----------+--------------------------------------------------+
| OP_LOADKX | NO | R(A) := Kst(extra arg) |
+-------------------------+----------+--------------------------------------------------+
| OP_LOADBOOL | YES | R(A) := (Bool)B; if (C) pc++ |
+-------------------------+----------+--------------------------------------------------+
| OP_LOADNIL | YES | R(A), R(A+1), ..., R(A+B) := nil |
+-------------------------+----------+--------------------------------------------------+
| OP_GETUPVAL | YES | R(A) := UpValue[B] |
+-------------------------+----------+--------------------------------------------------+
| OP_GETTABUP | YES | R(A) := UpValue[B][RK(C)] |
+-------------------------+----------+--------------------------------------------------+
| OP_GETTABLE | YES | R(A) := R(B)[RK(C)] |
+-------------------------+----------+--------------------------------------------------+
| OP_SETTABUP | YES | UpValue[A][RK(B)] := RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_SETUPVAL | YES | UpValue[B] := R(A) |
+-------------------------+----------+--------------------------------------------------+
| OP_SETTABLE | YES | R(A)[RK(B)] := RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_NEWTABLE | YES | R(A) := {} (size = B,C) |
+-------------------------+----------+--------------------------------------------------+
| OP_SELF | YES | R(A+1) := R(B); R(A) := R(B)[RK(C)] |
+-------------------------+----------+--------------------------------------------------+
| OP_ADD | YES | R(A) := RK(B) + RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_SUB | YES | R(A) := RK(B) - RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_MUL | YES | R(A) := RK(B) * RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_MOD | NO | R(A) := RK(B) % RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_POW | NO | R(A) := RK(B) ^ RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_DIV | YES | R(A) := RK(B) / RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_IDIV | NO | R(A) := RK(B) // RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_BAND | NO | R(A) := RK(B) & RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_BOR | NO | R(A) := RK(B) | RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_BXOR | NO | R(A) := RK(B) ~ RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_SHL | NO | R(A) := RK(B) << RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_SHR | NO | R(A) := RK(B) >> RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_UNM | NO | R(A) := -R(B) |
+-------------------------+----------+--------------------------------------------------+
| OP_BNOT | NO | R(A) := ~R(B) |
+-------------------------+----------+--------------------------------------------------+
| OP_NOT | YES | R(A) := not R(B) |
+-------------------------+----------+--------------------------------------------------+
| OP_LEN | YES | R(A) := length of R(B) |
+-------------------------+----------+--------------------------------------------------+
| OP_CONCAT | YES | R(A) := R(B).. ... ..R(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_JMP | YES | c+=sBx; if (A) close all upvalues >= R(A - 1) |
+-------------------------+----------+--------------------------------------------------+
| OP_EQ | YES | if ((RK(B) == RK(C)) ~= A) then pc++ |
+-------------------------+----------+--------------------------------------------------+
| OP_LT | YES | if ((RK(B) < RK(C)) ~= A) then pc++ |
+-------------------------+----------+--------------------------------------------------+
| OP_LE | YES | if ((RK(B) <= RK(C)) ~= A) then pc++ |
+-------------------------+----------+--------------------------------------------------+
| OP_TEST | YES | if not (R(A) <=> C) then pc++ |
+-------------------------+----------+--------------------------------------------------+
| OP_TESTSET | YES | if (R(B) <=> C) then R(A) := R(B) else pc++ |
+-------------------------+----------+--------------------------------------------------+
| OP_CALL | YES | R(A), .. ,R(A+C-2) := R(A)(R(A+1), .. ,R(A+B-1)) |
+-------------------------+----------+--------------------------------------------------+
| OP_TAILCALL | YES | return R(A)(R(A+1), ... ,R(A+B-1)) |
| | | Compiled as OP_CALL so no tail call optimization |
+-------------------------+----------+--------------------------------------------------+
| OP_RETURN | YES | return R(A), ... ,R(A+B-2) (see note) |
+-------------------------+----------+--------------------------------------------------+
| OP_FORLOOP | NO | R(A)+=R(A+2); |
| | | if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) } |
+-------------------------+----------+--------------------------------------------------+
| OP_FORPREP | NO | R(A)-=R(A+2); pc+=sBx |
+-------------------------+----------+--------------------------------------------------+
| OP_TFORCALL | YES | R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); |
+-------------------------+----------+--------------------------------------------------+
| OP_TFORLOOP | YES | if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx } |
+-------------------------+----------+--------------------------------------------------+
| OP_SETLIST | YES | R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B |
+-------------------------+----------+--------------------------------------------------+
| OP_CLOSURE | YES | R(A) := closure(KPROTO[Bx]) |
+-------------------------+----------+--------------------------------------------------+
| OP_VARARG | YES | R(A), R(A+1), ..., R(A+B-2) = vararg |
+-------------------------+----------+--------------------------------------------------+
| OP_EXTRAARG | N/A | extra (larger) argument for previous opcode |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_NEWARRAYI | YES | R(A) := array of int |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_NEWARRAYF | YES | R(A) := array of float |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_LOADIZ | YES | R(A) := tointeger(0) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_LOADFZ | YES | R(A) := tonumber(0) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_ADDFF | YES | R(A) := RK(B) + RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_ADDFI | YES | R(A) := RK(B) + RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_ADDII | YES | R(A) := RK(B) + RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_SUBFF | YES | R(A) := RK(B) - RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_SUBFI | YES | R(A) := RK(B) - RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_SUBIF | YES | R(A) := RK(B) - RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_SUBII | YES | R(A) := RK(B) - RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_MULFF | YES | R(A) := RK(B) * RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_MULFI | YES | R(A) := RK(B) * RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_MULII | YES | R(A) := RK(B) * RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_DIVFF | YES | R(A) := RK(B) / RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_DIVFI | YES | R(A) := RK(B) / RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_DIVIF | YES | R(A) := RK(B) / RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_DIVII | YES | R(A) := RK(B) / RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_TOINT | YES | R(A) := toint(R(A)) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_TOFLT | YES | R(A) := tofloat(R(A)) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_TOARRAYI | YES | R(A) := to_arrayi(R(A)) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_TOARRAYF | YES | R(A) := to_arrayf(R(A)) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_MOVEI | YES | R(A) := R(B), check R(B) is integer |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_MOVEF | YES | R(A) := R(B), check R(B) is number |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_MOVEAI | YES | R(A) := R(B), check R(B) is array of integer |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_MOVEAF | YES | R(A) := R(B), check R(B) is array of numbers |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_GETTABLE_AI | YES | R(A) := R(B)[RK(C)] where R(B) is array of |
| | | integers and RK(C) is integer |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_GETTABLE_AF | YES | R(A) := R(B)[RK(C)] where R(B) is array of |
| | | numbers and RK(C) is integer |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_SETTABLE_AI | YES | R(A)[RK(B)] := RK(C) where RK(B) is an integer |
| | | R(A) is array of integers, and RK(C) is an int |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_SETTABLE_AF | YES | R(A)[RK(B)] := RK(C) where RK(B) is an integer |
| | | R(A) is array of numbers, and RK(C) is a number |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_FORLOOP_IP | YES | R(A)+=R(A+2); |
| | | if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) } |
| | | Specialization for integer step > 1 |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_FORPREP_IP | YES | R(A)-=R(A+2); pc+=sBx |
| | | Specialization for integer step > 1 |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_FORLOOP_I1 | YES | R(A)+=R(A+2); |
| | | if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) } |
| | | Specialization for integer step == 1 |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_FORPREP_I1 | YES | R(A)-=R(A+2); pc+=sBx |
| | | Specialization for integer step == 1 |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_SETUPVALI | NO | UpValue[B] := tointeger(R(A)) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_SETUPVALF | NO | UpValue[B] := tonumber(R(A)) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_SETUPVALAI | NO | UpValue[B] := toarrayint(R(A)) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_SETUPVALAF | NO | UpValue[B] := toarrayflt(R(A)) |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_SETTABLE_AII | YES | R(A)[RK(B)] := RK(C) where RK(B) is an integer |
| | | R(A) is array of integers, and RK(C) is an int |
| | | No conversion as input is known to be int |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_SETTABLE_AFF | YES | R(A)[RK(B)] := RK(C) where RK(B) is an integer |
| | | R(A) is array of numbers, and RK(C) is a number |
| | | No conversion as input is known to be float |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_BAND_II | NO | R(A) := RK(B) & RK(C), operands are int |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_BOR_II | NO | R(A) := RK(B) | RK(C), operands are int |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_BXOR_II | NO | R(A) := RK(B) ~ RK(C), operands are int |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_SHL_II | NO | R(A) := RK(B) << RK(C), operands are int |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_SHR_II | NO | R(A) := RK(B) >> RK(C), operands are int |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_BNOT_I | NO | R(A) := ~R(B), int operand |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_EQ_II | YES | if ((RK(B) == RK(C)) ~= A) then pc++ |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_EQ_FF | YES | if ((RK(B) == RK(C)) ~= A) then pc++ |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_LT_II | YES | if ((RK(B) < RK(C)) ~= A) then pc++ |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_LT_FF | YES | if ((RK(B) < RK(C)) ~= A) then pc++ |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_LE_II | YES | if ((RK(B) <= RK(C)) ~= A) then pc++ |
+-------------------------+----------+--------------------------------------------------+
| OP_RAVI_LE_FF | YES | if ((RK(B) <= RK(C)) ~= A) then pc++ |
+-------------------------+----------+--------------------------------------------------+
Ravi's libgccjit JIT compiler source
------------------------------------
The libgccjit JIT implementation is in following sources:
* ravijit.h - defines the JIT API
* ravi_gccjit.h - defines the types used by the code generator, and declares prototypes
* ravijit.cpp - basic JIT infrastructure and Ravi API definition
* ravi_gcctypes.c - contains JIT type definitions for Lua objects
* ravi_gcccodegen.c - JIT compiler - main driver for compiling Lua bytecodes
* ravi_gccload.c - implements OP_LOADK and OP_MOVE, and related operations, also OP_LOADBOOL
* ravi_gcccomp.c - implements OP_EQ, OP_LT, OP_LE, OP_TEST and OP_TESTSET.
* ravi_gccreturn.c - implements OP_RETURN
* ravi_gccforprep.c - implements OP_RAVI_FORPREP_I1 and OP_RAVI_FORPREP_IP
* ravi_gccforloop.c - implements OP_RAVI_FORLOOP_I1 and OP_RAVI_FORLOOP_IP
* ravi_gcctforcall.c - implements OP_TFORCALL and OP_TFORLOOP
* ravi_gccarith1.c - implements various type specialized arithmetic operations - these are Ravi extensions
* ravi_gccarith2.c - implements Lua opcodes such as OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_UNM
* ravi_gcccall.c - implements OP_CALL, OP_JMP
* ravi_gcctable.c - implements OP_GETTABLE, OP_SETTABLE and various other table operations, OP_SELF, and also upvalue operations
* ravi_gccrest.c - OP_CLOSURE, OP_VARARG, OP_CONCAT

@ -24,7 +24,7 @@ Features
* Type specific bytecodes to improve performance
* Compatibility with Lua 5.3 (see Compatibility section below)
* `LLVM <http://www.llvm.org/>`_ powered JIT compiler
* Additionally a `libgccjit <https://gcc.gnu.org/wiki/JIT>`_ based alternative JIT compiler is also available, although this is not currently being worked on
* Additionally a `libgccjit <https://gcc.gnu.org/wiki/JIT>`_ based alternative JIT compiler is also available (on a branch), although this is not currently being worked on
* LLVM bindings exposed in Lua
Recent Work
@ -50,8 +50,6 @@ The LLVM JIT compiler is functional. The Lua and Ravi bytecodes currently implem
Ravi also provides an `LLVM binding <http://the-ravi-programming-language.readthedocs.org/en/latest/llvm-bindings.html>`_; this is still work in progress so please check documentation for the latest status.
There is also a `libgccjit <http://the-ravi-programming-language.readthedocs.org/en/latest/ravi-jit-libgccjit.html>`_ based JIT implementation but this implementation is lagging behind the LLVM based implementation. Further development of this is currently not planned.
Ravi Extensions to Lua 5.3
==========================
@ -508,7 +506,7 @@ I test the build by running a modified version of Lua 5.3.3 test suite. These te
Roadmap
=======
* 2015 - Implemented JIT compilation using LLVM
* 2015 - Implemented libgccjit based alternative JIT
* 2015 - 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 - Main priorities are:

@ -1,382 +0,0 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
#include <ravi_gccjit.h>
// R(A) := -R(B), floating point
void ravi_emit_UNMF(ravi_function_def_t *def, int A, int B, int pc) {
(void)pc;
// Load pointer to base
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register_or_constant(def, B);
// rb->value_.n
gcc_jit_lvalue *lhs = ravi_emit_load_reg_n(def, rb);
// result = -rb->value_.n;
gcc_jit_rvalue *result = gcc_jit_context_new_unary_op(
def->function_context, NULL, GCC_JIT_UNARY_OP_MINUS,
def->ravi->types->lua_NumberT, gcc_jit_lvalue_as_rvalue(lhs));
ravi_emit_store_reg_n_withtype(def, result, ra);
}
// R(A) := -R(B), integer
void ravi_emit_UNMI(ravi_function_def_t *def, int A, int B, int pc) {
(void)pc;
// Load pointer to base
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register_or_constant(def, B);
// rb->value_.n
gcc_jit_lvalue *lhs = ravi_emit_load_reg_i(def, rb);
gcc_jit_rvalue *result = gcc_jit_context_new_unary_op(
def->function_context, NULL, GCC_JIT_UNARY_OP_MINUS,
def->ravi->types->lua_IntegerT, gcc_jit_lvalue_as_rvalue(lhs));
ravi_emit_store_reg_i_withtype(def, result, ra);
}
// R(A) := RK(B) + RK(C), all floating
void ravi_emit_ADDFF(ravi_function_def_t *def, int A, int B, int C, int pc) {
(void)pc;
// Load pointer to base
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register_or_constant(def, B);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
// rb->value_.n
gcc_jit_lvalue *lhs = ravi_emit_load_reg_n(def, rb);
// rc->value_.n
gcc_jit_lvalue *rhs = ravi_emit_load_reg_n(def, rc);
// result = rb->value_.n + rc->value_.n
gcc_jit_rvalue *result = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_PLUS,
def->ravi->types->lua_NumberT, gcc_jit_lvalue_as_rvalue(lhs),
gcc_jit_lvalue_as_rvalue(rhs));
// ra->value_.n = result
// ra->tt_ = LUA_TNUMFLT
ravi_emit_store_reg_n_withtype(def, result, ra);
}
// R(A) := RK(B) * RK(C), float*float
void ravi_emit_MULFF(ravi_function_def_t *def, int A, int B, int C, int pc) {
(void)pc;
// Load pointer to base
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register_or_constant(def, B);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
// rb->value_.n
gcc_jit_lvalue *lhs = ravi_emit_load_reg_n(def, rb);
// rc->value_.n
gcc_jit_lvalue *rhs = ravi_emit_load_reg_n(def, rc);
// result = rb->value_.n * rc->value_.n
gcc_jit_rvalue *result = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_MULT,
def->ravi->types->lua_NumberT, gcc_jit_lvalue_as_rvalue(lhs),
gcc_jit_lvalue_as_rvalue(rhs));
// ra->value_.n = result
// ra->tt_ = LUA_TNUMFLT
ravi_emit_store_reg_n_withtype(def, result, ra);
}
// R(A) := RK(B) - RK(C), float-float
void ravi_emit_SUBFF(ravi_function_def_t *def, int A, int B, int C, int pc) {
(void)pc;
// Load pointer to base
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register_or_constant(def, B);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
// rb->value_.n
gcc_jit_lvalue *lhs = ravi_emit_load_reg_n(def, rb);
// rc->value_.n
gcc_jit_lvalue *rhs = ravi_emit_load_reg_n(def, rc);
// result = rb->value_.n - rc->value_.n
gcc_jit_rvalue *result = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_MINUS,
def->ravi->types->lua_NumberT, gcc_jit_lvalue_as_rvalue(lhs),
gcc_jit_lvalue_as_rvalue(rhs));
// ra->value_.n = result
// ra->tt_ = LUA_TNUMFLT
ravi_emit_store_reg_n_withtype(def, result, ra);
}
// R(A) := RK(B) / RK(C), float/float
void ravi_emit_DIVFF(ravi_function_def_t *def, int A, int B, int C, int pc) {
(void)pc;
// Load pointer to base
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register_or_constant(def, B);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
// rb->value_.n
gcc_jit_lvalue *lhs = ravi_emit_load_reg_n(def, rb);
// rc->value_.n
gcc_jit_lvalue *rhs = ravi_emit_load_reg_n(def, rc);
// result = rb->value_.n / rc->value_.n
gcc_jit_rvalue *result = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_DIVIDE,
def->ravi->types->lua_NumberT, gcc_jit_lvalue_as_rvalue(lhs),
gcc_jit_lvalue_as_rvalue(rhs));
// ra->value_.n = result
// ra->tt_ = LUA_TNUMFLT
ravi_emit_store_reg_n_withtype(def, result, ra);
}
// R(A) := RK(B) + RK(C), float+int
void ravi_emit_ADDFI(ravi_function_def_t *def, int A, int B, int C, int pc) {
(void)pc;
// Load pointer to base
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register_or_constant(def, B);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
// rb->value_.n
gcc_jit_lvalue *lhs = ravi_emit_load_reg_n(def, rb);
// rc->value_.i
gcc_jit_lvalue *rhs = ravi_emit_load_reg_i(def, rc);
// result = rb->value_.n + (lua_number)rc->value_.i
gcc_jit_rvalue *result = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_PLUS,
def->ravi->types->lua_NumberT, gcc_jit_lvalue_as_rvalue(lhs),
gcc_jit_context_new_cast(def->function_context, NULL,
gcc_jit_lvalue_as_rvalue(rhs),
def->ravi->types->lua_NumberT));
// ra->value_.n = result
// ra->tt_ = LUA_TNUMFLT
ravi_emit_store_reg_n_withtype(def, result, ra);
}
// R(A) := RK(B) * RK(C), float*int
void ravi_emit_MULFI(ravi_function_def_t *def, int A, int B, int C, int pc) {
(void)pc;
// Load pointer to base
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register_or_constant(def, B);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
// rb->value_.n
gcc_jit_lvalue *lhs = ravi_emit_load_reg_n(def, rb);
// rc->value_.i
gcc_jit_lvalue *rhs = ravi_emit_load_reg_i(def, rc);
// result = rb->value_.n * (lua_number)rc->value_.i
gcc_jit_rvalue *result = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_MULT,
def->ravi->types->lua_NumberT, gcc_jit_lvalue_as_rvalue(lhs),
gcc_jit_context_new_cast(def->function_context, NULL,
gcc_jit_lvalue_as_rvalue(rhs),
def->ravi->types->lua_NumberT));
// ra->value_.n = result
// ra->tt_ = LUA_TNUMFLT
ravi_emit_store_reg_n_withtype(def, result, ra);
}
// R(A) := RK(B) - RK(C), float-int
void ravi_emit_SUBFI(ravi_function_def_t *def, int A, int B, int C, int pc) {
(void)pc;
// Load pointer to base
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register_or_constant(def, B);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
// rb->value_.n
gcc_jit_lvalue *lhs = ravi_emit_load_reg_n(def, rb);
// rc->value_.i
gcc_jit_lvalue *rhs = ravi_emit_load_reg_i(def, rc);
// result = rb->value_.n - (lua_number)rc->value_.i
gcc_jit_rvalue *result = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_MINUS,
def->ravi->types->lua_NumberT, gcc_jit_lvalue_as_rvalue(lhs),
gcc_jit_context_new_cast(def->function_context, NULL,
gcc_jit_lvalue_as_rvalue(rhs),
def->ravi->types->lua_NumberT));
// ra->value_.n = result
// ra->tt_ = LUA_TNUMFLT
ravi_emit_store_reg_n_withtype(def, result, ra);
}
// R(A) := RK(B) / RK(C), float/int
void ravi_emit_DIVFI(ravi_function_def_t *def, int A, int B, int C, int pc) {
(void)pc;
// Load pointer to base
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register_or_constant(def, B);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
// rb->value_.n
gcc_jit_lvalue *lhs = ravi_emit_load_reg_n(def, rb);
// rc->value_.i
gcc_jit_lvalue *rhs = ravi_emit_load_reg_i(def, rc);
// result = rb->value_.n / (lua_number)rc->value_.i
gcc_jit_rvalue *result = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_DIVIDE,
def->ravi->types->lua_NumberT, gcc_jit_lvalue_as_rvalue(lhs),
gcc_jit_context_new_cast(def->function_context, NULL,
gcc_jit_lvalue_as_rvalue(rhs),
def->ravi->types->lua_NumberT));
// ra->value_.n = result
// ra->tt_ = LUA_TNUMFLT
ravi_emit_store_reg_n_withtype(def, result, ra);
}
// R(A) := RK(B) - RK(C), int-float
void ravi_emit_SUBIF(ravi_function_def_t *def, int A, int B, int C, int pc) {
(void)pc;
// Load pointer to base
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register_or_constant(def, B);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
// rb->value_.i
gcc_jit_lvalue *lhs = ravi_emit_load_reg_i(def, rb);
// rc->value_.n
gcc_jit_lvalue *rhs = ravi_emit_load_reg_n(def, rc);
// result = (lua_Number) rb->value_.i - rc->value_.n
gcc_jit_rvalue *result = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_MINUS,
def->ravi->types->lua_NumberT,
gcc_jit_context_new_cast(def->function_context, NULL,
gcc_jit_lvalue_as_rvalue(lhs),
def->ravi->types->lua_NumberT),
gcc_jit_lvalue_as_rvalue(rhs));
// ra->value_.n = result
// ra->tt_ = LUA_TNUMFLT
ravi_emit_store_reg_n_withtype(def, result, ra);
}
// R(A) := RK(B) / RK(C), int/float
void ravi_emit_DIVIF(ravi_function_def_t *def, int A, int B, int C, int pc) {
(void)pc;
// Load pointer to base
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register_or_constant(def, B);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
// rb->value_.i
gcc_jit_lvalue *lhs = ravi_emit_load_reg_i(def, rb);
// rc->value_.n
gcc_jit_lvalue *rhs = ravi_emit_load_reg_n(def, rc);
// result = (lua_Number) rb->value_.i / rc->value_.n
gcc_jit_rvalue *result = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_DIVIDE,
def->ravi->types->lua_NumberT,
gcc_jit_context_new_cast(def->function_context, NULL,
gcc_jit_lvalue_as_rvalue(lhs),
def->ravi->types->lua_NumberT),
gcc_jit_lvalue_as_rvalue(rhs));
// ra->value_.n = result
// ra->tt_ = LUA_TNUMFLT
ravi_emit_store_reg_n_withtype(def, result, ra);
}
// R(A) := RK(B) + RK(C), int+int
void ravi_emit_ADDII(ravi_function_def_t *def, int A, int B, int C, int pc) {
(void)pc;
// Load pointer to base
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register_or_constant(def, B);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
// rb->value_.i
gcc_jit_lvalue *lhs = ravi_emit_load_reg_i(def, rb);
// rc->value_.i
gcc_jit_lvalue *rhs = ravi_emit_load_reg_i(def, rc);
// result = rb->value_.i + rc->value_.i
gcc_jit_rvalue *result = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_PLUS,
def->ravi->types->lua_IntegerT, gcc_jit_lvalue_as_rvalue(lhs),
gcc_jit_lvalue_as_rvalue(rhs));
// ra->value_.i = result
// ra->tt_ = LUA_TNUMINT
ravi_emit_store_reg_i_withtype(def, result, ra);
}
// R(A) := RK(B) * RK(C), int*int
void ravi_emit_MULII(ravi_function_def_t *def, int A, int B, int C, int pc) {
(void)pc;
// Load pointer to base
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register_or_constant(def, B);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
// rb->value_.i
gcc_jit_lvalue *lhs = ravi_emit_load_reg_i(def, rb);
// rc->value_.i
gcc_jit_lvalue *rhs = ravi_emit_load_reg_i(def, rc);
// result = rb->value_.i * rc->value_.i
gcc_jit_rvalue *result = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_MULT,
def->ravi->types->lua_IntegerT, gcc_jit_lvalue_as_rvalue(lhs),
gcc_jit_lvalue_as_rvalue(rhs));
// ra->value_.i = result
// ra->tt_ = LUA_TNUMINT
ravi_emit_store_reg_i_withtype(def, result, ra);
}
// R(A) := RK(B) - RK(C), int-int
void ravi_emit_SUBII(ravi_function_def_t *def, int A, int B, int C, int pc) {
(void)pc;
// Load pointer to base
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register_or_constant(def, B);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
// rb->value_.i
gcc_jit_lvalue *lhs = ravi_emit_load_reg_i(def, rb);
// rc->value_.i
gcc_jit_lvalue *rhs = ravi_emit_load_reg_i(def, rc);
// result = rb->value_.i - rc->value_.i
gcc_jit_rvalue *result = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_MINUS,
def->ravi->types->lua_IntegerT, gcc_jit_lvalue_as_rvalue(lhs),
gcc_jit_lvalue_as_rvalue(rhs));
// ra->value_.i = result
// ra->tt_ = LUA_TNUMINT
ravi_emit_store_reg_i_withtype(def, result, ra);
}
// R(A) := RK(B) / RK(C), int/int but result is float
void ravi_emit_DIVII(ravi_function_def_t *def, int A, int B, int C, int pc) {
(void)pc;
// Load pointer to base
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register_or_constant(def, B);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
// rb->value_.i
gcc_jit_lvalue *lhs = ravi_emit_load_reg_i(def, rb);
// rc->value_.i
gcc_jit_lvalue *rhs = ravi_emit_load_reg_i(def, rc);
// result = (lua_Number)rb->value_.i / (lua_Number)rc->value_.i
gcc_jit_rvalue *result = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_DIVIDE,
def->ravi->types->lua_IntegerT,
gcc_jit_context_new_cast(def->function_context, NULL,
gcc_jit_lvalue_as_rvalue(lhs),
def->ravi->types->lua_NumberT),
gcc_jit_context_new_cast(def->function_context, NULL,
gcc_jit_lvalue_as_rvalue(rhs),
def->ravi->types->lua_NumberT));
// ra->value_.i = result
// ra->tt_ = LUA_TNUMINT
ravi_emit_store_reg_i_withtype(def, result, ra);
}

@ -1,247 +0,0 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
#include <ravi_gccjit.h>
// OP_ADD, OP_SUB, OP_MUL and OP_DIV
void ravi_emit_ARITH(ravi_function_def_t *def, int A, int B, int C, OpCode op,
TMS tms, int pc) {
// TValue *rb = RKB(i);
// TValue *rc = RKC(i);
// lua_Number nb; lua_Number nc;
// if (ttisinteger(rb) && ttisinteger(rc)) {
// lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
// setivalue(ra, intop(+, ib, ic));
//}
// else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
// setfltvalue(ra, luai_numadd(L, nb, nc));
//}
// else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD)); }
gcc_jit_lvalue *nb = gcc_jit_function_new_local(
def->jit_function, NULL, def->ravi->types->lua_NumberT,
unique_name(def, "ARITH_nb", pc));
gcc_jit_lvalue *nc = gcc_jit_function_new_local(
def->jit_function, NULL, def->ravi->types->lua_NumberT,
unique_name(def, "ARITH_nc", pc));
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register_or_constant(def, B);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
gcc_jit_lvalue *rb_type = ravi_emit_load_type(def, rb);
gcc_jit_lvalue *rc_type = ravi_emit_load_type(def, rc);
gcc_jit_block *float_op = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "ARITH_float.op", pc));
gcc_jit_block *try_meta = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "ARITH_try_meta", pc));
gcc_jit_block *done_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "done", pc));
if (op != OP_DIV) {
gcc_jit_rvalue *cmp1 = ravi_emit_is_value_of_type(
def, gcc_jit_lvalue_as_rvalue(rb_type), LUA__TNUMINT);
gcc_jit_rvalue *cmp2 = ravi_emit_is_value_of_type(
def, gcc_jit_lvalue_as_rvalue(rc_type), LUA__TNUMINT);
gcc_jit_rvalue *andvalue = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_LOGICAL_AND,
def->ravi->types->C_boolT, cmp1, cmp2);
// Check if both RB and RC are integers
gcc_jit_block *then_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "ARITH_if_integer", pc));
gcc_jit_block *else_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "ARITH_if_not_integer", pc));
ravi_emit_conditional_branch(def, andvalue, then_block, else_block);
ravi_set_current_block(def, then_block);
// Both are integers
gcc_jit_lvalue *lhs = ravi_emit_load_reg_i(def, rb);
gcc_jit_lvalue *rhs = ravi_emit_load_reg_i(def, rc);
gcc_jit_rvalue *result = NULL;
switch (op) {
case OP_ADD:
result = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_PLUS,
def->ravi->types->lua_IntegerT, gcc_jit_lvalue_as_rvalue(lhs),
gcc_jit_lvalue_as_rvalue(rhs));
break;
case OP_SUB:
result = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_MINUS,
def->ravi->types->lua_IntegerT, gcc_jit_lvalue_as_rvalue(lhs),
gcc_jit_lvalue_as_rvalue(rhs));
break;
case OP_MUL:
result = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_MULT,
def->ravi->types->lua_IntegerT, gcc_jit_lvalue_as_rvalue(lhs),
gcc_jit_lvalue_as_rvalue(rhs));
break;
default:
lua_assert(0);
}
ravi_emit_store_reg_i_withtype(def, result, ra);
ravi_emit_branch(def, done_block);
// Not integer
ravi_set_current_block(def, else_block);
}
// Is RB a float?
gcc_jit_rvalue *cmp1 = ravi_emit_is_value_of_type(
def, gcc_jit_lvalue_as_rvalue(rb_type), LUA__TNUMFLT);
gcc_jit_block *convert_rb = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "ARITH_convert_rb", pc));
gcc_jit_block *test_rc = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "ARITH_test_rc", pc));
gcc_jit_block *load_rb = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "ARITH_load_rb", pc));
// If RB is floating then load RB, else convert RB
ravi_emit_conditional_branch(def, cmp1, load_rb, convert_rb);
// Convert RB
ravi_set_current_block(def, convert_rb);
// Call luaV_tonumber_()
gcc_jit_rvalue *rb_isnum =
ravi_function_call2_rvalue(def, def->ravi->types->luaV_tonumberT,
gcc_jit_lvalue_get_address(rb, NULL),
gcc_jit_lvalue_get_address(nb, NULL));
cmp1 = ravi_emit_comparison(def, GCC_JIT_COMPARISON_EQ, rb_isnum,
ravi_int_constant(def, 1));
// If not number then go to meta block
// Else proceed to test RC
ravi_emit_conditional_branch(def, cmp1, test_rc, try_meta);
ravi_set_current_block(def, load_rb);
// Copy RB to local nb
gcc_jit_lvalue *src = ravi_emit_load_reg_n(def, rb);
gcc_jit_block_add_assignment(def->current_block, NULL, nb,
gcc_jit_lvalue_as_rvalue(src));
ravi_emit_branch(def, test_rc);
ravi_set_current_block(def, test_rc);
// Is RC a float?
cmp1 = ravi_emit_is_value_of_type(def, gcc_jit_lvalue_as_rvalue(rc_type),
LUA__TNUMFLT);
gcc_jit_block *convert_rc = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "ARITH_convert_rc", pc));
gcc_jit_block *load_rc = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "ARITH_load_rc", pc));
// If RC is float load RC
// else try to convert RC
ravi_emit_conditional_branch(def, cmp1, load_rc, convert_rc);
ravi_set_current_block(def, convert_rc);
// Call luaV_tonumber_()
gcc_jit_rvalue *rc_isnum =
ravi_function_call2_rvalue(def, def->ravi->types->luaV_tonumberT,
gcc_jit_lvalue_get_address(rc, NULL),
gcc_jit_lvalue_get_address(nc, NULL));
cmp1 = ravi_emit_comparison(def, GCC_JIT_COMPARISON_EQ, rc_isnum,
ravi_int_constant(def, 1));
// If not number then go to meta block
// else both RB and RC float so go to op
ravi_emit_conditional_branch(def, cmp1, float_op, try_meta);
ravi_set_current_block(def, load_rc);
// Copy RC to local;
src = ravi_emit_load_reg_n(def, rc);
gcc_jit_block_add_assignment(def->current_block, NULL, nc,
gcc_jit_lvalue_as_rvalue(src));
ravi_emit_branch(def, float_op);
ravi_set_current_block(def, float_op);
gcc_jit_lvalue *lhs = nb;
gcc_jit_lvalue *rhs = nc;
gcc_jit_rvalue *result = NULL;
// Add and set RA
switch (op) {
case OP_ADD:
result = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_PLUS,
def->ravi->types->lua_NumberT, gcc_jit_lvalue_as_rvalue(lhs),
gcc_jit_lvalue_as_rvalue(rhs));
break;
case OP_SUB:
result = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_MINUS,
def->ravi->types->lua_NumberT, gcc_jit_lvalue_as_rvalue(lhs),
gcc_jit_lvalue_as_rvalue(rhs));
break;
case OP_MUL:
result = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_MULT,
def->ravi->types->lua_NumberT, gcc_jit_lvalue_as_rvalue(lhs),
gcc_jit_lvalue_as_rvalue(rhs));
break;
case OP_DIV:
result = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_DIVIDE,
def->ravi->types->lua_NumberT, gcc_jit_lvalue_as_rvalue(lhs),
gcc_jit_lvalue_as_rvalue(rhs));
break;
default:
lua_assert(0);
}
ravi_emit_store_reg_n_withtype(def, result, ra);
ravi_emit_branch(def, done_block);
// Neither integer nor float so try meta
ravi_set_current_block(def, try_meta);
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call5_rvalue(
def, def->ravi->types->luaT_trybinTMT,
gcc_jit_param_as_rvalue(def->L), gcc_jit_lvalue_get_address(rb, NULL),
gcc_jit_lvalue_get_address(rc, NULL),
gcc_jit_lvalue_get_address(ra, NULL), ravi_int_constant(def, tms)));
ravi_emit_branch(def, done_block);
ravi_set_current_block(def, done_block);
}

@ -1,170 +0,0 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
#include <ravi_gccjit.h>
#include <assert.h>
// OP_JMP
void ravi_emit_JMP(ravi_function_def_t *def, int A, int j, int pc) {
//#define dojump(ci,i,e)
// { int a = GETARG_A(i);
// if (a > 0) luaF_close(L, ci->u.l.base + a - 1);
// ci->u.l.savedpc += GETARG_sBx(i) + e; }
//
// dojump(ci, i, 0);
assert(def->jmp_targets[j]->jmp);
if (def->current_block_terminated) {
gcc_jit_block *jmp_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_JMP", pc));
ravi_set_current_block(def, jmp_block);
}
// ravi_debug_printf2(def, "OP_JMP(%d) jmp to %d\n", ravi_int_constant(def,
// pc+1), ravi_int_constant(def, j+1));
// if (a > 0) luaF_close(L, ci->u.l.base + a - 1);
if (A > 0) {
ravi_emit_load_base(def);
// base + a - 1
gcc_jit_lvalue *val = ravi_emit_get_register(def, A - 1);
// Call luaF_close
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call2_rvalue(def, def->ravi->types->luaF_closeT,
gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_get_address(val, NULL)));
}
ravi_emit_branch(def, def->jmp_targets[j]->jmp);
gcc_jit_block *block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_JMP_post", pc));
ravi_set_current_block(def, block);
}
// Handle OP_CALL
void ravi_emit_CALL(ravi_function_def_t *def, int A, int B, int C, int pc) {
// int nresults = c - 1;
// if (b != 0)
// L->top = ra + b; /* else previous instruction set top */
// int c = luaD_precall(L, ra, nresults); /* C or JITed function? */
// if (c) {
// if (c == 1 && nresults >= 0)
// L->top = ci->top; /* adjust results if C function */
// }
// else { /* Lua function */
// luaV_execute(L);
// }
ravi_emit_load_base(def);
// int nresults = c - 1;
int nresults = C - 1;
// if (b != 0)
if (B != 0) {
ravi_emit_set_L_top_toreg(def, A + B);
}
// luaD_precall() returns following
// 1 - C function called, results to be adjusted
// 2 - JITed Lua function called, no action
// 0 - Run interpreter on Lua function
// int c = luaD_precall(L, ra, nresults); /* C or JITed function? */
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_rvalue *nresults_const = gcc_jit_context_new_rvalue_from_int(
def->function_context, def->ravi->types->C_intT, nresults);
gcc_jit_rvalue *precall_result = ravi_function_call4_rvalue(
def, def->ravi->types->luaD_precallT, gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_get_address(ra, NULL), nresults_const,
ravi_int_constant(def, 1));
/* Need to save the result of the luaD_precall() so that we can do another
* check later on
*/
gcc_jit_lvalue *tmp_var = gcc_jit_function_new_local(
def->jit_function, NULL, def->ravi->types->C_intT,
unique_name(def, "OP_CALL_luaD_precall_result", pc));
gcc_jit_block_add_assignment(def->current_block, NULL, tmp_var,
precall_result);
gcc_jit_rvalue *zero_const = gcc_jit_context_new_rvalue_from_int(
def->function_context, def->ravi->types->C_intT, 0);
gcc_jit_rvalue *precall_bool =
ravi_emit_comparison(def, GCC_JIT_COMPARISON_EQ,
gcc_jit_lvalue_as_rvalue(tmp_var), zero_const);
gcc_jit_block *then_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_CALL_if_lua_function", pc));
gcc_jit_block *else_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_CALL_else_lua_function", pc));
gcc_jit_block *end_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_CALL_done", pc));
ravi_emit_conditional_branch(def, precall_bool, then_block, else_block);
ravi_set_current_block(def, then_block);
// Lua function, not compiled, so call luaV_execute
gcc_jit_rvalue *b = ravi_function_call1_rvalue(
def, def->ravi->types->luaV_executeT, gcc_jit_param_as_rvalue(def->L));
// If the return value is non zero then we need to refresh L->top = ci->top
gcc_jit_rvalue *b_not_zero = ravi_emit_comparison(
def, GCC_JIT_COMPARISON_NE, b, ravi_int_constant(def, 0));
gcc_jit_block *if_b_block = gcc_jit_function_new_block(
def->jit_function,
unique_name(def, "OP_CALL_if_luaV_execute_b_value", pc));
ravi_emit_conditional_branch(def, b_not_zero, if_b_block, else_block);
ravi_set_current_block(def, if_b_block);
ravi_emit_refresh_L_top(def);
ravi_emit_branch(def, end_block);
ravi_set_current_block(def, else_block);
if (nresults >= 0) {
// In case the precall returned 1 then a C function was
// called so we need to update L->top
// if (c == 1 && nresults >= 0)
// L->top = ci->top; /* adjust results if C function */
gcc_jit_rvalue *one_const = gcc_jit_context_new_rvalue_from_int(
def->function_context, def->ravi->types->C_intT, 1);
gcc_jit_rvalue *precall_C =
ravi_emit_comparison(def, GCC_JIT_COMPARISON_EQ,
gcc_jit_lvalue_as_rvalue(tmp_var), one_const);
gcc_jit_block *then1_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_CALL_if_C_function", pc));
ravi_emit_conditional_branch(def, precall_C, then1_block, end_block);
ravi_set_current_block(def, then1_block);
// L->top = ci->top; /* adjust results if C function */
ravi_emit_refresh_L_top(def);
}
ravi_emit_branch(def, end_block);
ravi_set_current_block(def, end_block);
}

File diff suppressed because it is too large Load Diff

@ -1,356 +0,0 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
#include <ravi_gccjit.h>
#include <assert.h>
// implements EQ, LE and LT - by using the supplied lua function to call.
void ravi_emit_EQ_LE_LT(ravi_function_def_t *def, int A, int B, int C, int j,
int jA, gcc_jit_function *callee, const char *opname,
OpCode opCode, int pc) {
// case OP_EQ: {
// TValue *rb = RKB(i);
// TValue *rc = RKC(i);
// Protect(
// if (cast_int(luaV_equalobj(L, rb, rc)) != GETARG_A(i))
// ci->u.l.savedpc++;
// else
// donextjump(ci);
// )
// } break;
// Load pointer to base
ravi_emit_load_base(def);
// Get pointer to register B
gcc_jit_lvalue *regB = ravi_emit_get_register_or_constant(def, B);
// Get pointer to register C
gcc_jit_lvalue *regC = ravi_emit_get_register_or_constant(def, C);
gcc_jit_rvalue *result = NULL;
switch (opCode) {
case OP_RAVI_LT_II:
case OP_RAVI_LE_II:
case OP_RAVI_EQ_II: {
gcc_jit_lvalue *p1 = ravi_emit_load_reg_i(def, regB);
gcc_jit_lvalue *p2 = ravi_emit_load_reg_i(def, regC);
switch (opCode) {
case OP_RAVI_EQ_II:
result = ravi_emit_comparison(def, GCC_JIT_COMPARISON_EQ,
gcc_jit_lvalue_as_rvalue(p1),
gcc_jit_lvalue_as_rvalue(p2));
break;
case OP_RAVI_LT_II:
result = ravi_emit_comparison(def, GCC_JIT_COMPARISON_LT,
gcc_jit_lvalue_as_rvalue(p1),
gcc_jit_lvalue_as_rvalue(p2));
break;
case OP_RAVI_LE_II:
result = ravi_emit_comparison(def, GCC_JIT_COMPARISON_LE,
gcc_jit_lvalue_as_rvalue(p1),
gcc_jit_lvalue_as_rvalue(p2));
break;
default:
assert(0);
}
result = gcc_jit_context_new_cast(def->function_context, NULL, result,
def->ravi->types->C_intT);
} break;
case OP_RAVI_LT_FF:
case OP_RAVI_LE_FF:
case OP_RAVI_EQ_FF: {
gcc_jit_lvalue *p1 = ravi_emit_load_reg_n(def, regB);
gcc_jit_lvalue *p2 = ravi_emit_load_reg_n(def, regC);
switch (opCode) {
case OP_RAVI_EQ_FF:
result = ravi_emit_comparison(def, GCC_JIT_COMPARISON_EQ,
gcc_jit_lvalue_as_rvalue(p1),
gcc_jit_lvalue_as_rvalue(p2));
break;
case OP_RAVI_LT_FF:
result = ravi_emit_comparison(def, GCC_JIT_COMPARISON_LT,
gcc_jit_lvalue_as_rvalue(p1),
gcc_jit_lvalue_as_rvalue(p2));
break;
case OP_RAVI_LE_FF:
result = ravi_emit_comparison(def, GCC_JIT_COMPARISON_LE,
gcc_jit_lvalue_as_rvalue(p1),
gcc_jit_lvalue_as_rvalue(p2));
break;
default:
assert(0);
}
result = gcc_jit_context_new_cast(def->function_context, NULL, result,
def->ravi->types->C_intT);
} break;
default:
// Call luaV_equalobj with register B and C
result =
ravi_function_call3_rvalue(def, callee, gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_get_address(regB, NULL),
gcc_jit_lvalue_get_address(regC, NULL));
}
// Test if result is equal to operand A
gcc_jit_rvalue *A_const = ravi_int_constant(def, A);
gcc_jit_rvalue *result_eq_A =
ravi_emit_comparison(def, GCC_JIT_COMPARISON_EQ, result, A_const);
// If result == A then we need to execute the next statement which is a jump
char temp[80];
snprintf(temp, sizeof temp, "%s_then", opname);
gcc_jit_block *then_block =
gcc_jit_function_new_block(def->jit_function, unique_name(def, temp, pc));
snprintf(temp, sizeof temp, "%s_else", opname);
gcc_jit_block *else_block =
gcc_jit_function_new_block(def->jit_function, unique_name(def, temp, pc));
ravi_emit_conditional_branch(def, result_eq_A, then_block, else_block);
ravi_set_current_block(def, then_block);
// if (a > 0) luaF_close(L, ci->u.l.base + a - 1);
if (jA > 0) {
// jA is the A operand of the Jump instruction
// Reload pointer to base as the call to luaV_equalobj() may
// have invoked a Lua function and as a result the stack may have
// been reallocated - so the previous base pointer could be stale
ravi_emit_load_base(def);
// base + a - 1
gcc_jit_lvalue *val = ravi_emit_get_register(def, jA - 1);
// Call luaF_close
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call2_rvalue(def, def->ravi->types->luaF_closeT,
gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_get_address(val, NULL)));
}
// Do the jump
ravi_emit_branch(def, def->jmp_targets[j]->jmp);
// Add the else block and make it current so that the next instruction flows
// here
ravi_set_current_block(def, else_block);
}
gcc_jit_rvalue *ravi_emit_boolean_testfalse(ravi_function_def_t *def,
gcc_jit_lvalue *reg, bool negate) {
// (isnil() || isbool() && b == 0)
gcc_jit_lvalue *var = gcc_jit_function_new_local(
def->jit_function, NULL, def->ravi->types->C_boolT,
unique_name(def, "isfalse", 0));
gcc_jit_lvalue *type = ravi_emit_load_type(def, reg);
// Test if type == LUA_TNIL (0)
gcc_jit_rvalue *isnil = ravi_emit_is_value_of_type(
def, gcc_jit_lvalue_as_rvalue(type), LUA__TNIL);
// Test if type == LUA_TBOOLEAN
gcc_jit_rvalue *isbool = ravi_emit_is_value_of_type(
def, gcc_jit_lvalue_as_rvalue(type), LUA__TBOOLEAN);
// Test if bool value == 0
gcc_jit_lvalue *bool_value = ravi_emit_load_reg_b(def, reg);
gcc_jit_rvalue *zero = gcc_jit_context_new_rvalue_from_int(
def->function_context, def->ravi->types->C_intT, 0);
gcc_jit_rvalue *boolzero = ravi_emit_comparison(
def, GCC_JIT_COMPARISON_EQ, gcc_jit_lvalue_as_rvalue(bool_value), zero);
// Test type == LUA_TBOOLEAN && bool value == 0
gcc_jit_rvalue *andvalue = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_LOGICAL_AND,
def->ravi->types->C_boolT, isbool, boolzero);
gcc_jit_rvalue *orvalue = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_LOGICAL_OR,
def->ravi->types->C_boolT, isnil, andvalue);
gcc_jit_block_add_assignment(def->current_block, NULL, var, orvalue);
gcc_jit_rvalue *result = NULL;
if (negate) {
result = gcc_jit_context_new_unary_op(
def->function_context, NULL, GCC_JIT_UNARY_OP_LOGICAL_NEGATE,
def->ravi->types->C_boolT, gcc_jit_lvalue_as_rvalue(var));
} else {
result = gcc_jit_lvalue_as_rvalue(var);
}
return result;
}
void ravi_emit_TEST(ravi_function_def_t *def, int A, int B, int C, int j,
int jA, int pc) {
// case OP_TEST: {
// if (GETARG_C(i) ? l_isfalse(ra) : !l_isfalse(ra))
// ci->u.l.savedpc++;
// else
// donextjump(ci);
// } break;
(void)B;
// if (C) {
// ravi_debug_printf3(def, "OP_TEST(%d C=1)) if (!reg(A=%d)) then skip next
// else jmp to %d\n", ravi_int_constant(def, pc+1),
// ravi_int_constant(def, A), ravi_int_constant(def,
// j+1));
// }
// else {
// ravi_debug_printf3(def, "OP_TEST(%d C=0) if (reg(A=%d)) then skip next
// else jmp to %d\n", ravi_int_constant(def, pc+1),
// ravi_int_constant(def, A), ravi_int_constant(def,
// j+1));
// }
// Load pointer to base
ravi_emit_load_base(def);
// Get pointer to register A
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
// v = C ? is_false(ra) : !is_false(ra)
gcc_jit_rvalue *v = C ? ravi_emit_boolean_testfalse(def, ra, false)
: ravi_emit_boolean_testfalse(def, ra, true);
// Test NOT v
gcc_jit_rvalue *result = gcc_jit_context_new_unary_op(
def->function_context, NULL, GCC_JIT_UNARY_OP_LOGICAL_NEGATE,
def->ravi->types->C_boolT, v);
// If !v then we need to execute the next statement which is a jump
gcc_jit_block *then_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_TEST_do_jmp", pc));
gcc_jit_block *else_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_TEST_do_skip", pc));
ravi_emit_conditional_branch(def, result, then_block, else_block);
ravi_set_current_block(def, then_block);
// if (a > 0) luaF_close(L, ci->u.l.base + a - 1);
if (jA > 0) {
// jA is the A operand of the Jump instruction
// base + a - 1
gcc_jit_lvalue *val = ravi_emit_get_register(def, jA - 1);
// Call luaF_close
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call2_rvalue(def, def->ravi->types->luaF_closeT,
gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_get_address(val, NULL)));
}
// Do the jump
ravi_emit_branch(def, def->jmp_targets[j]->jmp);
// Add the else block and make it current so that the next instruction flows
// here
ravi_set_current_block(def, else_block);
}
void ravi_emit_NOT(ravi_function_def_t *def, int A, int B, int pc) {
// case OP_NOT: {
// TValue *rb = RB(i);
// int res = l_isfalse(rb); /* next assignment may change this value */
// setbvalue(ra, res);
// } break;
(void)pc;
ravi_emit_load_base(def);
// Get pointer to register B
gcc_jit_lvalue *rb = ravi_emit_get_register(def, B);
gcc_jit_rvalue *v = ravi_emit_boolean_testfalse(def, rb, false);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
ravi_emit_store_reg_b_withtype(
def, gcc_jit_context_new_cast(def->function_context, NULL, v,
def->ravi->types->C_intT),
ra);
}
void ravi_emit_TESTSET(ravi_function_def_t *def, int A, int B, int C, int j,
int jA, int pc) {
// case OP_TESTSET: {
// TValue *rb = RB(i);
// if (GETARG_C(i) ? l_isfalse(rb) : !l_isfalse(rb))
// ci->u.l.savedpc++;
// else {
// setobjs2s(L, ra, rb);
// donextjump(ci);
// }
// } break;
(void)pc;
// Load pointer to base
ravi_emit_load_base(def);
// Get pointer to register B
gcc_jit_lvalue *rb = ravi_emit_get_register(def, B);
// v = C ? is_false(ra) : !is_false(ra)
gcc_jit_rvalue *v = C ? ravi_emit_boolean_testfalse(def, rb, false)
: ravi_emit_boolean_testfalse(def, rb, true);
// Test NOT v
gcc_jit_rvalue *result = gcc_jit_context_new_unary_op(
def->function_context, NULL, GCC_JIT_UNARY_OP_LOGICAL_NEGATE,
def->ravi->types->C_boolT, v);
// If !v then we need to execute the next statement which is a jump
gcc_jit_block *then_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_TESTSET_if_then", pc));
gcc_jit_block *else_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_TESTSET_if_else", pc));
ravi_emit_conditional_branch(def, result, then_block, else_block);
ravi_set_current_block(def, then_block);
// Get pointer to register A
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
ravi_emit_struct_assign(def, ra, rb);
// if (a > 0) luaF_close(L, ci->u.l.base + a - 1);
if (jA > 0) {
// jA is the A operand of the Jump instruction
// base + a - 1
gcc_jit_lvalue *val = ravi_emit_get_register(def, jA - 1);
// Call luaF_close
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call2_rvalue(def, def->ravi->types->luaF_closeT,
gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_get_address(val, NULL)));
}
// Do the jump
ravi_emit_branch(def, def->jmp_targets[j]->jmp);
// Add the else block and make it current so that the next instruction flows
// here
ravi_set_current_block(def, else_block);
}

@ -1,87 +0,0 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
#include <ravi_gccjit.h>
void ravi_emit_iFORLOOP(ravi_function_def_t *def, int A, int pc,
ravi_branch_def_t *b, int step_one) {
// lua_Integer step = ivalue(ra + 2);
// lua_Integer idx = ivalue(ra) + step; /* increment index */
// lua_Integer limit = ivalue(ra + 1);
// if (idx <= limit) {
// ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
// setivalue(ra, idx); /* update internal index... */
// setivalue(ra + 3, idx); /* ...and external index */
// }
// We are in b->jmp as this is already the current block
lua_assert(def->current_block == b->jmp);
// Create the done block
gcc_jit_block *exit_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "FORLOOP_I1_exit", 0));
gcc_jit_rvalue *new_idx;
if (!step_one) {
// lua_Integer step = ivalue(ra + 2);
new_idx = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_PLUS,
def->ravi->types->lua_IntegerT, gcc_jit_lvalue_as_rvalue(b->iidx),
gcc_jit_lvalue_as_rvalue(b->istep));
} else
new_idx = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_PLUS,
def->ravi->types->lua_IntegerT, gcc_jit_lvalue_as_rvalue(b->iidx),
gcc_jit_context_new_rvalue_from_int(def->function_context,
def->ravi->types->lua_IntegerT, 1));
// save new index
gcc_jit_block_add_assignment(def->current_block, NULL, b->iidx, new_idx);
// lua_Integer limit = ivalue(ra + 1);
// idx > limit?
gcc_jit_rvalue *new_idx_gt_limit = ravi_emit_comparison(
def, GCC_JIT_COMPARISON_GT, gcc_jit_lvalue_as_rvalue(b->iidx),
gcc_jit_lvalue_as_rvalue(b->ilimit));
// If idx > limit we are done
gcc_jit_block *update_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "FORLOOP_I1_updatei", 0));
ravi_emit_conditional_branch(def, new_idx_gt_limit, exit_block, update_block);
ravi_set_current_block(def, update_block);
// Load pointer to base
ravi_emit_load_base(def);
// setivalue(ra + 3, idx); /* ...and external index */
gcc_jit_lvalue *rvar = ravi_emit_get_register(def, A + 3);
ravi_emit_store_reg_i_withtype(def, gcc_jit_lvalue_as_rvalue(b->iidx), rvar);
// ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
ravi_emit_branch(def, def->jmp_targets[pc]->jmp);
ravi_set_current_block(def, exit_block);
}

@ -1,95 +0,0 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
#include <ravi_gccjit.h>
#include <assert.h>
void ravi_emit_iFORPREP(ravi_function_def_t *def, int A, int pc, int step_one) {
ravi_branch_def_t *forloop_target = def->jmp_targets[pc];
assert(forloop_target);
forloop_target->ilimit = gcc_jit_function_new_local(
def->jit_function, NULL, def->ravi->types->lua_IntegerT,
unique_name(def, "ilimit", 0));
if (!step_one) {
forloop_target->istep = gcc_jit_function_new_local(
def->jit_function, NULL, def->ravi->types->lua_IntegerT,
unique_name(def, "istep", 0));
}
forloop_target->iidx = gcc_jit_function_new_local(
def->jit_function, NULL, def->ravi->types->lua_IntegerT,
unique_name(def, "iidx", 0));
// lua_Integer initv = ivalue(init);
// setivalue(init, initv - ivalue(pstep));
// Load pointer to base
ravi_emit_load_base(def);
// TValue *init = ra;
// TValue *pstep = ra + 2;
gcc_jit_lvalue *init = ravi_emit_get_register(def, A);
gcc_jit_lvalue *plimit = ravi_emit_get_register(def, A + 1);
gcc_jit_lvalue *pstep = NULL;
if (!step_one)
pstep = ravi_emit_get_register(def, A + 2);
// Get ivalue(pstep)
gcc_jit_lvalue *limit_ivalue = ravi_emit_load_reg_i(def, plimit);
gcc_jit_lvalue *init_ivalue = ravi_emit_load_reg_i(def, init);
if (!step_one) {
// setivalue(init, initv - ivalue(pstep));
gcc_jit_lvalue *step_ivalue = ravi_emit_load_reg_i(def, pstep);
gcc_jit_rvalue *idx = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_MINUS,
def->ravi->types->lua_IntegerT, gcc_jit_lvalue_as_rvalue(init_ivalue),
gcc_jit_lvalue_as_rvalue(step_ivalue));
// Save idx
gcc_jit_block_add_assignment(def->current_block, NULL, forloop_target->iidx,
idx);
// Save step
gcc_jit_block_add_assignment(def->current_block, NULL,
forloop_target->istep,
gcc_jit_lvalue_as_rvalue(step_ivalue));
} else {
// setivalue(init, initv - ivalue(pstep));
gcc_jit_rvalue *idx = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_MINUS,
def->ravi->types->lua_IntegerT, gcc_jit_lvalue_as_rvalue(init_ivalue),
gcc_jit_context_new_rvalue_from_int(def->function_context,
def->ravi->types->lua_IntegerT, 1));
// Save idx
gcc_jit_block_add_assignment(def->current_block, NULL, forloop_target->iidx,
idx);
}
// Save limit
gcc_jit_block_add_assignment(def->current_block, NULL, forloop_target->ilimit,
gcc_jit_lvalue_as_rvalue(limit_ivalue));
// We are done so jump to forloop
lua_assert(def->jmp_targets[pc]->jmp);
ravi_emit_branch(def, def->jmp_targets[pc]->jmp);
}

@ -1,270 +0,0 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
#include <stddef.h>
#include "ravi_gccjit.h"
ravi_gcc_context_t *ravi_jit_new_context(void) {
ravi_gcc_context_t *ravi = NULL;
gcc_jit_context *gcc_ctx = gcc_jit_context_acquire();
if (!gcc_ctx) {
fprintf(stderr, "failed to allocate a GCC JIT context\n");
goto on_error;
}
ravi = (ravi_gcc_context_t *)calloc(1, sizeof(ravi_gcc_context_t));
if (!ravi) {
fprintf(stderr, "failed to allocate a Ravi JIT context\n");
goto on_error;
}
ravi->context = gcc_ctx;
ravi->auto_ = false;
ravi->enabled_ = true;
ravi->min_code_size_ = 150;
ravi->min_exec_count_ = 50;
ravi->opt_level_ = 3;
ravi->size_level_ = 0;
if (!ravi_setup_lua_types(ravi)) {
fprintf(stderr, "failed to setup types\n");
goto on_error;
}
ravi->parent_result_ = gcc_jit_context_compile(ravi->context);
if (gcc_jit_context_get_first_error(ravi->context)) {
fprintf(stderr, "aborting due to JIT error: %s\n",
gcc_jit_context_get_first_error(ravi->context));
abort();
}
return ravi;
on_error:
if (ravi) {
ravi_jit_context_free(ravi);
} else if (gcc_ctx) {
gcc_jit_context_release(gcc_ctx);
}
return NULL;
}
void ravi_jit_context_free(ravi_gcc_context_t *ravi) {
if (ravi == NULL)
return;
if (ravi->parent_result_) {
gcc_jit_result_release(ravi->parent_result_);
ravi->parent_result_ = NULL;
}
if (ravi->context) {
gcc_jit_context_release(ravi->context);
ravi->context = NULL;
}
if (ravi->types) {
free(ravi->types);
ravi->types = NULL;
}
free(ravi);
}
ravi_gcc_codegen_t *ravi_jit_new_codegen(ravi_gcc_context_t *ravi) {
ravi_gcc_codegen_t *cg = NULL;
cg = (ravi_gcc_codegen_t *)calloc(1, sizeof(ravi_gcc_codegen_t));
if (cg == NULL) {
fprintf(stderr, "error creating a new context: out of memory\n");
goto on_error;
}
cg->id = 1;
cg->temp[0] = 0;
cg->ravi = ravi;
return cg;
on_error:
if (cg)
ravi_jit_codegen_free(cg);
return NULL;
}
void ravi_jit_codegen_free(ravi_gcc_codegen_t *codegen) {
if (codegen == NULL)
return;
free(codegen);
}
bool ravi_jit_has_errored(ravi_gcc_context_t *ravi) {
const char *msg = gcc_jit_context_get_first_error(ravi->context);
if (msg) {
fprintf(stderr, "JIT error: %s\n", msg);
return true;
}
return false;
}
#include <ravi_jitshared.h>
// Initialize the JIT State and attach it to the
// Global Lua State
// If a JIT State already exists then this function
// will return -1
int raviV_initjit(struct lua_State *L) {
global_State *G = G(L);
if (G->ravi_state != NULL)
return -1;
ravi_State *jit = (ravi_State *)calloc(1, sizeof(ravi_State));
jit->jit = ravi_jit_new_context();
jit->code_generator = ravi_jit_new_codegen(jit->jit);
G->ravi_state = jit;
return 0;
}
// Free up the JIT State
void raviV_close(struct lua_State *L) {
global_State *G = G(L);
if (G->ravi_state == NULL)
return;
ravi_jit_codegen_free(G->ravi_state->code_generator);
ravi_jit_context_free(G->ravi_state->jit);
free(G->ravi_state);
}
// Dump the LLVM IR
void raviV_dumpIR(struct lua_State *L, struct Proto *p) {
(void)L;
(void)p;
}
// Dump the LLVM ASM
void raviV_dumpASM(struct lua_State *L, struct Proto *p) {
(void)L;
(void)p;
}
void raviV_setminexeccount(lua_State *L, int value) {
global_State *G = G(L);
if (!G->ravi_state)
return;
G->ravi_state->jit->min_exec_count_ = value;
}
int raviV_getminexeccount(lua_State *L) {
global_State *G = G(L);
if (!G->ravi_state)
return 0;
return G->ravi_state->jit->min_exec_count_;
}
void raviV_setmincodesize(lua_State *L, int value) {
global_State *G = G(L);
if (!G->ravi_state)
return;
G->ravi_state->jit->min_code_size_ = value;
}
int raviV_getmincodesize(lua_State *L) {
global_State *G = G(L);
if (!G->ravi_state)
return 0;
return G->ravi_state->jit->min_code_size_;
}
void raviV_setauto(lua_State *L, int value) {
global_State *G = G(L);
if (!G->ravi_state)
return;
G->ravi_state->jit->auto_ = value;
}
int raviV_getauto(lua_State *L) {
global_State *G = G(L);
if (!G->ravi_state)
return 0;
return G->ravi_state->jit->auto_;
}
// Turn on/off the JIT compiler
void raviV_setjitenabled(lua_State *L, int value) {
global_State *G = G(L);
if (!G->ravi_state)
return;
G->ravi_state->jit->enabled_ = value;
}
int raviV_getjitenabled(lua_State *L) {
global_State *G = G(L);
if (!G->ravi_state)
return 0;
return G->ravi_state->jit->enabled_;
}
void raviV_setoptlevel(lua_State *L, int value) {
global_State *G = G(L);
if (!G->ravi_state)
return;
G->ravi_state->jit->opt_level_ = value;
}
int raviV_getoptlevel(lua_State *L) {
global_State *G = G(L);
if (!G->ravi_state)
return 0;
return G->ravi_state->jit->opt_level_;
}
void raviV_setsizelevel(lua_State *L, int value) {
(void)L;
(void)value;
}
int raviV_getsizelevel(lua_State *L) {
(void)L;
return 0;
}
void raviV_setvalidation(lua_State *L, int value) {
(void)L;
(void)value;
}
int raviV_getvalidation(lua_State *L) {
(void)L;
return 0;
}
void raviV_setverbosity(lua_State *L, int value) {
(void)L;
(void)value;
}
int raviV_getverbosity(lua_State *L) {
(void)L;
return 0;
}
void raviV_setgcstep(lua_State *L, int value) {
(void)L;
(void)value;
}
int raviV_getgcstep(lua_State *L) {
(void)L;
return 0;
}
// Turn on/off the JIT compiler
void raviV_settraceenabled(lua_State *L, int value) {
(void)L;
(void)value;
}
int raviV_gettraceenabled(lua_State *L) {
(void)L;
return 0;
}

@ -1,467 +0,0 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
#include <ravi_gccjit.h>
// R(A+1), ..., R(A+B) := nil
void ravi_emit_LOADNIL(ravi_function_def_t *def, int A, int B, int pc) {
(void)pc;
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call3_rvalue(
def, def->ravi->types->raviV_op_loadnilT,
gcc_jit_lvalue_as_rvalue(def->ci_val),
gcc_jit_context_new_rvalue_from_int(def->function_context,
def->ravi->types->C_intT, A),
gcc_jit_context_new_rvalue_from_int(def->function_context,
def->ravi->types->C_intT, B)));
}
// R(A) := tonumber(0)
void ravi_emit_LOADFZ(ravi_function_def_t *def, int A, int pc) {
(void)pc;
// Load pointer to base
ravi_emit_load_base(def);
// ra
gcc_jit_lvalue *dest = ravi_emit_get_register(def, A);
// destvalue->value_.n = 0.0
ravi_emit_store_reg_n_withtype(
def, gcc_jit_context_new_rvalue_from_double(
def->function_context, def->ravi->types->lua_NumberT, 0.0),
dest);
}
// R(A) := tointeger(0)
void ravi_emit_LOADIZ(ravi_function_def_t *def, int A, int pc) {
(void)pc;
// Load pointer to base
ravi_emit_load_base(def);
// ra
gcc_jit_lvalue *dest = ravi_emit_get_register(def, A);
// destvalue->value_.i =
ravi_emit_store_reg_i_withtype(
def, gcc_jit_context_new_rvalue_from_int(
def->function_context, def->ravi->types->lua_IntegerT, 0),
dest);
}
void ravi_emit_LOADK(ravi_function_def_t *def, int A, int Bx, int pc) {
(void)pc;
// TValue *rb = k + GETARG_Bx(i);
// setobj2s(L, ra, rb);
// Load pointer to base
ravi_emit_load_base(def);
// ra
gcc_jit_lvalue *dest = ravi_emit_get_register(def, A);
#if 1
TValue *Konst = &def->p->k[Bx];
switch (Konst->tt_) {
case LUA_TNUMINT:
ravi_emit_store_reg_i_withtype(
def, gcc_jit_context_new_rvalue_from_int(def->function_context,
def->ravi->types->lua_IntegerT,
Konst->value_.i),
dest);
break;
case LUA_TNUMFLT:
ravi_emit_store_reg_n_withtype(def, gcc_jit_context_new_rvalue_from_double(
def->function_context,
def->ravi->types->lua_NumberT,
Konst->value_.n),
dest);
break;
case LUA_TBOOLEAN:
ravi_emit_store_reg_b_withtype(
def,
gcc_jit_context_new_rvalue_from_int(
def->function_context, def->ravi->types->C_intT, Konst->value_.b),
dest);
break;
default: {
#endif
// rb
gcc_jit_lvalue *src = ravi_emit_get_constant(def, Bx);
// *ra = *rb
ravi_emit_struct_assign(def, dest, src);
#if 1
}
}
#endif
}
// R(A) := R(B)
void ravi_emit_MOVE(ravi_function_def_t *def, int A, int B) {
// setobjs2s(L, ra, RB(i));
lua_assert(A != B);
// Load pointer to base
ravi_emit_load_base(def);
// rb
gcc_jit_lvalue *src = ravi_emit_get_register(def, B);
// ra
gcc_jit_lvalue *dest = ravi_emit_get_register(def, A);
// *ra = *rb
ravi_emit_struct_assign(def, dest, src);
}
// R(A) := (Bool)B; if (C) pc++
void ravi_emit_LOADBOOL(ravi_function_def_t *def, int A, int B, int C, int j,
int pc) {
// setbvalue(ra, GETARG_B(i));
// if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */
// ravi_debug_printf4(def, "LOADBOOL(pc=%d) set reg(A=%d) to boolean(B=%d);
// if ((C=%d) != 0) skip next\n", ravi_int_constant(def, pc+1),
// ravi_int_constant(def, A), ravi_int_constant(def, B),
// ravi_int_constant(def, C));
// Load pointer to base
ravi_emit_load_base(def);
// ra
gcc_jit_lvalue *dest = ravi_emit_get_register(def, A);
// dest->i = 0
ravi_emit_store_reg_b_withtype(
def, gcc_jit_context_new_rvalue_from_int(def->function_context,
def->ravi->types->C_intT, B),
dest);
if (C) {
// Skip next instruction if C
ravi_emit_branch(def, def->jmp_targets[j]->jmp);
gcc_jit_block *block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_LOADBOOL_skip_next", pc));
ravi_set_current_block(def, block);
}
}
// R(A) := R(B), check R(B) is int
void ravi_emit_MOVEI(ravi_function_def_t *def, int A, int B, int pc) {
// TValue *rb = RB(i);
// lua_Integer j;
// if (tointeger(rb, &j)) {
// setivalue(ra, j);
// }
// else
// luaG_runerror(L, "integer expected");
gcc_jit_lvalue *var = gcc_jit_function_new_local(
def->jit_function, NULL, def->ravi->types->lua_IntegerT,
unique_name(def, "OP_RAVI_MOVEI_i", pc));
// Load pointer to base
ravi_emit_load_base(def);
gcc_jit_lvalue *dest = ravi_emit_get_register(def, A);
gcc_jit_lvalue *src = ravi_emit_get_register(def, B);
gcc_jit_lvalue *src_type = ravi_emit_load_type(def, src);
// Compare src->tt == LUA_TNUMINT
gcc_jit_rvalue *cmp1 = ravi_emit_is_value_of_type(
def, gcc_jit_lvalue_as_rvalue(src_type), LUA__TNUMINT);
gcc_jit_block *then1 = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_RAVI_MOVEI_if_integer", pc));
gcc_jit_block *else1 = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_RAVI_MOVEI_if_not_integer", pc));
gcc_jit_block *end1 = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_RAVI_MOVEI_done", pc));
ravi_emit_conditional_branch(def, cmp1, then1, else1);
ravi_set_current_block(def, then1);
// Already a int - move
gcc_jit_lvalue *tmp = ravi_emit_load_reg_i(def, src);
gcc_jit_block_add_assignment(def->current_block, NULL, var,
gcc_jit_lvalue_as_rvalue(tmp));
ravi_emit_branch(def, end1);
// we need to convert
ravi_set_current_block(def, else1);
// Call luaV_tointeger_()
gcc_jit_rvalue *var_isint =
ravi_function_call2_rvalue(def, def->ravi->types->luaV_tointegerT,
gcc_jit_lvalue_get_address(src, NULL),
gcc_jit_lvalue_get_address(var, NULL));
gcc_jit_rvalue *zero = gcc_jit_context_new_rvalue_from_int(
def->function_context, def->ravi->types->C_intT, 0);
gcc_jit_rvalue *tobool =
ravi_emit_comparison(def, GCC_JIT_COMPARISON_EQ, var_isint, zero);
// Did conversion fail?
gcc_jit_block *else2 = gcc_jit_function_new_block(
def->jit_function,
unique_name(def, "OP_RAVI_MOVEI_if_conversion_failed", pc));
ravi_emit_conditional_branch(def, tobool, else2, end1);
// Conversion failed, so raise error
ravi_set_current_block(def, else2);
ravi_emit_raise_lua_error(def, "integer expected");
ravi_emit_branch(def, end1);
// Conversion OK
ravi_set_current_block(def, end1);
// Set R(A)
ravi_emit_store_reg_i_withtype(def, gcc_jit_lvalue_as_rvalue(var), dest);
}
void ravi_emit_MOVEF(ravi_function_def_t *def, int A, int B, int pc) {
// case OP_RAVI_MOVEF: {
// TValue *rb = RB(i);
// lua_Number j;
// if (tonumber(rb, &j)) {
// setfltvalue(ra, j);
// }
// else
// luaG_runerror(L, "float expected");
// } break;
gcc_jit_lvalue *var = gcc_jit_function_new_local(
def->jit_function, NULL, def->ravi->types->lua_NumberT,
unique_name(def, "OP_RAVI_MOVEF_n", pc));
// Load pointer to base
ravi_emit_load_base(def);
gcc_jit_lvalue *dest = ravi_emit_get_register(def, A);
gcc_jit_lvalue *src = ravi_emit_get_register(def, B);
gcc_jit_lvalue *src_type = ravi_emit_load_type(def, src);
// Compare src->tt == LUA_TNUMFLT
gcc_jit_rvalue *cmp1 = ravi_emit_is_value_of_type(
def, gcc_jit_lvalue_as_rvalue(src_type), LUA__TNUMFLT);
gcc_jit_block *then1 = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_RAVI_MOVEF_if_float", pc));
gcc_jit_block *else1 = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_RAVI_MOVEF_if_not_float", pc));
gcc_jit_block *end1 = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_RAVI_MOVEF_done", pc));
ravi_emit_conditional_branch(def, cmp1, then1, else1);
ravi_set_current_block(def, then1);
// Already a float - copy to var
gcc_jit_lvalue *tmp = ravi_emit_load_reg_n(def, src);
gcc_jit_block_add_assignment(def->current_block, NULL, var,
gcc_jit_lvalue_as_rvalue(tmp));
ravi_emit_branch(def, end1);
// we need to convert
ravi_set_current_block(def, else1);
// Call luaV_tonumber()
gcc_jit_rvalue *var_isflt =
ravi_function_call2_rvalue(def, def->ravi->types->luaV_tonumberT,
gcc_jit_lvalue_get_address(src, NULL),
gcc_jit_lvalue_get_address(var, NULL));
gcc_jit_rvalue *zero = gcc_jit_context_new_rvalue_from_int(
def->function_context, def->ravi->types->C_intT, 0);
gcc_jit_rvalue *tobool =
ravi_emit_comparison(def, GCC_JIT_COMPARISON_EQ, var_isflt, zero);
// Did conversion fail?
gcc_jit_block *else2 = gcc_jit_function_new_block(
def->jit_function,
unique_name(def, "OP_RAVI_MOVEF_if_conversion_failed", pc));
ravi_emit_conditional_branch(def, tobool, else2, end1);
// Conversion failed, so raise error
ravi_set_current_block(def, else2);
ravi_emit_raise_lua_error(def, "number expected");
ravi_emit_branch(def, end1);
// Conversion OK
ravi_set_current_block(def, end1);
// Set R(A)
ravi_emit_store_reg_n_withtype(def, gcc_jit_lvalue_as_rvalue(var), dest);
}
void ravi_emit_TOINT(ravi_function_def_t *def, int A, int pc) {
// case OP_RAVI_TOINT: {
// lua_Integer j;
// if (tointeger(ra, &j)) {
// setivalue(ra, j);
// }
// else
// luaG_runerror(L, "integer expected");
// } break;
gcc_jit_lvalue *var = gcc_jit_function_new_local(
def->jit_function, NULL, def->ravi->types->lua_IntegerT,
unique_name(def, "OP_RAVI_TOINT_i", pc));
// Load pointer to base
ravi_emit_load_base(def);
gcc_jit_lvalue *dest = ravi_emit_get_register(def, A);
gcc_jit_lvalue *src = dest;
gcc_jit_lvalue *src_type = ravi_emit_load_type(def, src);
// Is src->tt != LUA_TNUMINT?
gcc_jit_rvalue *cmp1 = ravi_emit_is_not_value_of_type(
def, gcc_jit_lvalue_as_rvalue(src_type), LUA__TNUMINT);
gcc_jit_block *then1 = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_RAVI_TOINT_if_not_integer", pc));
gcc_jit_block *end1 = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_RAVI_TOINT_done", pc));
ravi_emit_conditional_branch(def, cmp1, then1, end1);
ravi_set_current_block(def, then1);
// Call luaV_tointeger_()
gcc_jit_rvalue *var_isint =
ravi_function_call2_rvalue(def, def->ravi->types->luaV_tointegerT,
gcc_jit_lvalue_get_address(src, NULL),
gcc_jit_lvalue_get_address(var, NULL));
gcc_jit_rvalue *zero = gcc_jit_context_new_rvalue_from_int(
def->function_context, def->ravi->types->C_intT, 0);
gcc_jit_rvalue *failed_conversion =
ravi_emit_comparison(def, GCC_JIT_COMPARISON_EQ, var_isint, zero);
// Did conversion fail?
gcc_jit_block *then2 = gcc_jit_function_new_block(
def->jit_function,
unique_name(def, "OP_RAVI_TOINT_if_conversion_failed", pc));
gcc_jit_block *else2 = gcc_jit_function_new_block(
def->jit_function,
unique_name(def, "OP_RAVI_TOINT_if_conversion_ok", pc));
ravi_emit_conditional_branch(def, failed_conversion, then2, else2);
ravi_set_current_block(def, then2);
// Conversion failed, so raise error
ravi_emit_raise_lua_error(def, "integer expected");
ravi_emit_branch(def, else2);
// Conversion OK
ravi_set_current_block(def, else2);
ravi_emit_store_reg_i_withtype(def, gcc_jit_lvalue_as_rvalue(var), dest);
ravi_emit_branch(def, end1);
ravi_set_current_block(def, end1);
}
void ravi_emit_TOFLT(ravi_function_def_t *def, int A, int pc) {
// case OP_RAVI_TOFLT: {
// lua_Number j;
// if (tonumber(ra, &j)) {
// setfltvalue(ra, j);
// }
// else
// luaG_runerror(L, "float expected");
// } break;
gcc_jit_lvalue *var = gcc_jit_function_new_local(
def->jit_function, NULL, def->ravi->types->lua_NumberT,
unique_name(def, "OP_RAVI_TOFLT_n", pc));
// Load pointer to base
ravi_emit_load_base(def);
gcc_jit_lvalue *dest = ravi_emit_get_register(def, A);
gcc_jit_lvalue *src = dest;
gcc_jit_lvalue *src_type = ravi_emit_load_type(def, src);
// Is src->tt != LUA_TNUMFLT?
gcc_jit_rvalue *cmp1 = ravi_emit_is_not_value_of_type(
def, gcc_jit_lvalue_as_rvalue(src_type), LUA__TNUMFLT);
gcc_jit_block *then1 = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_RAVI_TOFLT_if_not_float", pc));
gcc_jit_block *end1 = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_RAVI_TOFLT_done", pc));
ravi_emit_conditional_branch(def, cmp1, then1, end1);
ravi_set_current_block(def, then1);
// Call luaV_tonumber()
gcc_jit_rvalue *var_ptr = gcc_jit_lvalue_get_address(var, NULL);
// ravi_debug_printf3(def, "number %p = %f before call to luaV_number\n",
// var_ptr, gcc_jit_lvalue_as_rvalue(var));
gcc_jit_rvalue *var_isflt = ravi_function_call2_rvalue(
def, def->ravi->types->luaV_tonumberT,
gcc_jit_lvalue_get_address(src, NULL), var_ptr);
gcc_jit_rvalue *zero = gcc_jit_context_new_rvalue_from_int(
def->function_context, def->ravi->types->C_intT, 0);
gcc_jit_rvalue *failed_conversion =
ravi_emit_comparison(def, GCC_JIT_COMPARISON_EQ, var_isflt, zero);
// Did conversion fail?
gcc_jit_block *then2 = gcc_jit_function_new_block(
def->jit_function,
unique_name(def, "OP_RAVI_TOFLT_if_conversion_failed", pc));
gcc_jit_block *else2 = gcc_jit_function_new_block(
def->jit_function,
unique_name(def, "OP_RAVI_TOFLT_if_conversion_ok", pc));
ravi_emit_conditional_branch(def, failed_conversion, then2, else2);
ravi_set_current_block(def, then2);
// Conversion failed, so raise error
ravi_emit_raise_lua_error(def, "number expected");
ravi_emit_branch(def, else2);
// Conversion OK
ravi_set_current_block(def, else2);
// ravi_debug_printf2(def, "number ok = %f\n", gcc_jit_lvalue_as_rvalue(var));
ravi_emit_store_reg_n_withtype(def, gcc_jit_lvalue_as_rvalue(var), dest);
ravi_emit_branch(def, end1);
ravi_set_current_block(def, end1);
}

@ -1,68 +0,0 @@
#include <ravi_gccjit.h>
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
void ravi_emit_CONCAT(ravi_function_def_t *def, int A, int B, int C, int pc) {
(void)pc;
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call5_rvalue(
def, def->ravi->types->raviV_op_concatT,
gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_as_rvalue(def->ci_val),
gcc_jit_context_new_rvalue_from_int(def->function_context,
def->ravi->types->C_intT, A),
gcc_jit_context_new_rvalue_from_int(def->function_context,
def->ravi->types->C_intT, B),
gcc_jit_context_new_rvalue_from_int(def->function_context,
def->ravi->types->C_intT, C)));
}
void ravi_emit_CLOSURE(ravi_function_def_t *def, int A, int Bx, int pc) {
(void)pc;
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call5_rvalue(
def, def->ravi->types->raviV_op_closureT,
gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_as_rvalue(def->ci_val), def->lua_closure,
gcc_jit_context_new_rvalue_from_int(def->function_context,
def->ravi->types->C_intT, A),
gcc_jit_context_new_rvalue_from_int(def->function_context,
def->ravi->types->C_intT, Bx)));
}
void ravi_emit_VARARG(ravi_function_def_t *def, int A, int B, int pc) {
(void)pc;
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call5_rvalue(
def, def->ravi->types->raviV_op_varargT,
gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_as_rvalue(def->ci_val), def->lua_closure,
gcc_jit_context_new_rvalue_from_int(def->function_context,
def->ravi->types->C_intT, A),
gcc_jit_context_new_rvalue_from_int(def->function_context,
def->ravi->types->C_intT, B)));
}

@ -1,103 +0,0 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
#include <ravi_gccjit.h>
void ravi_emit_RETURN(ravi_function_def_t *def, int A, int B, int pc) {
// Here is what OP_RETURN looks like. We only compile steps
// marked with //*. This is because the rest is only relevant in the
// interpreter
// case OP_RETURN: {
// int b = GETARG_B(i);
//* if (cl->p->sizep > 0) luaF_close(L, base);
//* b = luaD_poscall(L, ra, (b != 0 ? b - 1 : L->top - ra));
// if (!(ci->callstatus & CIST_REENTRY)) /* 'ci' still the called one */
// return; /* external invocation: return */
// else { /* invocation via reentry: continue execution */
// ci = L->ci;
// if (b) L->top = ci->top;
// goto newframe; /* restart luaV_execute over new Lua function */
// }
// }
// As Lua inserts redundant OP_RETURN instructions it is
// possible that this is one of them. If this is the case then the
// current block may already be terminated - so we have to insert
// a new block
if (def->current_block_terminated) {
gcc_jit_block *block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_RETURN", pc));
ravi_set_current_block(def, block);
}
// Load pointer to base
ravi_emit_load_base(def);
// Get pointer to register A
gcc_jit_lvalue *ra_ptr = ravi_emit_get_register(def, A);
// if (cl->p->sizep > 0) luaF_close(L, base);
// Get pointer to Proto->sizep
gcc_jit_lvalue *psize = ravi_emit_get_Proto_sizep(def);
// Test if psize > 0
gcc_jit_rvalue *psize_gt_0 = ravi_emit_comparison(
def, GCC_JIT_COMPARISON_GT, gcc_jit_lvalue_as_rvalue(psize),
gcc_jit_context_new_rvalue_from_int(def->function_context,
def->ravi->types->C_intT, 0));
gcc_jit_block *then_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_RETURN_if_sizep_gt_0", pc));
gcc_jit_block *else_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_RETURN_else_sizep_gt_0", pc));
ravi_emit_conditional_branch(def, psize_gt_0, then_block, else_block);
ravi_set_current_block(def, then_block);
gcc_jit_block_add_eval(def->current_block, NULL,
ravi_function_call2_rvalue(
def, def->ravi->types->luaF_closeT,
gcc_jit_param_as_rvalue(def->L), def->base_ref));
// gcc_jit_lvalue_as_rvalue(def->base)));
ravi_emit_branch(def, else_block);
ravi_set_current_block(def, else_block);
gcc_jit_rvalue *nresults = NULL;
if (B != 0)
nresults = ravi_int_constant(def, B - 1);
else
nresults = ravi_emit_num_stack_elements(
def, gcc_jit_lvalue_get_address(ra_ptr, NULL));
//* b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : L->top - ra));
gcc_jit_rvalue *b = ravi_function_call4_rvalue(
def, def->ravi->types->luaD_poscallT, gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_as_rvalue(def->ci_val),
gcc_jit_lvalue_get_address(ra_ptr, NULL), nresults);
gcc_jit_block_end_with_return(def->current_block, NULL, b);
def->current_block_terminated = true;
}

@ -1,577 +0,0 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
#include <ravi_gccjit.h>
#include <assert.h>
// R(A+1) := R(B); R(A) := R(B)[RK(C)]
void ravi_emit_SELF(ravi_function_def_t *def, int A, int B, int C, int pc) {
// StkId rb = RB(i);
// setobjs2s(L, ra + 1, rb);
// Protect(luaV_gettable(L, rb, RKC(i), ra));
(void)pc;
ravi_emit_load_base(def);
gcc_jit_lvalue *rb = ravi_emit_get_register(def, B);
gcc_jit_lvalue *ra1 = ravi_emit_get_register(def, A + 1);
ravi_emit_struct_assign(def, ra1, rb);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call4_rvalue(def, def->ravi->types->luaV_gettableT,
gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_get_address(rb, NULL),
gcc_jit_lvalue_get_address(rc, NULL),
gcc_jit_lvalue_get_address(ra, NULL)));
}
// R(A) := length of R(B)
void ravi_emit_LEN(ravi_function_def_t *def, int A, int B, int pc) {
// Protect(luaV_objlen(L, ra, RB(i)));
(void)pc;
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register(def, B);
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call3_rvalue(def, def->ravi->types->luaV_objlenT,
gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_get_address(ra, NULL),
gcc_jit_lvalue_get_address(rb, NULL)));
}
// R(A)[RK(B)] := RK(C)
void ravi_emit_SETTABLE(ravi_function_def_t *def, int A, int B, int C, int pc) {
// Protect(luaV_settable(L, ra, RKB(i), RKC(i)));
(void)pc;
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register_or_constant(def, B);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call4_rvalue(def, def->ravi->types->luaV_settableT,
gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_get_address(ra, NULL),
gcc_jit_lvalue_get_address(rb, NULL),
gcc_jit_lvalue_get_address(rc, NULL)));
}
// R(A) := R(B)[RK(C)]
void ravi_emit_GETTABLE(ravi_function_def_t *def, int A, int B, int C, int pc) {
// Protect(luaV_gettable(L, RB(i), RKC(i), ra));
(void)pc;
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register(def, B);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call4_rvalue(def, def->ravi->types->luaV_gettableT,
gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_get_address(rb, NULL),
gcc_jit_lvalue_get_address(rc, NULL),
gcc_jit_lvalue_get_address(ra, NULL)));
}
void ravi_emit_GETTABLE_AF(ravi_function_def_t *def, int A, int B, int C,
int pc, bool omitArrayGetRangeCheck) {
//#define raviH_get_float_inline(L, t, key, v)
//{ unsigned ukey = (unsigned)((key));
// lua_Number *data = (lua_Number *)t->ravi_array.data;
// if (ukey < t->ravi_array.len) {
// setfltvalue(v, data[ukey]);
// }else
// luaG_runerror(L, "array out of bounds");
//}
// TValue *rb = RB(i);
// TValue *rc = RKC(i);
// lua_Integer idx = ivalue(rc);
// Table *t = hvalue(rb);
// raviH_get_float_inline(L, t, idx, ra);
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register(def, B);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
gcc_jit_lvalue *key = ravi_emit_load_reg_i(def, rc);
gcc_jit_rvalue *t = ravi_emit_load_reg_h(def, rb);
gcc_jit_rvalue *data = ravi_emit_load_reg_h_floatarray(def, t);
gcc_jit_lvalue *len = ravi_emit_load_ravi_arraylength(def, t);
gcc_jit_rvalue *ukey = gcc_jit_context_new_cast(
def->function_context, NULL, gcc_jit_lvalue_as_rvalue(key),
def->ravi->types->lua_UnsignedT);
gcc_jit_block *then_block = NULL;
gcc_jit_block *else_block = NULL;
gcc_jit_block *end_block = NULL;
if (omitArrayGetRangeCheck) {
gcc_jit_rvalue *ulen = gcc_jit_context_new_cast(
def->function_context, NULL, gcc_jit_lvalue_as_rvalue(len),
def->ravi->types->lua_UnsignedT);
gcc_jit_rvalue *cmp =
ravi_emit_comparison(def, GCC_JIT_COMPARISON_LT, ukey, ulen);
then_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "GETTABLE_AF_if_in_range", pc));
else_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "GETTABLE_AF_if_not_in_range", pc));
end_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "GETTABLE_AF_if_end", pc));
ravi_emit_conditional_branch(def, cmp, then_block, else_block);
ravi_set_current_block(def, then_block);
}
gcc_jit_rvalue *value = ravi_emit_array_get(def, data, ukey);
ravi_emit_store_reg_n_withtype(def, value, ra);
if (omitArrayGetRangeCheck) {
ravi_emit_branch(def, end_block);
ravi_set_current_block(def, else_block);
ravi_emit_raise_lua_error(def, "array out of bounds");
ravi_emit_branch(def, end_block);
ravi_set_current_block(def, end_block);
}
}
void ravi_emit_GETTABLE_AI(ravi_function_def_t *def, int A, int B, int C,
int pc, bool omitArrayGetRangeCheck) {
//#define raviH_get_int_inline(L, t, key, v)
//{ unsigned ukey = (unsigned)((key));
// lua_Integer *data = (lua_Integer *)t->ravi_array.data;
// if (ukey < t->ravi_array.len) {
// setivalue(v, data[ukey]);
// } else
// luaG_runerror(L, "array out of bounds");
//}
// TValue *rb = RB(i);
// TValue *rc = RKC(i);
// lua_Integer idx = ivalue(rc);
// Table *t = hvalue(rb);
// raviH_get_int_inline(L, t, idx, ra);
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register(def, B);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
gcc_jit_lvalue *key = ravi_emit_load_reg_i(def, rc);
gcc_jit_rvalue *t = ravi_emit_load_reg_h(def, rb);
gcc_jit_rvalue *data = ravi_emit_load_reg_h_intarray(def, t);
gcc_jit_lvalue *len = ravi_emit_load_ravi_arraylength(def, t);
gcc_jit_rvalue *ukey = gcc_jit_context_new_cast(
def->function_context, NULL, gcc_jit_lvalue_as_rvalue(key),
def->ravi->types->lua_UnsignedT);
gcc_jit_block *then_block = NULL;
gcc_jit_block *else_block = NULL;
gcc_jit_block *end_block = NULL;
if (omitArrayGetRangeCheck) {
gcc_jit_rvalue *ulen = gcc_jit_context_new_cast(
def->function_context, NULL, gcc_jit_lvalue_as_rvalue(len),
def->ravi->types->lua_UnsignedT);
gcc_jit_rvalue *cmp =
ravi_emit_comparison(def, GCC_JIT_COMPARISON_LT, ukey, ulen);
then_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "GETTABLE_AI_if_in_range", pc));
else_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "GETTABLE_AI_if_not_in_range", pc));
end_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "GETTABLE_AI_if_end", pc));
ravi_emit_conditional_branch(def, cmp, then_block, else_block);
ravi_set_current_block(def, then_block);
}
gcc_jit_rvalue *value = ravi_emit_array_get(def, data, ukey);
ravi_emit_store_reg_i_withtype(def, value, ra);
if (omitArrayGetRangeCheck) {
ravi_emit_branch(def, end_block);
ravi_set_current_block(def, else_block);
ravi_emit_raise_lua_error(def, "array out of bounds");
ravi_emit_branch(def, end_block);
ravi_set_current_block(def, end_block);
}
}
void ravi_emit_SETTABLE_AI_AF(ravi_function_def_t *def, int A, int B, int C,
bool known_tt, lua_typecode_t tt, int pc) {
//#define raviH_set_int_inline(L, t, key, value)
//{ unsigned ukey = (unsigned)((key));
// lua_Integer *data = (lua_Integer *)t->ravi_array.data;
// if (ukey < t->ravi_array.len) {
// data[ukey] = value;
// } else
// raviH_set_int(L, t, ukey, value);
//}
// Table *t = hvalue(ra);
// TValue *rb = RKB(i);
// TValue *rc = RKC(i);
// lua_Integer idx = ivalue(rb);
// lua_Integer value = ivalue(rc);
// raviH_set_int_inline(L, t, idx, value);
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rb = ravi_emit_get_register_or_constant(def, B);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
gcc_jit_lvalue *key = ravi_emit_load_reg_i(def, rb);
gcc_jit_lvalue *value = NULL;
switch (tt) {
case LUA__TNUMINT:
value = known_tt ? ravi_emit_load_reg_i(def, rc)
: ravi_emit_tonumtype(def, rc, LUA__TNUMINT, pc);
break;
case LUA__TNUMFLT:
value = known_tt ? ravi_emit_load_reg_n(def, rc)
: ravi_emit_tonumtype(def, rc, LUA__TNUMFLT, pc);
break;
default:
assert(false);
abort();
}
gcc_jit_rvalue *t = ravi_emit_load_reg_h(def, ra);
gcc_jit_rvalue *data = NULL;
switch (tt) {
case LUA__TNUMINT:
data = ravi_emit_load_reg_h_intarray(def, t);
break;
case LUA__TNUMFLT:
data = ravi_emit_load_reg_h_floatarray(def, t);
break;
default:
assert(false);
abort();
}
gcc_jit_lvalue *len = ravi_emit_load_ravi_arraylength(def, t);
gcc_jit_rvalue *ukey = gcc_jit_context_new_cast(
def->function_context, NULL, gcc_jit_lvalue_as_rvalue(key),
def->ravi->types->lua_UnsignedT);
gcc_jit_rvalue *ulen = gcc_jit_context_new_cast(
def->function_context, NULL, gcc_jit_lvalue_as_rvalue(len),
def->ravi->types->lua_UnsignedT);
gcc_jit_rvalue *cmp =
ravi_emit_comparison(def, GCC_JIT_COMPARISON_LT, ukey, ulen);
gcc_jit_block *then_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "SETTABLE_AX_if_in_range", pc));
gcc_jit_block *else_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "SETTABLE_AX_if_not_in_range", pc));
gcc_jit_block *end_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "SETTABLE_AX_if_end", pc));
ravi_emit_conditional_branch(def, cmp, then_block, else_block);
ravi_set_current_block(def, then_block);
gcc_jit_lvalue *ptr = ravi_emit_array_get_ptr(def, data, ukey);
gcc_jit_block_add_assignment(def->current_block, NULL, ptr,
gcc_jit_lvalue_as_rvalue(value));
ravi_emit_branch(def, end_block);
ravi_set_current_block(def, else_block);
gcc_jit_function *f = NULL;
switch (tt) {
case LUA__TNUMINT:
f = def->ravi->types->raviH_set_intT;
break;
case LUA__TNUMFLT:
f = def->ravi->types->raviH_set_floatT;
break;
default:
assert(false);
abort();
}
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call4_rvalue(def, f, gcc_jit_param_as_rvalue(def->L), t,
ukey, gcc_jit_lvalue_as_rvalue(value)));
ravi_emit_branch(def, end_block);
ravi_set_current_block(def, end_block);
}
// R(A) := UpValue[B]
void ravi_emit_GETUPVAL(ravi_function_def_t *def, int A, int B, int pc) {
// int b = GETARG_B(i);
// setobj2s(L, ra, cl->upvals[b]->v);
(void)pc;
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_rvalue *upval = ravi_emit_get_upvals(def, B);
gcc_jit_lvalue *v = ravi_emit_load_upval_v(def, upval);
ravi_emit_struct_assign(
def, ra, gcc_jit_rvalue_dereference(gcc_jit_lvalue_as_rvalue(v), NULL));
}
// UpValue[B] := R(A)
void ravi_emit_SETUPVAL(ravi_function_def_t *def, int A, int B, int pc) {
#if 1
// Work around libgccjit compilation failure
// The inline version causes segmentation fault during compilation
(void)pc;
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call4_rvalue(def, def->ravi->types->raviV_op_setupvalT,
gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_as_rvalue(def->lua_closure_val),
gcc_jit_lvalue_get_address(ra, NULL),
ravi_int_constant(def, B)));
#else
// UpVal *uv = cl->upvals[GETARG_B(i)];
// setobj(L, uv->v, ra);
// luaC_upvalbarrier(L, uv);
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_rvalue *upval = ravi_emit_get_upvals(def, B);
gcc_jit_lvalue *v = ravi_emit_load_upval_v(def, upval);
ravi_emit_struct_assign(def, v, ra);
gcc_jit_lvalue *type = ravi_emit_load_type(def, v);
// (type & BIT_ISCOLLECTIBLE) != 0
gcc_jit_rvalue *bit_iscollectible = ravi_int_constant(def, BIT_ISCOLLECTABLE);
gcc_jit_rvalue *is_collectible_bit = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_BITWISE_AND,
def->ravi->types->C_intT, gcc_jit_lvalue_as_rvalue(type),
bit_iscollectible);
gcc_jit_rvalue *zero = ravi_int_constant(def, 0);
gcc_jit_rvalue *is_collectible = ravi_emit_comparison(
def, GCC_JIT_COMPARISON_NE, is_collectible_bit, zero);
// Is upvalue closed?
// (up->v == &up->u.value)
gcc_jit_lvalue *value = ravi_emit_load_upval_value(def, upval);
gcc_jit_rvalue *upisclosed = ravi_emit_comparison(
def, GCC_JIT_COMPARISON_EQ, gcc_jit_lvalue_as_rvalue(v),
gcc_jit_lvalue_get_address(value, NULL));
// Collectible type and upvalue is closed
// ((type & BIT_ISCOLLECTIBLE) != 0) && ((up)->v == &(up)->u.value))
gcc_jit_rvalue *andcond = gcc_jit_context_new_binary_op(
def->function_context, NULL, GCC_JIT_BINARY_OP_LOGICAL_AND,
def->ravi->types->C_boolT, is_collectible, upisclosed);
gcc_jit_block *then = gcc_jit_function_new_block(
def->jit_function,
unique_name(def, "SETUPVAL_if_collectible_and_upval_is_closed", pc));
gcc_jit_block *end = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "SETUPVAL_if_end", pc));
ravi_emit_conditional_branch(def, andcond, then, end);
ravi_set_current_block(def, then);
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call2_rvalue(def, def->ravi->types->luaC_upvalbarrierT,
gcc_jit_param_as_rvalue(def->L), upval));
ravi_emit_branch(def, end);
ravi_set_current_block(def, end);
#endif
}
// UpValue[A][RK(B)] := RK(C)
void ravi_emit_SETTABUP(ravi_function_def_t *def, int A, int B, int C, int pc) {
// int a = GETARG_A(i);
// Protect(luaV_settable(L, cl->upvals[a]->v, RKB(i), RKC(i)));
(void)pc;
ravi_emit_load_base(def);
gcc_jit_lvalue *rb = ravi_emit_get_register_or_constant(def, B);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
gcc_jit_rvalue *upval = ravi_emit_get_upvals(def, A);
gcc_jit_lvalue *v = ravi_emit_load_upval_v(def, upval);
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call4_rvalue(def, def->ravi->types->luaV_settableT,
gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_as_rvalue(v),
gcc_jit_lvalue_get_address(rb, NULL),
gcc_jit_lvalue_get_address(rc, NULL)));
}
// R(A) := UpValue[B][RK(C)]
void ravi_emit_GETTABUP(ravi_function_def_t *def, int A, int B, int C, int pc) {
// int b = GETARG_B(i);
// Protect(luaV_gettable(L, cl->upvals[b]->v, RKC(i), ra));
(void)pc;
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *rc = ravi_emit_get_register_or_constant(def, C);
gcc_jit_rvalue *upval = ravi_emit_get_upvals(def, B);
gcc_jit_lvalue *v = ravi_emit_load_upval_v(def, upval);
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call4_rvalue(def, def->ravi->types->luaV_gettableT,
gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_as_rvalue(v),
gcc_jit_lvalue_get_address(rc, NULL),
gcc_jit_lvalue_get_address(ra, NULL)));
}
void ravi_emit_NEWTABLE(ravi_function_def_t *def, int A, int B, int C, int pc) {
// case OP_NEWTABLE: {
// int b = GETARG_B(i);
// int c = GETARG_C(i);
// Table *t = luaH_new(L);
// sethvalue(L, ra, t);
// if (b != 0 || c != 0)
// luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c));
// checkGC(L, ra + 1);
// } break;
(void)pc;
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call5_rvalue(
def, def->ravi->types->raviV_op_newtableT,
gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_as_rvalue(def->ci_val),
gcc_jit_lvalue_get_address(ra, NULL),
gcc_jit_context_new_rvalue_from_int(def->function_context,
def->ravi->types->C_intT, B),
gcc_jit_context_new_rvalue_from_int(def->function_context,
def->ravi->types->C_intT, C)));
}
void ravi_emit_NEWARRAYINT(ravi_function_def_t *def, int A, int pc) {
(void)pc;
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call3_rvalue(def, def->ravi->types->raviV_op_newarrayintT,
gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_as_rvalue(def->ci_val),
gcc_jit_lvalue_get_address(ra, NULL)));
}
void ravi_emit_NEWARRAYFLOAT(ravi_function_def_t *def, int A, int pc) {
(void)pc;
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call3_rvalue(def, def->ravi->types->raviV_op_newarrayfloatT,
gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_as_rvalue(def->ci_val),
gcc_jit_lvalue_get_address(ra, NULL)));
}
void ravi_emit_SETLIST(ravi_function_def_t *def, int A, int B, int C, int pc) {
(void)pc;
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call5_rvalue(
def, def->ravi->types->raviV_op_setlistT,
gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_as_rvalue(def->ci_val),
gcc_jit_lvalue_get_address(ra, NULL),
gcc_jit_context_new_rvalue_from_int(def->function_context,
def->ravi->types->C_intT, B),
gcc_jit_context_new_rvalue_from_int(def->function_context,
def->ravi->types->C_intT, C)));
}
void ravi_emit_TOARRAY(ravi_function_def_t *def, int A, int array_type_expected,
const char *errmsg, int pc) {
// if (!ttistable(ra) || hvalue(ra)->ravi_array.type != RAVI_TARRAYINT)
// luaG_runerror(L, "integer[] expected");
OpCode op = OP_RAVI_TOTAB;
lua_typecode_t expected_type = RAVI__TLTABLE;
switch (array_type_expected) {
case RAVI_TARRAYINT:
op = OP_RAVI_TOARRAYI;
expected_type = RAVI__TIARRAY;
break;
case RAVI_TARRAYFLT:
op = OP_RAVI_TOARRAYF;
expected_type = RAVI__TFARRAY;
break;
case RAVI_TTABLE:
default: break;
}
ravi_emit_load_base(def);
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *type = ravi_emit_load_type(def, ra);
// type != expected_type ?
gcc_jit_rvalue *cmp1 = ravi_emit_is_not_value_of_type(
def, gcc_jit_lvalue_as_rvalue(type), expected_type);
gcc_jit_block *raise_error = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "TOARRAY_if_not_table", pc));
gcc_jit_block *done = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "TOARRAY_done", pc));
ravi_emit_conditional_branch(def, cmp1, raise_error, done);
ravi_set_current_block(def, raise_error);
// Conversion failed, so raise error
ravi_emit_raise_lua_error(def, errmsg);
ravi_emit_branch(def, done);
ravi_set_current_block(def, done);
}
void ravi_emit_MOVEAI(ravi_function_def_t *def, int A, int B, int pc) {
ravi_emit_TOARRAY(def, B, RAVI_TARRAYINT, "integer[] expected", pc);
gcc_jit_lvalue *src = ravi_emit_get_register(def, B);
gcc_jit_lvalue *dest = ravi_emit_get_register(def, A);
ravi_emit_struct_assign(def, dest, src);
}
void ravi_emit_MOVEAF(ravi_function_def_t *def, int A, int B, int pc) {
ravi_emit_TOARRAY(def, B, RAVI_TARRAYFLT, "number[] expected", pc);
gcc_jit_lvalue *src = ravi_emit_get_register(def, B);
gcc_jit_lvalue *dest = ravi_emit_get_register(def, A);
ravi_emit_struct_assign(def, dest, src);
}

@ -1,140 +0,0 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
#include <ravi_gccjit.h>
void ravi_emit_TFORCALL(ravi_function_def_t *def, int A, int B, int C, int j,
int jA, int pc) {
// case OP_TFORCALL: {
// StkId cb = ra + 3; /* call base */
// setobjs2s(L, cb + 2, ra + 2);
// setobjs2s(L, cb + 1, ra + 1);
// setobjs2s(L, cb, ra);
// L->top = cb + 3; /* func. + 2 args (state and index) */
// Protect(luaD_call(L, cb, GETARG_C(i), 1));
// L->top = ci->top;
// i = *(ci->u.l.savedpc++); /* go to next instruction */
// ra = RA(i);
// lua_assert(GET_OPCODE(i) == OP_TFORLOOP);
// goto l_tforloop;
// }
// case OP_TFORLOOP: {
// l_tforloop:
// if (!ttisnil(ra + 1)) { /* continue loop? */
// setobjs2s(L, ra, ra + 1); /* save control variable */
// ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
// }
// } break;
(void)B;
// Load pointer to base
ravi_emit_load_base(def);
// Get pointer to register A
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *ra1 = ravi_emit_get_register(def, A + 1);
gcc_jit_lvalue *ra2 = ravi_emit_get_register(def, A + 2);
gcc_jit_lvalue *cb = ravi_emit_get_register(def, A + 3);
gcc_jit_lvalue *cb1 = ravi_emit_get_register(def, A + 4);
gcc_jit_lvalue *cb2 = ravi_emit_get_register(def, A + 5);
ravi_emit_struct_assign(def, cb2, ra2);
ravi_emit_struct_assign(def, cb1, ra1);
ravi_emit_struct_assign(def, cb, ra);
// L->top = cb + 3; /* func. + 2 args (state and index) */
ravi_emit_set_L_top_toreg(def, A + 6);
// Protect(luaD_call(L, cb, GETARG_C(i)));
gcc_jit_block_add_eval(
def->current_block, NULL,
ravi_function_call3_rvalue(
def, def->ravi->types->luaD_callT, gcc_jit_param_as_rvalue(def->L),
gcc_jit_lvalue_get_address(cb, NULL),
gcc_jit_context_new_rvalue_from_int(def->function_context,
def->ravi->types->C_intT, C)));
// reload base
ravi_emit_load_base(def);
// L->top = ci->top;
ravi_emit_refresh_L_top(def);
ra = ravi_emit_get_register(def, jA);
ra1 = ravi_emit_get_register(def, jA + 1);
gcc_jit_lvalue *type = ravi_emit_load_type(def, ra1);
// Test if type != LUA_TNIL (0)
gcc_jit_rvalue *isnotnil = ravi_emit_is_not_value_of_type(
def, gcc_jit_lvalue_as_rvalue(type), LUA__TNIL);
gcc_jit_block *then_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_TFORCALL_if_not_nil", pc));
gcc_jit_block *else_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_TFORCALL_if_nil", pc));
ravi_emit_conditional_branch(def, isnotnil, then_block, else_block);
ravi_set_current_block(def, then_block);
ravi_emit_struct_assign(def, ra, ra1);
// Do the jump
ravi_emit_branch(def, def->jmp_targets[j]->jmp);
// Add the else block and make it current so that the next instruction flows
// here
ravi_set_current_block(def, else_block);
}
void ravi_emit_TFORLOOP(ravi_function_def_t *def, int A, int j, int pc) {
// case OP_TFORLOOP: {
// l_tforloop:
// if (!ttisnil(ra + 1)) { /* continue loop? */
// setobjs2s(L, ra, ra + 1); /* save control variable */
// ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
// }
// } break;
// Load pointer to base
ravi_emit_load_base(def);
// Get pointer to register A
gcc_jit_lvalue *ra = ravi_emit_get_register(def, A);
gcc_jit_lvalue *ra1 = ravi_emit_get_register(def, A + 1);
gcc_jit_lvalue *type = ravi_emit_load_type(def, ra1);
// Test if type != LUA_TNIL (0)
gcc_jit_rvalue *isnotnil = ravi_emit_is_not_value_of_type(
def, gcc_jit_lvalue_as_rvalue(type), LUA__TNIL);
gcc_jit_block *then_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_TFORLOOP_if_not_nil", pc));
gcc_jit_block *else_block = gcc_jit_function_new_block(
def->jit_function, unique_name(def, "OP_TFORLOOP_if_nil", pc));
ravi_emit_conditional_branch(def, isnotnil, then_block, else_block);
ravi_set_current_block(def, then_block);
ravi_emit_struct_assign(def, ra, ra1);
// Do the jump
ravi_emit_branch(def, def->jmp_targets[j]->jmp);
// Add the else block and make it current so that the next instruction flows
// here
ravi_set_current_block(def, else_block);
}

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save