issue #98 merge changes in master

pull/167/head
Dibyendu Majumdar 6 years ago
commit 24ac6f29f3

@ -69,7 +69,7 @@ PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
SortIncludes: true
SortIncludes: false
PointerAlignment: Left
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true

1
.gitignore vendored

@ -1,7 +1,6 @@
CMakeCache.txt
CMakeFiles
CMakeScripts
Makefile
cmake_install.cmake
install_manifest.txt
CTestTestfile.cmake

3
.gitmodules vendored

@ -0,0 +1,3 @@
[submodule "dmr_c"]
path = dmr_c
url = https://github.com/dibyendumajumdar/dmr_c.git

@ -3,28 +3,32 @@ project(Ravi)
enable_language(CXX)
enable_language(C)
enable_language(ASM)
enable_testing()
# Get access to CMake helpers
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
# By default LLVM JIT is ON, and GCC JIT is OFF
# Only one can be ON, and at last one of them must be ON
# 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(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)
option(LTESTS "Controls whether ltests are enabled in Debug mode" OFF)
if (LLVM_JIT)
set(ASM_VM OFF)
endif()
# 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")
if (ASM_VM)
# For now we switch to static build
# TODO A fix is needed to ensure that in shared library the asm functions are resolved
set(STATIC_BUILD ON)
set(LTESTS OFF)
endif()
if (STATIC_BUILD)
message(STATUS "STATIC library build enabled")
else()
message(STATUS "DYNAMIC library build enabled")
endif()
if (LLVM_JIT)
@ -35,20 +39,19 @@ if (LLVM_JIT)
include_directories(${LLVM_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})
add_definitions(-DUSE_LLVM)
endif()
if (GCC_JIT)
find_package(GCCJIT REQUIRED)
message(STATUS "Found GCCJIT")
# We also need to define USE_LLVM when compiling code
# but rather than setting globally we set this when building the
# library
endif()
include_directories(${GCCJIT_INCLUDE_DIRS})
add_definitions(-DUSE_GCCJIT)
message(STATUS "Computed goto ${COMPUTED_GOTO}")
if (COMPUTED_GOTO AND MSVC)
message(WARNING "Computed goto is not available with MSVC")
endif()
if (NOT LLVM_JIT AND NOT GCC_JIT)
message(WARNING "Neither LLVM nor gccjit will be enabled; specify -DLLVM_JIT or -DGCC_JIT to enable")
if (NOT LLVM_JIT)
message(WARNING "LLVM will not be enabled; specify -DLLVM_JIT=ON to enable")
endif()
if (MSVC)
@ -77,46 +80,83 @@ if (MSVC)
add_definitions("/wd4624")
add_definitions("/wd4141")
add_definitions("/DLUA_COMPAT_5_2")
endif ()
if (CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE)
add_definitions("/DLUA_COMPAT_5_1")
elseif ((CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") AND NOT APPLE)
if (NOT WIN32)
# assume Linux
set(CXX_OPTIONS -DLUA_USE_LINUX)
set(OS_FLAGS "-DLUA_USE_LINUX")
endif ()
# -fsanitize=bounds -fsanitize=alignment -fsanitize=object-size
set(SANITIZER_FLAGS "-fsanitize=address")
set(CMAKE_C_FLAGS "-std=c99 -O2 -fomit-frame-pointer -Wall -Wextra -Winline -DLUA_COMPAT_5_2 ${CXX_OPTIONS}")
set(CMAKE_C_FLAGS_DEBUG "${SANITIZER_FLAGS} -fno-omit-frame-pointer -std=c99 -O0 -g3 -Wall -Wextra -DLUA_COMPAT_5_2 ${CXX_OPTIONS}")
set(CMAKE_C_FLAGS_RELEASE "-std=c99 -O2 -fomit-frame-pointer -Wall -Wextra -Winline -DLUA_COMPAT_5_2 ${CXX_OPTIONS}")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${SANITIZER_FLAGS} -std=c99 -O1 -g3 -Wall -Wextra -DLUA_COMPAT_5_2 ${CXX_OPTIONS}")
set(CMAKE_CXX_FLAGS "-fno-rtti -O2 -fomit-frame-pointer -Wall -Wno-sign-compare -Winline -std=c++11 -fno-exceptions -DLUA_COMPAT_5_2 ${CXX_OPTIONS}")
set(CMAKE_CXX_FLAGS_RELEASE "-fno-rtti -O2 -fomit-frame-pointer -Wall -Wno-sign-compare -Winline -std=c++11 -fno-exceptions -DLUA_COMPAT_5_2 ${CXX_OPTIONS}")
set(CMAKE_CXX_FLAGS_DEBUG "${SANITIZER_FLAGS} -fno-omit-frame-pointer -fno-rtti -O0 -g3 -Wall -Wno-sign-compare -std=c++11 -fno-exceptions -DLUA_COMPAT_5_2 ${CXX_OPTIONS}")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${SANITIZER_FLAGS} -fno-rtti -O1 -g3 -Wall -Wno-sign-compare -std=c++11 -fno-exceptions -DLUA_COMPAT_5_2 ${CXX_OPTIONS}")
# In case we are using gcc 5.1 set ABI version
# add_definitions("-D_GLIBCXX_USE_CXX11_ABI=0")
endif ()
if (APPLE)
set(CMAKE_C_FLAGS "-std=c99 -O3 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX")
set(CMAKE_C_FLAGS_DEBUG "-std=c99 -O0 -g3 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX")
set(CMAKE_C_FLAGS_RELEASE "-std=c99 -O3 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-std=c99 -O1 -g3 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX")
set(CMAKE_CXX_FLAGS "-O3 -Wall -fno-rtti -Wno-sign-compare -std=c++11 -fno-exceptions -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX")
set(CMAKE_CXX_FLAGS_RELEASE "-fno-rtti -O3 -Wall -Wno-sign-compare -std=c++11 -fno-exceptions -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX")
set(CMAKE_CXX_FLAGS_DEBUG "-fno-rtti -O0 -g3 -Wall -Wno-sign-compare -std=c++11 -fno-exceptions -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-fno-rtti -O1 -g3 -Wall -Wno-sign-compare -std=c++11 -fno-exceptions -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX")
# set(SANITIZER_FLAGS "-fsanitize=address")
set(LUA_COMPAT_FLAGS "-DLUA_COMPAT_5_2 -DLUA_COMPAT_5_1")
set(CMAKE_C_FLAGS "-std=c99 -O2 -fomit-frame-pointer -Wall -Wextra -Winline ${LUA_COMPAT_FLAGS} ${OS_FLAGS}")
set(CMAKE_C_FLAGS_DEBUG "${SANITIZER_FLAGS} -fno-omit-frame-pointer -std=c99 -O0 -g3 -Wall -Wextra ${LUA_COMPAT_FLAGS} ${OS_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE "-std=c99 -O2 -fomit-frame-pointer -Wall -Wextra -Winline ${LUA_COMPAT_FLAGS} ${OS_FLAGS}")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${SANITIZER_FLAGS} -std=c99 -O1 -g3 -Wall -Wextra ${LUA_COMPAT_FLAGS} ${OS_FLAGS}")
set(CMAKE_CXX_FLAGS "-fno-rtti -O2 -fomit-frame-pointer -Wall -Wno-sign-compare -Winline -std=c++11 -fno-exceptions ${LUA_COMPAT_FLAGS} ${OS_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE "-fno-rtti -O2 -fomit-frame-pointer -Wall -Wno-sign-compare -Winline -std=c++11 -fno-exceptions ${LUA_COMPAT_FLAGS} ${OS_FLAGS}")
set(CMAKE_CXX_FLAGS_DEBUG "${SANITIZER_FLAGS} -fno-omit-frame-pointer -fno-rtti -O0 -g3 -Wall -Wno-sign-compare -std=c++11 -fno-exceptions ${LUA_COMPAT_FLAGS} ${OS_FLAGS}")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${SANITIZER_FLAGS} -fno-rtti -O1 -g3 -Wall -Wno-sign-compare -std=c++11 -fno-exceptions ${LUA_COMPAT_FLAGS} ${OS_FLAGS}")
elseif (APPLE)
set(LUA_COMPAT_FLAGS "-DLUA_COMPAT_5_2 -DLUA_COMPAT_5_1")
set(CMAKE_C_FLAGS "-std=c99 -O3 -Wall -Wextra ${LUA_COMPAT_FLAGS} -DLUA_USE_MACOSX")
set(CMAKE_C_FLAGS_DEBUG "-std=c99 -O0 -g3 -Wall -Wextra ${LUA_COMPAT_FLAGS} -DLUA_USE_MACOSX")
set(CMAKE_C_FLAGS_RELEASE "-std=c99 -O3 -Wall -Wextra ${LUA_COMPAT_FLAGS} -DLUA_USE_MACOSX")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-std=c99 -O1 -g3 -Wall -Wextra ${LUA_COMPAT_FLAGS} -DLUA_USE_MACOSX")
set(CMAKE_CXX_FLAGS "-O3 -Wall -fno-rtti -Wno-sign-compare -std=c++11 -fno-exceptions ${LUA_COMPAT_FLAGS} -DLUA_USE_MACOSX")
set(CMAKE_CXX_FLAGS_RELEASE "-fno-rtti -O3 -Wall -Wno-sign-compare -std=c++11 -fno-exceptions ${LUA_COMPAT_FLAGS} -DLUA_USE_MACOSX")
set(CMAKE_CXX_FLAGS_DEBUG "-fno-rtti -O0 -g3 -Wall -Wno-sign-compare -std=c++11 -fno-exceptions ${LUA_COMPAT_FLAGS} -DLUA_USE_MACOSX")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-fno-rtti -O1 -g3 -Wall -Wno-sign-compare -std=c++11 -fno-exceptions ${LUA_COMPAT_FLAGS} -DLUA_USE_MACOSX")
else()
message(FATAL_ERROR "Unsupported platform")
endif ()
include_directories("${PROJECT_SOURCE_DIR}/include")
add_definitions(-DLUA_COMPAT_MODULE)
if (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "DEBUG")
if ((CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "DEBUG") AND LTESTS AND NOT ASM_VM)
# Note that enabling ltests.h messes with global_State and thus interferes with ASM_VM
message(STATUS "Enabling Lua extended test harness 'ltests'")
add_definitions(-DLUA_USER_H="ltests.h")
endif ()
if (ASM_VM)
# For now we switch to static build
# TODO A fix is needed to ensure that in shared library the asm functions are resolved
add_definitions(-DRAVI_USE_ASMVM)
set ( ASMVM_DEFS ${PROJECT_SOURCE_DIR}/include/ravi_asmvm_defs.h )
if (WIN32 AND NOT CYGWIN)
set(VMMODE peobj)
elseif (APPLE)
set(VMMODE machasm)
else()
set(VMMODE elfasm)
endif()
# This macro runs the buildvm command to generate the VM code
macro(add_buildvm_target _target _mode)
add_custom_command(OUTPUT ${_target}
COMMAND ${PROJECT_SOURCE_DIR}/vmbuilder/bin/buildvm ARGS -m ${_mode} -o ${_target} ${ARGN}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${PROJECT_SOURCE_DIR}/vmbuilder/bin/buildvm ${ARGN}
)
endmacro(add_buildvm_target)
# Generate ravi_asmvm.obj / ravi_asmvm.s (obj on Windows)
if ( WIN32 AND NOT CYGWIN )
add_buildvm_target ( ${CMAKE_CURRENT_BINARY_DIR}/ravi_asmvm.obj ${VMMODE} )
set (ASMVM_SRC ${CMAKE_CURRENT_BINARY_DIR}/ravi_asmvm.obj)
else ()
add_buildvm_target ( ${CMAKE_CURRENT_BINARY_DIR}/ravi_asmvm.s ${VMMODE} )
set (ASMVM_SRC ${CMAKE_CURRENT_BINARY_DIR}/ravi_asmvm.s)
endif ()
# Generate the ravi_bcdef.h header file
add_buildvm_target ( ${ASMVM_DEFS} bcdef ${LJLIB_C} )
SET (ASMVM_DEPS
${ASMVM_SRC}
${ASMVM_DEFS}
)
endif()
# define LLVM JIT compiler sources
if (LLVM_JIT)
set(LLVM_JIT_SRCS src/ravi_llvmjit.cpp src/ravi_llvmtypes.cpp
@ -125,22 +165,22 @@ if (LLVM_JIT)
src/ravi_llvmarith1.cpp src/ravi_llvmcall.cpp src/ravi_llvmtable.cpp
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 (NOT LLVM_JIT AND NOT GCC_JIT)
else()
set(NO_JIT_SRCS src/ravi_nojit.c)
endif()
# define the lua core source files
set(LUA_CORE_SRCS src/lapi.c src/lcode.c src/lctype.c src/ldebug.c src/ldo.c src/ldump.c
src/lfunc.c src/lgc.c src/llex.c src/lmem.c src/lobject.c src/lopcodes.c
src/lparser.c src/lstate.c src/lstring.c src/ltable.c src/ltm.c src/lundump.c
src/lvm.c src/lzio.c src/ravijit.cpp src/ltests.c src/ravi_profile.c src/ravi_ast.c)
src/lvm.c src/lzio.c src/ravijit.cpp src/ltests.c src/ravi_profile.c src/ravi_ast.c src/ravi_membuf.c
src/ravi_jitshared.c src/bit.c)
if (COMPUTED_GOTO AND NOT MSVC)
if (CMAKE_C_COMPILER_ID MATCHES "Clang")
set_source_files_properties(src/lvm.c PROPERTIES COMPILE_FLAGS -DRAVI_USE_COMPUTED_GOTO)
elseif(CMAKE_C_COMPILER_ID MATCHES "GNU")
set_source_files_properties(src/lvm.c PROPERTIES COMPILE_FLAGS "-fno-crossjumping -fno-gcse -DRAVI_USE_COMPUTED_GOTO")
endif()
endif()
# define the lua lib source files
set(LUA_LIB_SRCS src/lauxlib.c src/lbaselib.c src/lbitlib.c src/lcorolib.c src/ldblib.c src/liolib.c
src/lmathlib.c src/loslib.c src/ltablib.c src/lstrlib.c src/loadlib.c src/linit.c src/lutf8lib.c)
@ -151,7 +191,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 ()
@ -162,12 +202,99 @@ elseif (NOT WIN32)
set(EXTRA_LIBRARIES m dl readline)
endif ()
if (EMBEDDED_DMRC)
if (CMAKE_COMPILER_IS_GNUCC)
execute_process(COMMAND ${CMAKE_C_COMPILER} --print-file-name=
OUTPUT_VARIABLE GCC_BASE OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND ${CMAKE_C_COMPILER} -print-multiarch
OUTPUT_VARIABLE MULTIARCH_TRIPLET ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
add_definitions(-DGCC_BASE="${GCC_BASE}")
add_definitions(-DMULTIARCH_TRIPLET="${MULTIARCH_TRIPLET}")
endif()
message( STATUS "GCC_BASE_DIR : " ${GCC_BASE})
message( STATUS "MULTIARCH_TRIPLET : " ${MULTIARCH_TRIPLET} )
include_directories("${PROJECT_SOURCE_DIR}/dmr_c/src")
set(DMR_C_HEADERS
dmr_c/src/allocate.h
dmr_c/src/char.h
dmr_c/src/expression.h
dmr_c/src/flow.h
dmr_c/src/ident-list.h
dmr_c/src/linearize.h
dmr_c/src/lib.h
dmr_c/src/parse.h
dmr_c/src/port.h
dmr_c/src/ptrlist.h
dmr_c/src/scope.h
dmr_c/src/symbol.h
dmr_c/src/target.h
dmr_c/src/token.h
dmr_c/src/walksymbol.h
)
set(DMR_C_SRCS
dmr_c/src/allocate.c
dmr_c/src/builtin.c
dmr_c/src/char.c
dmr_c/src/cse.c
dmr_c/src/expression.c
dmr_c/src/evaluate.c
dmr_c/src/expand.c
dmr_c/src/flow.c
dmr_c/src/inline.c
dmr_c/src/lib.c
dmr_c/src/linearize.c
dmr_c/src/liveness.c
dmr_c/src/memops.c
dmr_c/src/parse.c
dmr_c/src/target.c
dmr_c/src/tokenize.c
dmr_c/src/pre-process.c
dmr_c/src/ptrlist.c
dmr_c/src/scope.c
dmr_c/src/show-parse.c
dmr_c/src/simplify.c
dmr_c/src/symbol.c
dmr_c/src/unssa.c
dmr_c/src/walksymbol.c
src/ravi_dmrc_parsesymbols.c
)
if (LLVM_JIT)
set(DMR_C_JIT_SRCS
dmr_c/llvm-backend/sparse-llvm.c
)
set(DMR_C_JIT_HEADERS
dmr_c/llvm-backend/dmr_c.h
)
include_directories("${PROJECT_SOURCE_DIR}/dmr_c/llvm-backend")
else()
set(DMR_C_JIT_HEADERS
dmr_c/null-backend/dmr_c.h
)
include_directories("${PROJECT_SOURCE_DIR}/dmr_c/null-backend")
endif()
if (MSVC OR APPLE)
source_group("dmrC Headers" FILES ${DMR_C_HEADERS} ${DMR_C_JIT_HEADERS})
source_group("dmrC Source Files" FILES ${DMR_C_SRCS} ${DMR_C_JIT_SRCS})
endif()
endif()
# Enable minimal required LLVM components so that the
# the size of the resulting binary is manageable
if (LLVM_JIT)
if (${LLVM_PACKAGE_VERSION} VERSION_LESS "3.8")
set(LLVM_EXTRA_LIBS ipa)
endif()
if (NOT ${LLVM_PACKAGE_VERSION} VERSION_LESS "5.0.0")
set(LLVM_EXTRA_LIBS orcjit)
endif()
message(STATUS "SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR}")
if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)")
set(LLVM_LIBS_PROCESSOR
@ -191,11 +318,11 @@ if (LLVM_JIT)
endif()
llvm_map_components_to_libnames(LLVM_LIBS
Analysis
Core
CodeGen
AsmParser
AsmPrinter
BitReader
Core
CodeGen
ExecutionEngine
InstCombine
${LLVM_EXTRA_LIBS}
@ -209,7 +336,7 @@ if (LLVM_JIT)
Support
Target
TransformUtils
${LLVM_LIBS_PROCESSOR}
${LLVM_LIBS_PROCESSOR}
)
message(STATUS "LLVM_LIBS ${LLVM_LIBS}")
endif ()
@ -219,9 +346,7 @@ if (NOT STATIC_BUILD)
endif()
if (LLVM_JIT)
set (LIBRAVI_NAME libravillvm)
elseif (GCC_JIT)
set (LIBRAVI_NAME libravigccjit)
set (LIBRAVI_NAME libravillvm)
else()
set (LIBRAVI_NAME libravinojit)
endif()
@ -231,23 +356,75 @@ add_library(${LIBRAVI_NAME} ${LIBRAVI_BUILD_TYPE}
${RAVI_HEADERS}
${LUA_LIB_SRCS}
${LUA_CORE_SRCS}
${LLVM_JIT_SRCS}
${GCC_JIT_SRCS}
${NO_JIT_SRCS})
${LLVM_JIT_SRCS}
${NO_JIT_SRCS}
${DMR_C_HEADERS}
${DMR_C_SRCS}
${DMR_C_JIT_SRCS}
${ASMVM_DEPS}
)
if (NOT STATIC_BUILD)
if (WIN32)
# enable DLL export
set_target_properties(${LIBRAVI_NAME} PROPERTIES DEFINE_SYMBOL "LUA_BUILD_AS_DLL")
else()
else()
set_target_properties(${LIBRAVI_NAME} PROPERTIES PREFIX "")
endif ()
endif ()
endif()
if (LLVM_JIT)
set_target_properties(${LIBRAVI_NAME} PROPERTIES COMPILE_DEFINITIONS "USE_LLVM=1")
endif()
target_link_libraries(${LIBRAVI_NAME} ${EXTRA_LIBRARIES} ${LLVM_LIBS} ${GCCJIT_LIBRARIES})
if (EMBEDDED_DMRC)
set_target_properties(${LIBRAVI_NAME} PROPERTIES COMPILE_DEFINITIONS "USE_DMR_C=1")
endif()
target_link_libraries(${LIBRAVI_NAME} ${EXTRA_LIBRARIES} ${LLVM_LIBS})
# Ravi executable
# Main Ravi executable
add_executable(ravi src/lua.c)
if (LLVM_JIT)
set_target_properties(ravi PROPERTIES COMPILE_DEFINITIONS "USE_LLVM=1")
endif()
if (EMBEDDED_DMRC)
set_target_properties(ravi PROPERTIES COMPILE_DEFINITIONS "USE_DMR_C=1")
endif()
target_link_libraries(ravi ${LIBRAVI_NAME})
# Sources that are needed for a static NOJIT basic library
set(NOJIT_RAVI_SRCS
${RAVI_HEADERS}
${LUA_LIB_SRCS}
${LUA_CORE_SRCS}
src/ravi_nojit.c)
# We always build a static library without JIT so that
# we can create some default executables
add_library(libravinojit_static
${NOJIT_RAVI_SRCS})
set_target_properties(libravinojit_static PROPERTIES PREFIX "") # As we already prefix with lib
target_link_libraries(libravinojit_static ${EXTRA_LIBRARIES})
# Create a simple NoJIT version of statically linked ravi
# This is sometimes useful in other projects that just need a Lua commandline
# but do not care about the shared library
add_executable(ravi_s
src/lua.c)
target_link_libraries(ravi_s libravinojit_static)
# Ravi VSCode Debug adapter
set(RAVI_DEBUGGER_TARGET ravidebug)
add_executable(${RAVI_DEBUGGER_TARGET}
vscode-debugger/src/ravidebug.c
vscode-debugger/src/json.c
vscode-debugger/src/protocol.c)
target_link_libraries(${RAVI_DEBUGGER_TARGET} libravinojit_static)
# Tests for VSCode Debug Adapter
add_executable(testravidebug
vscode-debugger/src/testravidebug.c
vscode-debugger/src/json.c
vscode-debugger/src/protocol.c)
target_link_libraries(testravidebug libravinojit_static)
# Simple VM tests
add_executable(test_vm tests/test_vm.c)
target_link_libraries(test_vm ${LIBRAVI_NAME})
@ -259,11 +436,13 @@ target_link_libraries(test_ast ${LIBRAVI_NAME})
if (LLVM_JIT)
# LLVM playground
add_executable(test_llvm tests/test_llvm.cpp)
set_target_properties(test_llvm PROPERTIES COMPILE_DEFINITIONS "USE_LLVM=1")
target_link_libraries(test_llvm ${LIBRAVI_NAME})
endif ()
add_executable(test_misc tests/test_misc.c)
add_test(TestRaviDebug testravidebug)
if (LLVM_JIT)
add_test(TestLLVM test_llvm)
endif ()
@ -271,27 +450,10 @@ add_test(TestVM test_vm)
add_test(TestMisc test_misc)
add_test(TestAST test_ast)
# Build VSCode Debug Adapter for Ravi
if (STATIC_BUILD AND NOT GCC_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})
add_test(TestRaviDebug testravidebug)
if (LLVM_JIT)
set(RAVI_DEBUGGER_TARGET ravidebugllvm)
else()
set(RAVI_DEBUGGER_TARGET ravidebug)
endif()
# Ravi VSCode Debug adapter
add_executable(${RAVI_DEBUGGER_TARGET} vscode-debugger/src/ravidebug.c vscode-debugger/src/json.c vscode-debugger/src/protocol.c)
target_link_libraries(${RAVI_DEBUGGER_TARGET} ${LIBRAVI_NAME})
endif()
install(FILES ${LUA_HEADERS}
DESTINATION include/ravi)
install(TARGETS ${LIBRAVI_NAME} ravi ${RAVI_DEBUGGER_TARGET}
install(TARGETS ${LIBRAVI_NAME} ravi ${RAVI_DEBUGGER_TARGET} ravi_s
RUNTIME DESTINATION bin
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib)

@ -0,0 +1,116 @@
# The preferred build method for Ravi is to use CMake
# However if you want a quick build without JIT or other options then this
# Makefile might be adequate. It is based off the standard Lua Makefile
#
# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================
# Your platform. See PLATS for possible values.
PLAT= none
# Where to install. The installation starts in the src and doc directories,
# so take care if INSTALL_TOP is not an absolute path. See the local target.
# You may want to make INSTALL_LMOD and INSTALL_CMOD consistent with
# LUA_ROOT, LUA_LDIR, and LUA_CDIR in luaconf.h.
INSTALL_TOP= /usr/local
INSTALL_BIN= $(INSTALL_TOP)/bin
INSTALL_INC= $(INSTALL_TOP)/include/ravi
INSTALL_LIB= $(INSTALL_TOP)/lib
#INSTALL_MAN= $(INSTALL_TOP)/man/man1
INSTALL_LMOD= $(INSTALL_TOP)/share/lua/$V
INSTALL_CMOD= $(INSTALL_TOP)/lib/lua/$V
# How to install. If your install program does not support "-p", then
# you may have to run ranlib on the installed liblua.a.
INSTALL= install -p
INSTALL_EXEC= $(INSTALL) -m 0755
INSTALL_DATA= $(INSTALL) -m 0644
#
# If you don't have "install" you can use "cp" instead.
# INSTALL= cp -p
# INSTALL_EXEC= $(INSTALL)
# INSTALL_DATA= $(INSTALL)
# Other utilities.
MKDIR= mkdir -p
RM= rm -f
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
# Convenience platforms targets.
PLATS= aix bsd c89 freebsd generic linux macosx mingw posix solaris
# What to install.
TO_BIN= ravi
TO_INC= lua.h luaconf.h lualib.h lauxlib.h lua.hpp
TO_LIB= libravinojit.a
#TO_MAN= lua.1 luac.1
# Lua version and release.
V= 5.3
R= $V.4
# Targets start here.
all: $(PLAT)
$(PLATS) clean:
cd src && $(MAKE) $@
test: dummy
src/ravi -v
install: dummy
cd src && $(MKDIR) $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) $(INSTALL_LMOD) $(INSTALL_CMOD)
cd src && $(INSTALL_EXEC) $(TO_BIN) $(INSTALL_BIN)
cd src && $(INSTALL_DATA) $(TO_INC) $(INSTALL_INC)
cd src && $(INSTALL_DATA) $(TO_LIB) $(INSTALL_LIB)
# cd doc && $(INSTALL_DATA) $(TO_MAN) $(INSTALL_MAN)
uninstall:
cd src && cd $(INSTALL_BIN) && $(RM) $(TO_BIN)
cd src && cd $(INSTALL_INC) && $(RM) $(TO_INC)
cd src && cd $(INSTALL_LIB) && $(RM) $(TO_LIB)
# cd doc && cd $(INSTALL_MAN) && $(RM) $(TO_MAN)
local:
$(MAKE) install INSTALL_TOP=../install
none:
@echo "Please do 'make PLATFORM' where PLATFORM is one of these:"
@echo " $(PLATS)"
@echo "See doc/readme.html for complete instructions."
# make may get confused with test/ and install/
dummy:
# echo config parameters
echo:
@cd src && $(MAKE) -s echo
@echo "PLAT= $(PLAT)"
@echo "V= $V"
@echo "R= $R"
@echo "TO_BIN= $(TO_BIN)"
@echo "TO_INC= $(TO_INC)"
@echo "TO_LIB= $(TO_LIB)"
# @echo "TO_MAN= $(TO_MAN)"
@echo "INSTALL_TOP= $(INSTALL_TOP)"
@echo "INSTALL_BIN= $(INSTALL_BIN)"
@echo "INSTALL_INC= $(INSTALL_INC)"
@echo "INSTALL_LIB= $(INSTALL_LIB)"
# @echo "INSTALL_MAN= $(INSTALL_MAN)"
@echo "INSTALL_LMOD= $(INSTALL_LMOD)"
@echo "INSTALL_CMOD= $(INSTALL_CMOD)"
@echo "INSTALL_EXEC= $(INSTALL_EXEC)"
@echo "INSTALL_DATA= $(INSTALL_DATA)"
# echo pkg-config data
pc:
@echo "version=$R"
@echo "prefix=$(INSTALL_TOP)"
@echo "libdir=$(INSTALL_LIB)"
@echo "includedir=$(INSTALL_INC)"
# list targets that do not create files (but not all makes understand .PHONY)
.PHONY: all $(PLATS) clean test install local none dummy echo pecho lecho
# (end of Makefile)

@ -24,9 +24,15 @@ 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
* 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
===========
* A `distribution of Ravi/Lua 5.3 <https://github.com/dibyendumajumdar/ravi-distro>`_ is in the works - this will provide ready made binary downloads of Ravi/Lua with select high quality libraries.
* `Experimental Type Annotations`_ for user defined types was implemented in Oct 2017.
* A new `X86-64 VM written in assembler <https://github.com/dibyendumajumdar/ravi/tree/master/vmbuilder>`_ using `dynasm <https://luajit.org/dynasm.html>`_ tool is under development currently.
Documentation
=============
See `Ravi Documentation <http://the-ravi-programming-language.readthedocs.org/en/latest/index.html>`_.
@ -34,14 +40,17 @@ As more stuff is built I will keep updating the documentation so please revisit
Also see the slides I presented at the `Lua 2015 Workshop <http://www.lua.org/wshop15.html>`_.
Lua Goodies
===========
* `An Introduction to Lua <http://the-ravi-programming-language.readthedocs.io/en/latest/lua-introduction.html>`_ attempts to provide a quick overview of Lua for folks coming from other languages.
* `Lua 5.3 Bytecode Reference <http://the-ravi-programming-language.readthedocs.io/en/latest/lua_bytecode_reference.html>`_ is my attempt to bring up to date the `Lua 5.1 Bytecode Reference <http://luaforge.net/docman/83/98/ANoFrillsIntroToLua51VMInstructions.pdf>`_.
JIT Implementation
==================
The LLVM JIT compiler is functional. The Lua and Ravi bytecodes currently implemented in LLVM are described in `JIT Status <http://the-ravi-programming-language.readthedocs.org/en/latest/ravi-jit-status.html>`_ page.
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
==========================
@ -60,6 +69,8 @@ Ravi allows you to annotate ``local`` variables and function parameters with sta
``table``
a Lua table
Additionally there are some `Experimental Type Annotations`_.
Declaring the types of ``local`` variables and function parameters has following advantages.
* ``integer`` and ``number`` types are automatically initialized to zero
@ -183,6 +194,61 @@ The type assertion operator is a unary operator and binds to the expression foll
For a real example of how type assertions can be used, please have a look at the test program `gaussian2.lua <https://github.com/dibyendumajumdar/ravi/blob/master/ravi-tests/gaussian2.lua>`_
Experimental Type Annotations
-----------------------------
Following type annotations have experimental support. These type annotations are not always statically enforced. Furthermore using these types does not affect the JIT code generation, i.e. variables annotated using these types are still treated as dynamic types.
The scenarios where these type annotations have an impact are:
* Function parameters containing these annotations lead to type assertions at runtime.
* The type assertion operator @ can be applied to these types - leading to runtime assertions.
* Annotating ``local`` declarations results in type assertions.
``string``
denotes a string
``closure``
denotes a function
Name
Denotes a value that has a `metatable registered under Name <https://www.lua.org/pil/28.2.html>`_ in the Lua registry. The Name must be a valid Lua name - hence periods in the name are not allowed.
The main use case for these annotations is to help with type checking of larger Ravi programs. These type checks, particularly the one for user defined types, are executed directly by the VM and hence are more efficient than performing the checks in other ways.
All three types above allow ``nil`` assignment.
Examples::
-- Create a metatable
local mt = { __name='MyType'}
-- Register the metatable in Lua registry
debug.getregistry().MyType = mt
-- Create an object and assign the metatable as its type
local t = {}
setmetatable(t, mt)
-- Use the metatable name as the object's type
function x(s: MyType)
local assert = assert
assert(@MyType(s) == @MyType(t))
assert(@MyType(t) == t)
end
-- Here we use the string type
function x(s1: string, s2: string)
return @string( s1 .. s2 )
end
-- Following demonstrates an error caused by the type checking
-- Note that this error is raised at runtime
function x()
local s: string
-- call a function that returns integer value
-- and try to assign to s
s = (function() return 1 end)()
end
x() -- will fail at runtime
Array Slices
------------
Since release 0.6 Ravi supports array slices. An array slice allows a portion of a Ravi array to be treated as if it is an array - this allows efficient access to the underlying array elements. Following new functions are available:
@ -275,16 +341,17 @@ A JIT api is available with following functions:
``ravi.dumplua(func)``
dumps the Lua bytecode of the function
``ravi.dumpir(func)``
dumps the IR of the compiled function (only if function was compiled; only LLVM version)
(deprecated) dumps the IR of the compiled function (only if function was compiled; only available in LLVM 4.0 and earlier)
``ravi.dumpasm(func)``
dumps the machine code using the currently set optimization level (only if function was compiled; only LLVM)
(deprecated) dumps the machine code using the currently set optimization level (only if function was compiled; only available in LLVM version 4.0 and earlier)
``ravi.optlevel([n])``
sets LLVM optimization level (0, 1, 2, 3); defaults to 2
sets LLVM optimization level (0, 1, 2, 3); defaults to 2. These levels are handled by reusing LLVMs default pass definitions which are geared towards C/C++ programs, but appear to work well here. If level is set to 0, then an attempt is made to use fast instruction selection to further speed up compilation.
``ravi.sizelevel([n])``
sets LLVM size level (0, 1, 2); defaults to 0
``ravi.tracehook([b])``
Enables support for line hooks via the debug api. Note that enabling this option will result in inefficient JIT as a call to a C function will be inserted at beginning of every Lua bytecode
boundary; use this option only when you want to use the debug api to step through code line by line
Enables support for line hooks via the debug api. Note that enabling this option will result in inefficient JIT as a call to a C function will be inserted at beginning of every Lua bytecode boundary; use this option only when you want to use the debug api to step through code line by line
``ravi.verbosity([b])``
Controls the amount of verbose messages generated during compilation. Currently only available for LLVM.
Performance
===========
@ -324,6 +391,12 @@ When JIT compilation is enabled there are following additional constraints:
Building Ravi
=============
Quick build without JIT
-----------------------
A Makefile is supplied for a simple build without the JIT. Just run ``make`` and follow instructions. You may need to customize the Makefiles.
For building Ravi with JIT options please read on.
Build Dependencies
------------------
@ -331,10 +404,12 @@ Build Dependencies
Ravi can be built with or without LLVM. Following versions of LLVM work with Ravi.
* LLVM 3.7 or 3.8 or 3.9 or 4.0
* LLVM 3.7 or 3.8 or 3.9 or 4.0 or 5.0
* LLVM 3.5 and 3.6 should also work but have not been recently tested
Unless otherwise noted the instructions below should work for LLVM 3.7 or later.
Unless otherwise noted the instructions below should work for LLVM 3.9 and later.
Since LLVM 5.0 Ravi has begun to use the new ORC JIT apis. These apis are more memory efficient compared to the MCJIT apis because they release the Module IR as early as possible, whereas with MCJIT the Module IR hangs around as long as the compiled code is held. Because of this significant improvement, I recommend using LLVM 5.0 and above.
Building LLVM on Windows
------------------------
@ -370,19 +445,19 @@ Building Ravi with JIT enabled
------------------------------
I am developing Ravi using Visual Studio 2017 Community Edition on Windows 10 64bit, gcc on Unbuntu 64-bit, and clang/Xcode on MAC OS X. I was also able to successfully build a Ubuntu version on Windows 10 using the newly released Ubuntu/Linux sub-system for Windows 10.
.. note:: Location of cmake files has moved in LLVM 3.9; the new path is ``$LLVM_INSTALL_DIR/lib/cmake/llvm``.
.. note:: Location of cmake files prior to LLVM 3.9 was ``$LLVM_INSTALL_DIR/share/llvm/cmake``.
Assuming that LLVM has been installed as described above, then on Windows I invoke the cmake config as follows::
cd build
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=c:\ravi -DLLVM_DIR=c:\LLVM37\share\llvm\cmake -G "Visual Studio 15 2017 Win64" ..
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=c:\ravi -DLLVM_DIR=c:\LLVM\lib\cmake\llvm -G "Visual Studio 15 2017 Win64" ..
I then open the solution in VS2017 and do a build from there.
On Ubuntu I use::
cd build
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM/share/llvm/cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" ..
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM/lib/cmake/llvm -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" ..
make
Note that on a clean install of Ubuntu 15.10 I had to install following packages:
@ -394,7 +469,7 @@ Note that on a clean install of Ubuntu 15.10 I had to install following packages
On MAC OS X I use::
cd build
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM/share/llvm/cmake -DCMAKE_BUILD_TYPE=Release -G "Xcode" ..
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM/lib/cmake/llvm -DCMAKE_BUILD_TYPE=Release -G "Xcode" ..
I open the generated project in Xcode and do a build from there. You can also use the command line build tools if you wish - generate the make files in the same way as for Linux.
@ -429,15 +504,19 @@ 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
* 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:
- I would like Ravi to be backward compatible with Lua 5.1 and 5.2 as far as possible
- Lua function inlining
- Improve performance of Ravi
- Additional type annotations
* 2015
- Implemented JIT compilation using LLVM
- Implemented libgccjit based alternative JIT (now discontinued)
* 2016
- Implemented debugger for Ravi and Lua 5.3 for `Visual Studio Code <https://github.com/dibyendumajumdar/ravi/tree/master/vscode-debugger>`_
* 2017
- Embedded C compiler using dmrC project (C JIT compiler)
- Additional type annotations
* 2018
- 1.0 release of Ravi
- More testing and test cases
- ASM VM for X86-64 platform
- Better support for earlier Lua versions (5.1 especially)
License
=======

@ -1,5 +1,6 @@
mkdir llvm64d
cd llvm64d
rem cmake -DCMAKE_INSTALL_PREFIX=c:\ravi64llvmd -G "Visual Studio 14 Win64" -DLLVM_JIT=ON -DLLVM_DIR=c:\LLVM37debug\share\llvm\cmake ..
cmake -DSTATIC_BUILD=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=c:\d\ravi64llvmd -G "Visual Studio 14 Win64" -DLLVM_JIT=ON -DLLVM_DIR=c:\d\LLVM39D64\lib\cmake\llvm ..
rem cmake -DSTATIC_BUILD=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=c:\d\ravi64llvmd -G "Visual Studio 15 2017 Win64" -DLLVM_JIT=ON -DEMBEDDED_DMRC=ON -DLLVM_DIR=c:\d\LLVM39D64\lib\cmake\llvm ..
cmake -DCMAKE_INSTALL_PREFIX=c:\Software\ravi -G "Visual Studio 15 2017 Win64" -DLTESTS=ON -DSTATIC_BUILD=ON -DCMAKE_BUILD_TYPE=Debug -DLLVM_JIT=ON -DLLVM_DIR=c:\Software\llvm501d\lib\cmake\llvm ..
cd ..

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

@ -0,0 +1,4 @@
mkdir asmvm
cd asmvm
cmake -DCMAKE_INSTALL_PREFIX=c:\Software\ravi-asmvm -DSTATIC_BUILD=ON -DCMAKE_BUILD_TYPE=Debug -DASM_VM=ON -G "Visual Studio 15 2017 Win64" ..
cd ..

@ -1,4 +1,4 @@
mkdir nojit64a
cd nojit64a
cmake -DCMAKE_INSTALL_PREFIX=c:\ravi -DCMAKE_BUILD_TYPE=Debug -G "Visual Studio 15 2017 Win64" ..
cmake -DCMAKE_INSTALL_PREFIX=c:\Software\ravi -DCMAKE_BUILD_TYPE=Debug -DLTESTS=ON -G "Visual Studio 15 2017 Win64" ..
cd ..

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

@ -1,3 +1,4 @@
mkdir xcodellvm
cd xcodellvm
cmake -DCMAKE_BUILD_TYPE=Debug -G Xcode -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM/share/llvm/cmake ..
#cmake -DCMAKE_BUILD_TYPE=Debug -G Xcode -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM/share/llvm/cmake ..
cmake -DCMAKE_BUILD_TYPE=Debug -G Xcode -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM5/lib/cmake/llvm ..

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

@ -1,3 +1,5 @@
mkdir buildllvmd
cd buildllvmd
cmake -DCMAKE_BUILD_TYPE=Debug -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM/share/llvm/cmake ..
#cmake -DCMAKE_BUILD_TYPE=Debug -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM/share/llvm/cmake ..
#cmake -DCMAKE_BUILD_TYPE=Debug -DLLVM_JIT=ON -DLTESTS=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM5/lib/cmake/llvm ..
cmake -DCMAKE_BUILD_TYPE=Debug -DLLVM_JIT=ON -DLTESTS=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravillvm -DLLVM_DIR=$HOME/Software/llvm600/lib/cmake/llvm ..

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

@ -0,0 +1,3 @@
mkdir buildasmvm
cd buildasmvm
cmake -DSTATIC_BUILD=ON -DASM_VM=ON -DCMAKE_BUILD_TYPE=Debug -DCOMPUTED_GOTO=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi ..

@ -0,0 +1,3 @@
mkdir buildnojit
cd buildnojit
cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=$HOME/ravi ..

@ -1,3 +1,4 @@
mkdir buildnojit
cd buildnojit
cmake -DSTATIC_BUILD=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$HOME/ravi ..
#cmake -DSTATIC_BUILD=ON -DCMAKE_BUILD_TYPE=Release -DCOMPUTED_GOTO=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi ..
cmake -DCMAKE_BUILD_TYPE=Release -DCOMPUTED_GOTO=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi ..

@ -36,7 +36,7 @@ union Value {
struct TValue {
union Value value_;
int tt_;
lu_byte tt_;
};
struct TString {
@ -95,16 +95,18 @@ enum ravitype_t {
struct Upvaldesc {
struct TString *name; /* upvalue name (for debug information) */
enum ravitype_t type; /* RAVI type of upvalue */
struct TString *usertype; /* RAVI extension: name of user type */
lu_byte ravi_type; /* RAVI type of upvalue */
lu_byte instack; /* whether it is in stack */
lu_byte idx; /* index of upvalue (in stack or in outer function's list) */
};
struct LocVar {
struct TString *varname;
struct TString *usertype; /* RAVI extension: name of user type */
int startpc; /* first point where variable is active */
int endpc; /* first point where variable is dead */
enum ravitype_t ravi_type; /* RAVI type of the variable - RAVI_TANY if unknown */
lu_byte ravi_type; /* RAVI type of the variable - RAVI_TANY if unknown */
};
struct RaviJITProto {
@ -328,7 +330,7 @@ union GCUnion {
#define rttype(o) ((o)->tt_)
#define BIT_ISCOLLECTABLE (1 << 6)
#define BIT_ISCOLLECTABLE (1 << 7)
#define iscollectable(o) (rttype(o) & BIT_ISCOLLECTABLE)
#define upisopen(up) ((up)->v != &(up)->u.value)

@ -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}" )

@ -0,0 +1 @@
Subproject commit 5b42a99121627677952d4cf3445d795be85582de

@ -281,6 +281,11 @@ LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
IMPORTANT: Caller must ensure that supplied meta_key points to somewhere in
static storage as otherwise memory fault will occur.
*/
LUALIB_API int (luaL_newmetatable)(lua_State *L, const char *tname);
LUALIB_API void (luaL_setmetatable)(lua_State *L, const char *tname);
LUALIB_API void *(luaL_testudata)(lua_State *L, int ud, const char *tname);
LUALIB_API void *(luaL_checkudata)(lua_State *L, int ud, const char *tname);
#if 0
LUALIB_API int raviL_newmetatable(lua_State *L, const void *meta_key,
const char *tname);
@ -298,7 +303,12 @@ LUALIB_API void *raviL_testudata(lua_State *L, int arg_index, const void *meta_k
meta_key is the key assigned to the meta table of the userdata
*/
LUALIB_API void *raviL_checkudata(lua_State *L, int arg_index, const void *meta_key);
#else
#define raviL_newmetatable(L, meta_key, tname) luaL_newmetatable(L, meta_key)
#define raviL_getmetatable(L, meta_key) luaL_getmetatable(L, meta_key)
#define raviL_testudata(L, arg_index, meta_key) luaL_testudata(L, arg_index, meta_key)
#define raviL_checkudata(L, arg_index, meta_key) luaL_checkudata(L, arg_index, meta_key)
#endif
LUALIB_API int (raviL_loadbufferx) (lua_State *L, const char *buff, size_t size,
const char *name, const char *mode);

@ -38,7 +38,7 @@ typedef enum BinOpr {
/** RAVI change */
typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_TO_INTEGER,
OPR_TO_NUMBER, OPR_TO_INTARRAY, OPR_TO_NUMARRAY, OPR_TO_TABLE, OPR_NOUNOPR } UnOpr;
OPR_TO_NUMBER, OPR_TO_INTARRAY, OPR_TO_NUMARRAY, OPR_TO_TABLE, OPR_TO_STRING, OPR_TO_CLOSURE, OPR_TO_TYPE, OPR_NOUNOPR } UnOpr;
/* get (pointer to) instruction of given 'expdesc' */
#define getinstruction(fs,e) ((fs)->f->code[(e)->u.info])
@ -78,7 +78,7 @@ LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list);
LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level);
LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2);
LUAI_FUNC int luaK_getlabel (FuncState *fs);
LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line);
LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line, TString *);
LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);
LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1,
expdesc *v2, int line);

@ -36,7 +36,7 @@ enum RESERVED {
TK_FLT, TK_INT, TK_NAME, TK_STRING,
/** RAVI extensions */
TK_TO_INTEGER, TK_TO_NUMBER, TK_TO_INTARRAY, TK_TO_NUMARRAY,
TK_TO_TABLE
TK_TO_TABLE, TK_TO_STRING, TK_TO_CLOSURE
};
/* number of reserved words */

@ -63,7 +63,7 @@
/* Bit mark for collectable types */
#define BIT_ISCOLLECTABLE (1 << 6)
#define BIT_ISCOLLECTABLE (1 << 7)
/* mark a tag as collectable */
#define ctb(t) ((t) | BIT_ISCOLLECTABLE)
@ -110,7 +110,7 @@ typedef union Value {
} Value;
#define TValuefields Value value_; int tt_
#define TValuefields Value value_; lu_byte tt_
typedef struct lua_TValue {
@ -282,7 +282,8 @@ typedef struct lua_TValue {
#define setobj(L,obj1,obj2) \
{ TValue *io1=(obj1); *io1 = *(obj2); \
{ TValue *io1=(obj1); const TValue *io2=(obj2); \
io1->value_ = io2->value_; io1->tt_ = io2->tt_; \
(void)L; checkliveness(L,io1); }
@ -302,9 +303,8 @@ typedef struct lua_TValue {
/* to new object */
#define setobj2n setobj
#define setsvalue2n setsvalue
/* to table (define it as an expression to be used in macros) */
#define setobj2t(L,o1,o2) ((void)L, *(o1)=*(o2), checkliveness(L,(o1)))
/* to table */
#define setobj2t setobj
@ -411,8 +411,8 @@ typedef union UUdata {
** other types appear then they are all treated as ANY
**/
typedef enum {
RAVI_TANY = -1, /* Lua dynamic type */
RAVI_TNUMINT = 1, /* integer number */
RAVI_TANY = 0, /* Lua dynamic type */
RAVI_TNUMINT = 1, /* integer number */
RAVI_TNUMFLT, /* floating point number */
RAVI_TARRAYINT, /* array of ints */
RAVI_TARRAYFLT, /* array of doubles */
@ -429,7 +429,8 @@ typedef enum {
*/
typedef struct Upvaldesc {
TString *name; /* upvalue name (for debug information) */
ravitype_t type; /* RAVI type of upvalue */
TString *usertype; /* RAVI extension: name of user type */
lu_byte ravi_type; /* RAVI type of upvalue */
lu_byte instack; /* whether it is in stack (register) */
lu_byte idx; /* index of upvalue (in stack or in outer function's list) */
} Upvaldesc;
@ -441,9 +442,10 @@ typedef struct Upvaldesc {
*/
typedef struct LocVar {
TString *varname;
TString *usertype; /* RAVI extension: name of user type */
int startpc; /* first point where variable is active */
int endpc; /* first point where variable is dead */
ravitype_t ravi_type; /* RAVI type of the variable - RAVI_TANY if unknown */
lu_byte ravi_type; /* RAVI type of the variable - RAVI_TANY if unknown */
} LocVar;
/** RAVI changes start */
@ -588,7 +590,10 @@ typedef struct Table {
GCObject *gclist;
/** RAVI extension */
RaviArray ravi_array;
#if RAVI_USE_NEWHASH
// TODO we should reorganize this structure
unsigned int hmask; /* Hash part mask (size of hash part - 1) - borrowed from LuaJIT */
#endif
} Table;
@ -609,6 +614,9 @@ typedef struct Table {
*/
#define luaO_nilobject (&luaO_nilobject_)
/* Internal assembler functions. Never call these directly from C. */
typedef void(*ASMFunction)(void);
LUAI_DDEC const TValue luaO_nilobject_;

@ -12,15 +12,17 @@
/*===========================================================================
We assume that instructions are unsigned numbers.
All instructions have an opcode in the first 6 bits.
All instructions have an opcode in the first 8 bits.
Instructions can have the following fields:
'A' : 8 bits
'B' : 9 bits
'C' : 9 bits
'Ax' : 26 bits ('A', 'B', and 'C' together)
'Bx' : 18 bits ('B' and 'C' together)
'A' : 8 bits (7 bits used)
'B' : 8 bits
'C' : 8 bits
'Ax' : 24 bits ('A', 'B', and 'C' together)
'Bx' : 16 bits ('B' and 'C' together)
'sBx' : signed Bx
Above is based on LuaJIT scheme but unlike LuaJIT A is actually
represented in 7 bits.
A signed argument is represented in excess K; that is, the number
value is the unsigned value minus K. K is exactly the maximum value
for that argument (so that -max is represented by 0, and +max is
@ -31,108 +33,64 @@
enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */
#include "ravi_arch.h"
/*
** size and position of opcode arguments.
*/
/** RAVI changes **/
#define SIZE_C 8
#define SIZE_B 8
#define SIZE_Bx (SIZE_C + SIZE_B)
#define SIZE_A 7
#define SIZE_Ax (SIZE_C + SIZE_B + SIZE_A)
#define SIZE_OP 9
#define POS_OP 0
#define POS_A (POS_OP + SIZE_OP)
#define POS_C (POS_A + SIZE_A)
#define POS_B (POS_C + SIZE_C)
#define POS_Bx POS_C
#define POS_Ax POS_A
/*
** limits for opcode arguments.
** we use (signed) int to manipulate most arguments,
** so they must fit in LUAI_BITSINT-1 bits (-1 for sign)
*/
#if SIZE_Bx < LUAI_BITSINT-1
#define MAXARG_Bx ((1<<SIZE_Bx)-1)
#define MAXARG_sBx (MAXARG_Bx>>1) /* 'sBx' is signed */
#else
#define MAXARG_Bx MAX_INT
#define MAXARG_sBx MAX_INT
#endif
#if SIZE_Ax < LUAI_BITSINT-1
#define MAXARG_Ax ((1<<SIZE_Ax)-1)
#else
#define MAXARG_Ax MAX_INT
#endif
The bytecode layout here uses LuaJIT inspired format.
#define MAXARG_A ((1<<SIZE_A)-1)
#define MAXARG_B ((1<<SIZE_B)-1)
#define MAXARG_C ((1<<SIZE_C)-1)
+---+---+---+----+
| B | C | A | Op |
+---+---+---+----+
| Bx | A | Op |
+-------+---+----+
| Ax | Op |
+-----------+----+
/* creates a mask with 'n' 1 bits at position 'p' */
#define MASK1(n,p) ((~((~(Instruction)0)<<(n)))<<(p))
/* creates a mask with 'n' 0 bits at position 'p' */
#define MASK0(n,p) (~MASK1(n,p))
/*
** the following macros help to manipulate instructions
*/
#define GET_OPCODE(i) (cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0)))
#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \
((cast(Instruction, o)<<POS_OP)&MASK1(SIZE_OP,POS_OP))))
#define getarg(i,pos,size) (cast(int, ((i)>>pos) & MASK1(size,0)))
#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \
((cast(Instruction, v)<<pos)&MASK1(size,pos))))
#define GETARG_A(i) getarg(i, POS_A, SIZE_A)
#define SETARG_A(i,v) setarg(i, v, POS_A, SIZE_A)
#define GETARG_B(i) getarg(i, POS_B, SIZE_B)
#define SETARG_B(i,v) setarg(i, v, POS_B, SIZE_B)
#define GETARG_C(i) getarg(i, POS_C, SIZE_C)
#define SETARG_C(i,v) setarg(i, v, POS_C, SIZE_C)
#define GETARG_Bx(i) getarg(i, POS_Bx, SIZE_Bx)
#define SETARG_Bx(i,v) setarg(i, v, POS_Bx, SIZE_Bx)
#define GETARG_Ax(i) getarg(i, POS_Ax, SIZE_Ax)
#define SETARG_Ax(i,v) setarg(i, v, POS_Ax, SIZE_Ax)
#define GETARG_sBx(i) (GETARG_Bx(i)-MAXARG_sBx)
#define SETARG_sBx(i,b) SETARG_Bx((i),cast(unsigned int, (b)+MAXARG_sBx))
#define CREATE_ABC(o,a,b,c) ((cast(Instruction, o)<<POS_OP) \
| (cast(Instruction, a)<<POS_A) \
| (cast(Instruction, b)<<POS_B) \
| (cast(Instruction, c)<<POS_C))
#define CREATE_ABx(o,a,bc) ((cast(Instruction, o)<<POS_OP) \
| (cast(Instruction, a)<<POS_A) \
| (cast(Instruction, bc)<<POS_Bx))
#define CREATE_Ax(o,a) ((cast(Instruction, o)<<POS_OP) \
| (cast(Instruction, a)<<POS_Ax))
/*
** Macros to operate RK indices
*/
#define MAXARG_A 0x7f
#define MAXARG_B 0xff
#define MAXARG_C 0xff
#define MAXARG_Bx 0xffff
#define MAXARG_Ax 0xffffff
#define GET_OPCODE(i) cast(OpCode, ((i)&0xff))
#define GETARG_A(i) cast(int, ((i)>>8)&0x7f)
#define GETARG_B(i) cast(int, (i)>>24)
#define GETARG_C(i) cast(int, ((i)>>16)&0xff)
#define GETARG_Bx(i) cast(int, (i)>>16)
#define GETARG_Ax(i) cast(int, (i)>>8)
#define GETARG_sBx(i) (((int)GETARG_Bx(i))-MAXARG_sBx)
#define MAXARG_sBx 0x8000
#define setbc_byte(p, x, ofs) \
((lu_byte *)(&(p)))[RAVI_ENDIAN_SELECT(ofs, 3-ofs)] = ((lu_byte)cast(Instruction, x))
#define SET_OPCODE(p, x) setbc_byte(p, (x), 0)
#define SETARG_A(p, x) setbc_byte(p, ((x)&0x7f), 1)
#define SETARG_B(p, x) setbc_byte(p, (x), 3)
#define SETARG_C(p, x) setbc_byte(p, (x), 2)
#define SETARG_Bx(p, x) \
((unsigned short *)(&(p)))[RAVI_ENDIAN_SELECT(1, 0)] = (unsigned short)(cast(Instruction, x))
#define SETARG_sBx(p, x) SETARG_Bx(p, cast(unsigned int, cast(Instruction, x)+MAXARG_sBx))
#define SETARG_Ax(p, x) p = (cast(Instruction, p)&0xff | (cast(Instruction, x)<<8))
#define CREATE_ABC(o,a,b,c) ((cast(Instruction, o)) \
| (cast(Instruction, a)<<8) \
| (cast(Instruction, b)<<24) \
| (cast(Instruction, c)<<16))
#define CREATE_ABx(o,a,bc) ((cast(Instruction, o)) \
| (cast(Instruction, a)<<8) \
| (cast(Instruction, bc)<<16))
#define CREATE_Ax(o,a) ((cast(Instruction, o)) \
| (cast(Instruction, a)<<8))
/* this bit 1 means constant (0 means register) */
#define BITRK (1 << (SIZE_B - 1))
#define BITRK 0x80
/* test whether value is a constant */
#define ISK(x) ((x) & BITRK)
@ -263,17 +221,24 @@ OP_RAVI_TOINT, /* A R(A) := toint(R(A)) */
OP_RAVI_TOFLT, /* A R(A) := tofloat(R(A)) */
OP_RAVI_TOARRAYI, /* A R(A) := to_arrayi(R(A)) */
OP_RAVI_TOARRAYF, /* A R(A) := to_arrayf(R(A)) */
OP_RAVI_TOTAB, /* A R(A) := to_table(R(A)) */
OP_RAVI_TOSTRING,
OP_RAVI_TOCLOSURE,
OP_RAVI_TOTYPE,
OP_RAVI_MOVEI, /* A B R(A) := R(B), check R(B) is int */
OP_RAVI_MOVEF, /* A B R(A) := R(B), check R(B) is float */
OP_RAVI_MOVEAI, /* A B R(A) := R(B), check R(B) is array of int */
OP_RAVI_MOVEAF, /* A B R(A) := R(B), check R(B) is array of floats */
OP_RAVI_MOVETAB, /* A B R(A) := R(B), check R(B) is a table */
OP_RAVI_GETTABLE_AI,/* A B C R(A) := R(B)[RK(C)] where R(B) is array of integers and RK(C) is int */
OP_RAVI_GETTABLE_AF,/* A B C R(A) := R(B)[RK(C)] where R(B) is array of floats and RK(C) is int */
OP_RAVI_SETTABLE_AI,/* A B C R(A)[RK(B)] := RK(C) where RK(B) is an int, R(A) is array of ints, and RK(C) is an int */
OP_RAVI_SETTABLE_AF,/* A B C R(A)[RK(B)] := RK(C) where RK(B) is an int, R(A) is array of floats, and RK(C) is an float */
OP_RAVI_SETTABLE_AI,/* A B C R(A)[RK(B)] := RK(C) where RK(B) is an int, R(A) is array of ints */
OP_RAVI_SETTABLE_AF,/* A B C R(A)[RK(B)] := RK(C) where RK(B) is an int, R(A) is array of floats */
OP_RAVI_SETTABLE_AII,/* A B C R(A)[RK(B)] := RK(C) where RK(B) is an int, R(A) is array of ints, and RK(C) is an int */
OP_RAVI_SETTABLE_AFF,/* A B C R(A)[RK(B)] := RK(C) where RK(B) is an int, R(A) is array of floats, and RK(C) is an float */
OP_RAVI_FORLOOP_IP,
OP_RAVI_FORLOOP_I1,
@ -284,9 +249,7 @@ OP_RAVI_SETUPVALI, /* A B UpValue[B] := tointeger(R(A)) */
OP_RAVI_SETUPVALF, /* A B UpValue[B] := tonumber(R(A)) */
OP_RAVI_SETUPVALAI, /* A B UpValue[B] := toarrayint(R(A)) */
OP_RAVI_SETUPVALAF, /* A B UpValue[B] := toarrayflt(R(A)) */
OP_RAVI_SETTABLE_AII,/* A B C R(A)[RK(B)] := RK(C) where RK(B) is an int, R(A) is array of ints, and RK(C) is an int */
OP_RAVI_SETTABLE_AFF,/* A B C R(A)[RK(B)] := RK(C) where RK(B) is an int, R(A) is array of floats, and RK(C) is an float */
OP_RAVI_SETUPVALT,/* A B UpValue[B] := to_table(R(A)) */
OP_RAVI_BAND_II,/* A B C R(A) := RK(B) & RK(C) */
OP_RAVI_BOR_II, /* A B C R(A) := RK(B) | RK(C) */
@ -302,22 +265,21 @@ OP_RAVI_LT_FF,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
OP_RAVI_LE_II,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
OP_RAVI_LE_FF,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
OP_RAVI_GETTABLE_I,/* A B C R(A) := R(B)[RK(C)], integer key */
OP_RAVI_GETTABLE_S,/* A B C R(A) := R(B)[RK(C)], string key */
OP_RAVI_SETTABLE_I,/* A B C R(A)[RK(B)] := RK(C), integer key */
OP_RAVI_SETTABLE_S,/* A B C R(A)[RK(B)] := RK(C), string key */
OP_RAVI_TOTAB, /* A R(A) := to_table(R(A)) */
OP_RAVI_MOVETAB, /* A B R(A) := R(B), check R(B) is a table */
OP_RAVI_SETUPVALT,/* A B UpValue[B] := to_table(R(A)) */
OP_RAVI_SELF_S,/* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
/* Following op codes are specialised when it is known that indexing is being
done on a table and the key is known type */
OP_RAVI_GETTABLE_S,/* A B C R(A) := R(B)[RK(C)], string key, known table */
OP_RAVI_SETTABLE_S,/* A B C R(A)[RK(B)] := RK(C), string key, known table */
OP_RAVI_SELF_S,/* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)], string key, known table */
/* Following opcodes are specialized for access where the
/* Following opcodes are specialized for indexing where the
key is known to be string but the variable may or may not be
a table */
OP_RAVI_GETTABLE_I,/* A B C R(A) := R(B)[RK(C)], integer key, known table */
OP_RAVI_SETTABLE_I,/* A B C R(A)[RK(B)] := RK(C), integer key, known table */
OP_RAVI_GETTABLE_SK, /* A B C R(A) := R(B)[RK(C)], string key */
OP_RAVI_SELF_SK, /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
OP_RAVI_SETTABLE_SK, /* A B C R(A)[RK(B)] := RK(C), string key */
OP_RAVI_GETTABUP_SK, /* A B C R(A) := UpValue[B][RK(C)] */
OP_RAVI_SELF_SK, /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)], string key */
OP_RAVI_SETTABLE_SK, /* A B C R(A)[RK(B)] := RK(C), string key */
OP_RAVI_GETTABUP_SK, /* A B C R(A) := UpValue[B][RK(C)], string key */
} OpCode;

@ -66,12 +66,14 @@ typedef struct expdesc {
short idx; /* index (R/K) */
lu_byte t; /* table (register or upvalue) */
lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */
ravitype_t key_type; /* RAVI change: key type */
lu_byte key_ravi_type; /* RAVI change: key type */
TString *usertype; /* RAVI change: usertype name */
} ind;
} u;
int t; /* patch list of 'exit when true' */
int f; /* patch list of 'exit when false' */
ravitype_t ravi_type; /* RAVI change: type of the expression if known, else RAVI_TANY */
lu_byte ravi_type; /* RAVI change: type of the expression if known, else RAVI_TANY */
TString *usertype; /* RAVI change: usertype name */
int pc; /* RAVI change: holds the program counter for OP_NEWTABLE instruction when a constructor expression is parsed */
} expdesc;
@ -260,7 +262,7 @@ LUAI_FUNC void raviY_printf(FuncState *fs, const char *format, ...);
* Else RAVI_TANY is returned. Note that this function only looks
* at active local variables - see note on FuncState on what this means.
*/
LUAI_FUNC ravitype_t raviY_get_register_typeinfo(FuncState *fs, int reg);
LUAI_FUNC ravitype_t raviY_get_register_typeinfo(FuncState *fs, int reg, TString **);
#define DEBUG_EXPR(p) \
if ((ravi_parser_debug & 1) != 0) { \

@ -12,7 +12,7 @@
#include "lobject.h"
#include "ltm.h"
#include "lzio.h"
#include "lopcodes.h"
/*
@ -91,6 +91,7 @@ typedef struct CallInfo {
unsigned short callstatus;
unsigned short stacklevel; /* RAVI extension - stack level, bottom level is 0 */
lu_byte jitstatus; /* RAVI extension: Only valid if Lua function - if 1 means JITed - RAVI extension */
lu_byte magic;
} CallInfo;
@ -159,6 +160,7 @@ typedef struct global_State {
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
/* RAVI additions */
ravi_State *ravi_state;
ASMFunction dispatch[NUM_OPCODES];
ravi_Writeline ravi_writeline;
ravi_Writestring ravi_writestring;
ravi_Writestringerror ravi_writestringerror;
@ -170,6 +172,7 @@ typedef struct global_State {
#endif
} global_State;
#define DISPATCH_OFFSET ((int)offsetof(global_State, dispatch))
/*
** 'per thread' state
@ -206,6 +209,7 @@ struct lua_State {
** pending
*/
unsigned short nci; /* number of items in 'ci' list */
lu_byte magic;
};

@ -44,10 +44,7 @@ LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);
LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
TValue *value);
/** RAVI change start - attempt to inline some functions **/
#define NEW_HASH 1
#if NEW_HASH
#if RAVI_USE_NEWHASH
/*
Like LuaJIT we use a pre-computed hmask to minimise the number of steps
@ -64,7 +61,9 @@ required to get to a node in the hash table
*/
#define hashmod(t, n) (gnode(t, ((n) % ((t)->hmask|1))))
#define hashpointer(t, p) hashmod(t, point2uint(p))
#else
#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
#define hashstr(t,str) hashpow2(t, (str)->hash)
#define hashboolean(t,p) hashpow2(t, p)
@ -75,6 +74,7 @@ required to get to a node in the hash table
*/
#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1))))
#define hashpointer(t,p) hashmod(t, point2uint(p))
#endif
#if defined(RAVI_ENABLED)

@ -401,7 +401,7 @@
** This macro is not on by default even in compatibility mode,
** because this is not really an incompatibility.
*/
/* #define LUA_COMPAT_FLOATSTRING */
#define LUA_COMPAT_FLOATSTRING
/* }================================================================== */
@ -816,5 +816,11 @@
#endif
#define RAVI_USE_NEWHASH 1
#define RAVI_USE_LLVM_BRANCH_WEIGHTS 1
/* If following is defined as true then LLVM instructions emitted for arithmetic ops
priority floating point ops, else default is to prioritise integer ops */
#define RAVI_USE_LLVM_ARITH_FLOATPRIORITY 1
#endif

@ -38,6 +38,9 @@ LUAMOD_API int (luaopen_utf8) (lua_State *L);
#define LUA_BITLIBNAME "bit32"
LUAMOD_API int (luaopen_bit32) (lua_State *L);
#define LUAJIT_BITLIBNAME "bit"
LUAMOD_API int (luaopen_bit)(lua_State *L);
#define LUA_MATHLIBNAME "math"
LUAMOD_API int (luaopen_math) (lua_State *L);

@ -50,10 +50,10 @@
/*
** fast track for 'gettable': if 't' is a table and 't[k]' is not nil,
** return 1 with 'slot' pointing to 't[k]' (final result). Otherwise,
** return 0 (meaning it will have to check metamethod) with 'slot'
** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise).
** 'f' is the raw get function to use.
** return 1 with 'slot' pointing to 't[k]' (position of final result).
** Otherwise, return 0 (meaning it will have to check metamethod)
** with 'slot' pointing to a nil 't[k]' (if 't' is a table) or NULL
** (otherwise). 'f' is the raw get function to use.
*/
#define luaV_fastget(L,t,k,slot,f) \
(!ttistable(t) \
@ -61,41 +61,28 @@
: (slot = f(hvalue(t), k), /* else, do raw access */ \
!ttisnil(slot))) /* result not nil? */
/*
** standard implementation for 'gettable'
** RAVI change - renamed as we need luaV_gettable to be
** an exported function
** Special case of 'luaV_fastget' for integers, inlining the fast case
** of 'luaH_getint'.
*/
#define luaV_fastgettable(L,t,k,v) { const TValue *slot; \
if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
else luaV_finishget(L,t,k,v,slot); }
#define luaV_fastgeti(L,t,k,slot) \
(!ttistable(t) \
? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
: (slot = (l_castS2U(k) - 1u < hvalue(t)->sizearray) \
? &hvalue(t)->array[k - 1] : luaH_getint(hvalue(t), k), \
!ttisnil(slot))) /* result not nil? */
/*
** Fast track for set table. If 't' is a table and 't[k]' is not nil,
** call GC barrier, do a raw 't[k]=v', and return true; otherwise,
** return false with 'slot' equal to NULL (if 't' is not a table) or
** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro
** returns true, there is no need to 'invalidateTMcache', because the
** call is not creating a new entry.
** Finish a fast set operation (when fast get succeeds). In that case,
** 'slot' points to the place to put the value.
*/
#define luaV_fastset(L,t,k,slot,f,v) \
(!ttistable(t) \
? (slot = NULL, 0) \
: (slot = f(hvalue(t), k), \
ttisnil(slot) ? 0 \
: (luaC_barrierback(L, hvalue(t), v), \
setobj2t(L, cast(TValue *,slot), v), \
1)))
#define luaV_finishfastset(L,t,slot,v) \
{ setobj2t(L, cast(TValue *,slot), v); \
luaC_barrierback(L, hvalue(t), v); }
/*
** RAVI change - renamed as we need luaV_settable to be
** an exported function
*/
#define luaV_fastsettable(L,t,k,v) { const TValue *slot; \
if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \
luaV_finishset(L,t,k,v,slot); }
LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);
@ -153,5 +140,8 @@ LUAI_FUNC void raviV_op_band(lua_State *L, TValue *ra, TValue *rb, TValue *rc);
LUAI_FUNC void raviV_op_bnot(lua_State *L, TValue *ra, TValue *rb);
LUAI_FUNC void raviV_gettable_sskey(lua_State *L, const TValue *t, TValue *key, StkId val);
LUAI_FUNC void raviV_settable_sskey(lua_State *L, const TValue *t, TValue *key, StkId val);
LUAI_FUNC void raviV_gettable_i(lua_State *L, const TValue *t, TValue *key, StkId val);
LUAI_FUNC void raviV_settable_i(lua_State *L, const TValue *t, TValue *key, StkId val);
LUAI_FUNC void raviV_op_totype(lua_State *L, TValue *ra, TValue *rb);
#endif

@ -0,0 +1,180 @@
/*
** Target architecture selection.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef RAVI_ARCH_H
#define RAVI_ARCH_H
#include "lua.h"
/* Target endianess. */
#define RAVI__ARCH_LE 0
#define RAVI__ARCH_BE 1
/* Target architectures. */
#define RAVI__ARCH_X86 1
#define RAVI__ARCH_x86 1
#define RAVI__ARCH_X64 2
#define RAVI__ARCH_x64 2
#define RAVI__ARCH_ARM 3
#define RAVI__ARCH_arm 3
#define RAVI__ARCH_ARM64 4
#define RAVI__ARCH_arm64 4
#define RAVI__ARCH_PPC 5
#define RAVI__ARCH_ppc 5
#define RAVI__ARCH_MIPS 6
#define RAVI__ARCH_mips 6
#define RAVI__ARCH_MIPS32 6
#define RAVI__ARCH_mips32 6
#define RAVI__ARCH_MIPS64 7
#define RAVI__ARCH_mips64 7
/* Target OS. */
#define RAVI__OS_OTHER 0
#define RAVI__OS_WINDOWS 1
#define RAVI__OS_LINUX 2
#define RAVI__OS_OSX 3
#define RAVI__OS_BSD 4
#define RAVI__OS_POSIX 5
/* Select native target if no target defined. */
#ifndef RAVI__TARGET
#if defined(__i386) || defined(__i386__) || defined(_M_IX86)
#error "No support for this architecture (yet)"
#define RAVI__TARGET RAVI__ARCH_X86
#elif defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
#define RAVI__TARGET RAVI__ARCH_X64
#elif defined(__arm__) || defined(__arm) || defined(__ARM__) || defined(__ARM)
#error "No support for this architecture (yet)"
#define RAVI__TARGET RAVI__ARCH_ARM
#elif defined(__aarch64__)
#error "No support for this architecture (yet)"
#define RAVI__TARGET RAVI__ARCH_ARM64
#elif defined(__ppc__) || defined(__ppc) || defined(__PPC__) || defined(__PPC) || defined(__powerpc__) || defined(__powerpc) || defined(__POWERPC__) || defined(__POWERPC) || defined(_M_PPC)
#error "No support for this architecture (yet)"
#define RAVI__TARGET RAVI__ARCH_PPC
#elif defined(__mips64__) || defined(__mips64) || defined(__MIPS64__) || defined(__MIPS64)
#error "No support for this architecture (yet)"
#define RAVI__TARGET RAVI__ARCH_MIPS64
#elif defined(__mips__) || defined(__mips) || defined(__MIPS__) || defined(__MIPS)
#error "No support for this architecture (yet)"
#define RAVI__TARGET RAVI__ARCH_MIPS32
#else
#error "No support for this architecture (yet)"
#endif
#endif
/* Select native OS if no target OS defined. */
#ifndef RAVI__OS
#if defined(_WIN32) && !defined(_XBOX_VER)
#define RAVI__OS RAVI__OS_WINDOWS
#elif defined(__linux__)
#define RAVI__OS RAVI__OS_LINUX
#elif defined(__MACH__) && defined(__APPLE__)
#define RAVI__OS RAVI__OS_OSX
#elif (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
defined(__NetBSD__) || defined(__OpenBSD__) || \
defined(__DragonFly__)) && !defined(__ORBIS__)
#define RAVI__OS RAVI__OS_BSD
#elif (defined(__sun__) && defined(__svr4__)) || defined(__HAIKU__)
#define RAVI__OS RAVI__OS_POSIX
#elif defined(__CYGWIN__)
#define RAVI_TARGET_CYGWIN 1
#define RAVI__OS RAVI__OS_POSIX
#else
#define RAVI__OS RAVI__OS_OTHER
#endif
#endif
/* Set target OS properties. */
#if RAVI__OS == RAVI__OS_WINDOWS
#define RAVI_OS_NAME "Windows"
#elif RAVI__OS == RAVI__OS_LINUX
#define RAVI_OS_NAME "Linux"
#elif RAVI__OS == RAVI__OS_OSX
#define RAVI_OS_NAME "OSX"
#elif RAVI__OS == RAVI__OS_BSD
#define RAVI_OS_NAME "BSD"
#elif RAVI__OS == RAVI__OS_POSIX
#define RAVI_OS_NAME "POSIX"
#else
#define RAVI_OS_NAME "Other"
#endif
#define RAVI_TARGET_WINDOWS (RAVI__OS == RAVI__OS_WINDOWS)
#define RAVI_TARGET_LINUX (RAVI__OS == RAVI__OS_LINUX)
#define RAVI_TARGET_OSX (RAVI__OS == RAVI__OS_OSX)
#define RAVI_TARGET_IOS (RAVI_TARGET_OSX && (RAVI__TARGET == RAVI__ARCH_ARM || RAVI__TARGET == RAVI__ARCH_ARM64))
#define RAVI_TARGET_POSIX (RAVI__OS > RAVI__OS_WINDOWS)
#define RAVI_TARGET_DLOPEN RAVI_TARGET_POSIX
/* Set target architecture properties. */
#if RAVI__TARGET == RAVI__ARCH_X86
#define RAVI_ARCH_NAME "x86"
#define RAVI_ARCH_BITS 32
#define RAVI_ARCH_ENDIAN RAVI__ARCH_LE
#if RAVI_TARGET_WINDOWS || RAVI_TARGET_CYGWIN
#define RAVI_ABI_WIN 1
#else
#define RAVI_ABI_WIN 0
#endif
#define RAVI_TARGET_X86 1
#define RAVI_TARGET_X86ORX64 1
#define RAVI_TARGET_EHRETREG 0
#define RAVI_TARGET_MASKSHIFT 1
#define RAVI_TARGET_MASKROT 1
#define RAVI_TARGET_UNALIGNED 1
#elif RAVI__TARGET == RAVI__ARCH_X64
#define RAVI_ARCH_NAME "x64"
#define RAVI_ARCH_BITS 64
#define RAVI_ARCH_ENDIAN RAVI__ARCH_LE
#if RAVI_TARGET_WINDOWS || RAVI_TARGET_CYGWIN
#define RAVI_ABI_WIN 1
#else
#define RAVI_ABI_WIN 0
#endif
#define RAVI_TARGET_X64 1
#define RAVI_TARGET_X86ORX64 1
#define RAVI_TARGET_EHRETREG 0
#define RAVI_TARGET_JUMPRANGE 31 /* +-2^31 = +-2GB */
#define RAVI_TARGET_MASKSHIFT 1
#define RAVI_TARGET_MASKROT 1
#define RAVI_TARGET_UNALIGNED 1
#else
#error "No target architecture defined"
#endif
#ifndef RAVI_PAGESIZE
#define RAVI_PAGESIZE 4096
#endif
#if RAVI_ARCH_ENDIAN == RAVI__ARCH_BE
#define RAVI_LE 0
#define RAVI_BE 1
#define RAVI_ENDIAN_SELECT(le, be) be
#define RAVI_ENDIAN_LOHI(lo, hi) hi lo
#else
#define RAVI_LE 1
#define RAVI_BE 0
#define RAVI_ENDIAN_SELECT(le, be) le
#define RAVI_ENDIAN_LOHI(lo, hi) lo hi
#endif
#if RAVI_ARCH_BITS == 32
#define RAVI_32 1
#define RAVI_64 0
#else
#define RAVI_32 0
#define RAVI_64 1
#endif
#ifndef RAVI_TARGET_UNALIGNED
#define RAVI_TARGET_UNALIGNED 0
#endif
#endif

@ -0,0 +1,22 @@
/*
** LuaJIT common internal definitions.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef RAVI_DEF_H
#define RAVI_DEF_H
#include "lua.h"
#include <stdint.h>
/* Needed everywhere. */
#include <string.h>
#include <stdlib.h>
/* Various macros. */
#ifndef UNUSED
#define UNUSED(x) ((void)(x)) /* to avoid warnings */
#endif
#endif

@ -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 */

@ -0,0 +1,124 @@
/******************************************************************************
* Copyright (C) 2015-2017 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_JITSHARED_H
#define RAVI_JITSHARED_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 <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lauxlib.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 "lua.h"
#include "lvm.h"
#include <ravi_membuf.h>
#define RA(i) (base + GETARG_A(i))
/* to be used after possible stack reallocation */
#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base + GETARG_B(i))
#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base + GETARG_C(i))
#define RKB(i) \
check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \
ISK(GETARG_B(i)) ? k + INDEXK(GETARG_B(i)) : base + GETARG_B(i))
#define RKC(i) \
check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \
ISK(GETARG_C(i)) ? k + INDEXK(GETARG_C(i)) : base + GETARG_C(i))
#define KBx(i) \
(k + (GETARG_Bx(i) != 0 ? GETARG_Bx(i) - 1 : GETARG_Ax(*ci->u.l.savedpc++)))
/* RAVI */
#define KB(i) \
check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k + INDEXK(GETARG_B(i)))
#define KC(i) \
check_exp(getCMode(GET_OPCODE(i)) == OpArgK, k + INDEXK(GETARG_C(i)))
enum errorcode {
Error_integer_expected,
Error_number_expected,
Error_integer_array_expected,
Error_number_array_expected,
Error_table_expected,
Error_upval_needs_integer,
Error_upval_needs_number,
Error_upval_needs_integer_array,
Error_upval_needs_number_array,
Error_upval_needs_table,
Error_for_limit_must_be_number,
Error_for_step_must_be_number,
Error_for_initial_value_must_be_number,
Error_array_out_of_bounds,
};
enum ravi_codegen_type {
RAVI_CODEGEN_NONE = 0,
RAVI_CODEGEN_HEADER_ONLY = 1,
RAVI_CODEGEN_FUNCTION_ONLY = 2,
RAVI_CODEGEN_ALL = 3,
};
struct ravi_compile_options_t {
/* Is this a manual request? */
int manual_request;
/* Should range check be omitted when compiling array access */
int omit_array_get_range_check;
enum ravi_codegen_type codegen_type;
};
LUAI_FUNC bool raviJ_cancompile(Proto *p);
// Convert a Lua function to C code
// Returns true if compilation was successful
// If successful then buf will be set
LUAI_FUNC bool raviJ_codegen(struct lua_State *L, struct Proto *p,
struct ravi_compile_options_t *options,
const char *fname, membuff_t *buf);
#ifdef __cplusplus
};
#endif
#endif

@ -31,6 +31,16 @@
#error Unsupported LLVM version
#endif
#if LLVM_VERSION_MAJOR >= 5
#define USE_ORC_JIT 1
#else
#define USE_ORC_JIT 0
#endif
// In lua.c we include this just to get version numbers
// We cannot have C++ headers in that case
#ifdef __cplusplus
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
@ -60,11 +70,35 @@
#include "llvm/Transforms/Scalar.h"
#include "llvm/Support/FormattedStream.h"
#include <cstdio>
#if USE_ORC_JIT
#include "llvm/ADT/STLExtras.h"
#include "llvm/ExecutionEngine/JITSymbol.h"
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
#include "llvm/ExecutionEngine/Orc/IRTransformLayer.h"
#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
#include "llvm/IR/Mangler.h"
#include "llvm/Support/Error.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/Scalar/GVN.h"
#endif
#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <memory>
#include <string>
#include <cstdio>
#include <vector>
#include <memory>
#endif
#endif //__cplusplus
#endif //USE_LLVM
#endif

@ -1,25 +1,25 @@
/******************************************************************************
* 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.
******************************************************************************/
* 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_LLVMCODEGEN_H
#define RAVI_LLVMCODEGEN_H
@ -29,6 +29,11 @@
#include "ravi_llvm.h"
#include "ravijit.h"
#include <array>
#include <atomic>
#include <iterator>
#include <type_traits>
#ifdef __cplusplus
extern "C" {
#endif
@ -61,11 +66,6 @@ extern "C" {
}
#endif
#include <array>
#include <atomic>
#include <iterator>
#include <type_traits>
namespace ravi {
/*
@ -282,6 +282,9 @@ struct LuaLLVMTypes {
llvm::FunctionType *raviV_op_setupvaltT;
llvm::FunctionType *raviV_gettable_sskeyT;
llvm::FunctionType *raviV_settable_sskeyT;
llvm::FunctionType *raviV_gettable_iT;
llvm::FunctionType *raviV_settable_iT;
llvm::FunctionType *raviV_op_totypeT;
llvm::FunctionType *raviH_set_intT;
llvm::FunctionType *raviH_set_floatT;
@ -293,7 +296,7 @@ struct LuaLLVMTypes {
std::array<llvm::Constant *, 256> kInt;
std::array<llvm::Constant *, 21> kluaInteger;
std::array<llvm::Constant *, 10> kByte;
std::array<llvm::Constant *, 256> kByte;
llvm::Constant *kFalse;
@ -351,7 +354,9 @@ struct LuaLLVMTypes {
llvm::MDNode *tbaa_Table_array;
llvm::MDNode *tbaa_Table_flags;
llvm::MDNode *tbaa_Table_metatable;
#if RAVI_USE_NEWHASH
llvm::MDNode *tbaa_Table_hmask;
#endif
};
// The hierarchy of objects
@ -378,18 +383,171 @@ class RaviJITStateFactory {
static std::unique_ptr<RaviJITState> newJITState();
};
// Ravi's LLVM JIT State
// All of the JIT information is held here
class RaviJITState {
friend class RaviJITModule;
// The LLVM Context
llvm::LLVMContext *context_;
#if USE_ORC_JIT
// From LLVM version5 onwards we use the new ORC apis
// The main benefit is that memory management is tighter,
// all the IR in modules get released after compilation
// MCJIT is also likely to be removed at some time in
// future so we needed to migrate anyway
// We don't use ORC apis in earlier versions because
// the apis have changed over the releases so it
// is simpler to use them in 5.0 and above.
// The ORC usage here is heavily based upon the kaleidoscope
// sample, with some adjustments.
using ObjectLayerT = llvm::orc::RTDyldObjectLinkingLayer;
using CompileLayerT =
llvm::orc::IRCompileLayer<ObjectLayerT, llvm::orc::SimpleCompiler>;
using OptimizeFunction = std::function<std::shared_ptr<llvm::Module>(
std::shared_ptr<llvm::Module>)>;
using OptimizerLayerT =
llvm::orc::IRTransformLayer<CompileLayerT, OptimizeFunction>;
using ModuleHandle = OptimizerLayerT::ModuleHandleT;
std::unique_ptr<llvm::TargetMachine> TM;
std::unique_ptr<llvm::DataLayout> DL;
std::unique_ptr<ObjectLayerT> ObjectLayer;
std::unique_ptr<CompileLayerT> CompileLayer;
std::unique_ptr<OptimizerLayerT> OptimizeLayer;
#endif
// The triple represents the host target
std::string triple_;
// Lua type definitions
LuaLLVMTypes *types_;
// Should we auto compile what we can?
unsigned int auto_ : 1;
// Is JIT enabled
unsigned int enabled_ : 1;
// Optimizer level (LLVM PassManagerBuilder)
unsigned int opt_level_ : 2;
// Size level (LLVM PassManagerBuilder)
unsigned int size_level_ : 2;
// Verbosity
unsigned int verbosity_ : 3;
// enable calls to luaG_traceexec() at every bytecode
// instruction; this is expensive!
unsigned int tracehook_enabled_ : 1;
// Enable extra validation such as IR verification
// May slow down compilation
unsigned int validation_ : 1;
// Flag to control calls to collect
int gcstep_;
// min code size for compilation
int min_code_size_;
// min execution count for compilation
int min_exec_count_;
// Count of modules allocated
// Used to debug module deallocation
size_t allocated_modules_;
// flag to help avoid recursion
int compiling_;
public:
RaviJITState();
~RaviJITState();
#if USE_ORC_JIT
std::shared_ptr<llvm::Module> optimizeModule(std::shared_ptr<llvm::Module> M);
llvm::TargetMachine &getTargetMachine() { return *TM; }
ModuleHandle addModule(std::unique_ptr<llvm::Module> M);
llvm::JITSymbol findSymbol(const std::string Name);
void removeModule(ModuleHandle H);
#endif
void addGlobalSymbol(const std::string &name, void *address);
void dump();
llvm::LLVMContext &context() { return *context_; }
LuaLLVMTypes *types() const { return types_; }
const std::string &triple() const { return triple_; }
bool is_auto() const { return auto_; }
void set_auto(bool value) { auto_ = value; }
bool is_enabled() const { return enabled_; }
void set_enabled(bool value) { enabled_ = value; }
int get_optlevel() const { return opt_level_; }
void set_optlevel(int value) {
if (value >= 0 && value <= 3) opt_level_ = value;
}
int get_sizelevel() const { return size_level_; }
void set_sizelevel(int value) {
if (value >= 0 && value <= 2) size_level_ = value;
}
int get_verbosity() const { return verbosity_; }
void set_verbosity(int value) {
if (value >= 0 && value <= 3) verbosity_ = value;
}
int get_mincodesize() const { return min_code_size_; }
void set_mincodesize(int value) {
min_code_size_ = value > 0 ? value : min_code_size_;
}
int get_minexeccount() const { return min_exec_count_; }
void set_minexeccount(int value) {
min_exec_count_ = value > 0 ? value : min_exec_count_;
}
int get_validation() const { return validation_; }
void set_validation(bool value) { validation_ = value; }
int get_gcstep() const { return gcstep_; }
void set_gcstep(int value) {
gcstep_ = value > 0 ? value : gcstep_;
}
bool is_tracehook_enabled() const { return tracehook_enabled_; }
void set_tracehook_enabled(bool value) { tracehook_enabled_ = value; }
void incr_allocated_modules() { allocated_modules_++; }
void decr_allocated_modules() { allocated_modules_--; }
size_t allocated_modules() const { return allocated_modules_; }
int get_compiling_flag() const { return compiling_ > 0; }
void set_compiling_flag(bool value) {
if (value)
compiling_++;
else
compiling_--;
}
};
// A wrapper for LLVM Module
// Maintains a dedicated ExecutionEngine for the module
class RaviJITModule {
// The Context that owns this module
RaviJITState *owner_;
#if !USE_ORC_JIT
// The LLVM Module within which the functions will be defined
llvm::Module *module_;
// The execution engine responsible for compiling the
// module
llvm::ExecutionEngine *engine_;
#else
// The LLVM Module within which the functions will be defined
llvm::Module *module_;
std::unique_ptr<llvm::Module> module_;
// With ORC, once a module is compiled (added to the JIT)
// then a handle is used to refer to it rather than the
// module, as the module may have been deleted by then
RaviJITState::ModuleHandle module_handle_;
#endif
// List of JIT functions in this module
// We need this so that we can update the functions
@ -403,8 +561,13 @@ class RaviJITModule {
RaviJITModule(RaviJITState *owner);
~RaviJITModule();
#if !USE_ORC_JIT
llvm::Module *module() const { return module_; }
llvm::ExecutionEngine *engine() const { return engine_; }
#else
// Note that this can return nullptr
llvm::Module *module() const { return module_.get(); }
#endif
RaviJITState *owner() const { return owner_; }
void dump();
void dumpAssembly();
@ -464,18 +627,25 @@ class RaviJITFunction {
lua_CFunction *func_ptrptr_;
public:
RaviJITFunction(lua_CFunction *p, std::shared_ptr<RaviJITModule> module,
RaviJITFunction(lua_CFunction *p,
const std::shared_ptr<RaviJITModule> &module,
llvm::FunctionType *type,
llvm::GlobalValue::LinkageTypes linkage,
const std::string &name);
RaviJITFunction(lua_CFunction *p,
const std::shared_ptr<RaviJITModule> &module,
const std::string &name);
~RaviJITFunction();
const std::string &name() const { return name_; }
llvm::Function *function() const { return function_; }
// Note that this can return nullptr
llvm::Module *module() const { return module_->module(); }
std::shared_ptr<RaviJITModule> raviModule() const { return module_; }
#if !USE_ORC_JIT
llvm::ExecutionEngine *engine() const { return module_->engine(); }
#endif
RaviJITState *owner() const { return module_->owner(); }
// This method retrieves the JITed function from the
// execution engine and sets ptr_ member
@ -492,86 +662,6 @@ class RaviJITFunction {
}
};
// Ravi's LLVM JIT State
// All of the JIT information is held here
class RaviJITState {
// The LLVM Context
llvm::LLVMContext *context_;
// The triple represents the host target
std::string triple_;
// Lua type definitions
LuaLLVMTypes *types_;
// Should we auto compile what we can?
bool auto_;
// Is JIT enabled
bool enabled_;
// Optimizer level (LLVM PassManagerBuilder)
int opt_level_;
// Size level (LLVM PassManagerBuilder)
int size_level_;
// min code size for compilation
int min_code_size_;
// min execution count for compilation
int min_exec_count_;
// gc step size; defaults to 200
int gc_step_;
// enable calls to luaG_traceexec() at every bytecode
// instruction; this is expensive!
bool tracehook_enabled_;
// Count of modules allocated
// Used to debug module deallocation
size_t allocated_modules_;
public:
RaviJITState();
~RaviJITState();
void addGlobalSymbol(const std::string &name, void *address);
void dump();
llvm::LLVMContext &context() { return *context_; }
LuaLLVMTypes *types() const { return types_; }
const std::string &triple() const { return triple_; }
bool is_auto() const { return auto_; }
void set_auto(bool value) { auto_ = value; }
bool is_enabled() const { return enabled_; }
void set_enabled(bool value) { enabled_ = value; }
int get_optlevel() const { return opt_level_; }
void set_optlevel(int value) {
if (value >= 0 && value <= 3) opt_level_ = value;
}
int get_sizelevel() const { return size_level_; }
void set_sizelevel(int value) {
if (value >= 0 && value <= 2) size_level_ = value;
}
int get_mincodesize() const { return min_code_size_; }
void set_mincodesize(int value) {
min_code_size_ = value > 0 ? value : min_code_size_;
}
int get_minexeccount() const { return min_exec_count_; }
void set_minexeccount(int value) {
min_exec_count_ = value > 0 ? value : min_exec_count_;
}
int get_gcstep() const { return gc_step_; }
void set_gcstep(int value) { gc_step_ = value > 0 ? value : gc_step_; }
bool is_tracehook_enabled() const { return tracehook_enabled_; }
void set_tracehook_enabled(bool value) { tracehook_enabled_ = value; }
void incr_allocated_modules() { allocated_modules_++; }
void decr_allocated_modules() { allocated_modules_--; }
size_t allocated_modules() const { return allocated_modules_; }
};
// To optimise fornum loops
// i.e. OP_FORPREP and OP_FORLOOP instructions
// we use computed gotos to specialised
@ -670,6 +760,9 @@ struct RaviFunctionDef {
llvm::Function *raviV_op_setupvaltF;
llvm::Function *raviV_gettable_sskeyF;
llvm::Function *raviV_settable_sskeyF;
llvm::Function *raviV_gettable_iF;
llvm::Function *raviV_settable_iF;
llvm::Function *raviV_op_totypeF;
// array setters
llvm::Function *raviH_set_intF;
@ -809,7 +902,7 @@ class RaviCodeGenerator {
// The return value is a boolean type as a result of
// integer comparison result which is i1 in LLVM
llvm::Value *emit_is_not_value_of_type_class(
RaviFunctionDef *def, llvm::Value *value_type, LuaTypeCode lua_typecode,
RaviFunctionDef *def, llvm::Value *value_type, int lua_typecode,
const char *varname = "value.not.typeof");
// emit code for LClosure *cl = clLvalue(ci->func)
@ -817,9 +910,10 @@ class RaviCodeGenerator {
// emit code for (LClosure *)ci->func->value_.gc
llvm::Instruction *emit_gep_ci_func_value_gc_asLClosure(RaviFunctionDef *def);
llvm::Value *emit_gep(RaviFunctionDef *def, const char *name, llvm::Value *s,
int arg1);
llvm::Value *emit_gep(RaviFunctionDef *def, const char *name, llvm::Value *s,
int arg1, int arg2);
llvm::Value *emit_gep(RaviFunctionDef *def, const char *name, llvm::Value *s,
int arg1, int arg2, int arg3);
llvm::Value *emit_gep(RaviFunctionDef *def, const char *name,
@ -1042,11 +1136,26 @@ class RaviCodeGenerator {
void emit_LOADBOOL(RaviFunctionDef *def, int A, int B, int C, int j, int pc);
void emit_ARITH(RaviFunctionDef *def, int A, int B, int C, OpCode op, TMS tms,
int pc);
// Code size priority so go via function calls
void emit_ARITH_calls(RaviFunctionDef *def, int A, int B, int C, OpCode op,
TMS tms, int pc);
void emit_ARITH_new(RaviFunctionDef *def, int A, int B, int C, OpCode op,
TMS tms, int pc);
// integer arith priority over floating
void emit_ARITH_intpriority(RaviFunctionDef *def, int A, int B, int C,
OpCode op, TMS tms, int pc);
// floating arith priority over integer
void emit_ARITH_floatpriority(RaviFunctionDef *def, int A, int B, int C,
OpCode op, TMS tms, int pc);
inline void emit_ARITH(RaviFunctionDef *def, int A, int B, int C, OpCode op,
TMS tms, int pc) {
#if RAVI_USE_LLVM_ARITH_FLOATPRIORITY
emit_ARITH_floatpriority(def, A, B, C, op, tms, pc);
#else
emit_ARITH_intpriority(def, A, B, C, op, tms, pc);
#endif
}
void emit_MOD(RaviFunctionDef *def, int A, int B, int C, int pc);
@ -1121,6 +1230,12 @@ class RaviCodeGenerator {
void emit_TOFLT(RaviFunctionDef *def, int A, int pc);
void emit_TOSTRING(RaviFunctionDef *def, int A, int pc);
void emit_TOCLOSURE(RaviFunctionDef *def, int A, int pc);
void emit_TOTYPE(RaviFunctionDef *def, int A, int Bx, int pc);
void emit_LEN(RaviFunctionDef *def, int A, int B, int pc);
void emit_SETTABLE(RaviFunctionDef *def, int A, int B, int C, int pc);
@ -1253,7 +1368,7 @@ class RaviCodeGenerator {
char temp_[31]; // for name
int id_; // for name
};
}
} // namespace ravi
struct ravi_State {
ravi::RaviJITState *jit;

@ -0,0 +1,28 @@
#ifndef RAVI_MEMBUF_H
#define RAVI_MEMBUF_H
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
typedef struct {
char *buf;
size_t allocated_size;
size_t pos;
} membuff_t;
extern void membuff_init(membuff_t *mb, size_t initial_size);
extern void membuff_rewindpos(membuff_t *mb);
extern void membuff_resize(membuff_t *mb, size_t new_size);
extern void membuff_free(membuff_t *mb);
extern void membuff_add_string(membuff_t *mb, const char *str);
extern void membuff_add_fstring(membuff_t *mb, const char *str, ...);
extern void membuff_add_bool(membuff_t *mb, bool value);
extern void membuff_add_int(membuff_t *mb, int value);
extern void membuff_add_longlong(membuff_t *mb, int64_t value);
/* strncpy() with guaranteed 0 termination */
extern void ravi_string_copy(char *buf, const char *src, size_t buflen);
#endif

@ -29,20 +29,7 @@ extern "C" {
struct lua_State;
struct Proto;
typedef struct {
/* Is this a manual request? */
int manual_request;
/* Should range check be omitted when compiling array access */
int omit_array_get_range_check;
/* Should the compiler dump generated code ? */
int dump_level;
/* Should the compiler validate the generated code ? */
int verification_level;
} ravi_compile_options_t;
typedef struct ravi_compile_options_t ravi_compile_options_t;
/* Initialise the JIT engine */
int raviV_initjit(struct lua_State *L);
@ -68,6 +55,10 @@ int raviV_getsizelevel(struct lua_State *L);
/* Set optimizer level */
void raviV_setoptlevel(struct lua_State *L, int optlevel);
int raviV_getoptlevel(struct lua_State *L);
/* Set verbosity */
void raviV_setverbosity(struct lua_State *L, int verbosity);
int raviV_getverbosity(struct lua_State *L);
/* Enable or disable JIT */
void raviV_setjitenabled(struct lua_State *L, int enabled);
@ -85,8 +76,12 @@ int raviV_getmincodesize(struct lua_State *L);
void raviV_setminexeccount(struct lua_State *L, int minexecccount);
int raviV_getminexeccount(struct lua_State *L);
/* Enable GC Collection at every JIT compile */
void raviV_setgcstep(struct lua_State *L, int stepsize);
/* Enable IR / codegen validations */
void raviV_setvalidation(struct lua_State *L, int enabled);
int raviV_getvalidation(struct lua_State *L);
/* Enable calls to GCSTEP */
void raviV_setgcstep(struct lua_State *L, int value);
int raviV_getgcstep(struct lua_State *L);
/* Enable or disable trace hook */

@ -22,6 +22,8 @@ _soft = rawget(_G, "_soft") or false
_port = rawget(_G, "_port") or false
-- Make true to avoid messages about tests not performed
_nomsg = rawget(_G, "_nomsg") or false
-- JIT test mode, 1 = some time consuming tests skipped, 2 = all tests
_jit = rawget(_G, "_jit") or 1
local usertests = rawget(_G, "_U")

@ -44,7 +44,7 @@ function check (f, ...)
local arg = {...}
local c = T.listcode(f)
for i=1, #arg do
-- print(arg[i], c[i])
--print(arg[i], c[i])
assert(string.find(c[i], '- '..arg[i]..' *%d'))
end
assert(c[#arg+2] == nil)
@ -65,7 +65,7 @@ end
-- some basic instructions
check(function ()
(function () end){f()}
end, 'CLOSURE', 'NEWTABLE', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN')
end, 'CLOSURE', 'NEWTABLE', 'GETTABUP_SK', 'CALL', 'SETLIST', 'CALL', 'RETURN')
-- sequence of LOADNILs
@ -121,8 +121,8 @@ check(function ()
end,
'LOADNIL',
'MUL',
'DIV', 'ADD', 'GETTABLE', 'SUB', 'GETTABLE', 'POW',
'UNM', 'SETTABLE', 'SETTABLE', 'RETURN')
'DIV', 'ADD', 'GETTABLE', 'SUB', 'GETTABLE_SK', 'POW',
'UNM', 'SETTABLE', 'SETTABLE_I', 'RETURN')
-- direct access to constants
@ -132,7 +132,7 @@ check(function ()
a.x = b
a[b] = 'x'
end,
'LOADNIL', 'SETTABLE', 'SETTABLE', 'SETTABLE', 'RETURN')
'LOADNIL', 'SETTABLE_SK', 'SETTABLE_SK', 'SETTABLE', 'RETURN')
check(function ()
local a,b
@ -202,7 +202,7 @@ checkequal(function () if (a==nil) then a=1 end; if a~=nil then a=1 end end,
function () if (a==9) then a=1 end; if a~=9 then a=1 end end)
check(function () if a==nil then a='a' end end,
'GETTABUP', 'EQ', 'JMP', 'SETTABUP', 'RETURN')
'GETTABUP_SK', 'EQ', 'JMP', 'SETTABUP', 'RETURN')
-- de morgan
checkequal(function () local a; if not (a or b) then b=a end end,

@ -278,7 +278,7 @@ local function createcases (n)
end
-- do not do too many combinations for soft tests
local level = _soft and 3 or 4
local level = (_soft or _jit == 1) and 3 or 4
cases[1] = basiccases
for i = 2, level do cases[i] = createcases(i) end
@ -294,6 +294,9 @@ for n = 1, level do
IX = false
assert(p() == v[2] and IX == not not v[2])
i = i + 1
if _jit > 0 and i % 1000 == 0 then
collectgarbage()
end
if i % 60000 == 0 then print('+') end
end
end

@ -0,0 +1,69 @@
-- Microbenchmark for bit operations library. Public domain.
local bit = require"bit"
if not bit.rol then -- Replacement function if rotates are missing.
local bor, shl, shr = bit.bor, bit.lshift, bit.rshift
function bit.rol(a, b) return bor(shl(a, b), shr(a, 32-b)) end
end
if not bit.bswap then -- Replacement function if bswap is missing.
local bor, band, shl, shr = bit.bor, bit.band, bit.lshift, bit.rshift
function bit.bswap(a)
return bor(shr(a, 24), band(shr(a, 8), 0xff00),
shl(band(a, 0xff00), 8), shl(a, 24));
end
end
local base = 0
local function bench(name, t)
local n = 2000000
repeat
local tm = os.clock()
t(n)
tm = os.clock() - tm
if tm > 1 then
local ns = tm*1000/(n/1000000)
io.write(string.format("%-15s %6.1f ns\n", name, ns-base))
return ns
end
n = n + n
until false
end
-- The overhead for the base loop is subtracted from the other measurements.
base = bench("loop baseline", function(n)
local x = 0; for i=1,n do x = x + i end
end)
bench("tobit", function(n)
local f = bit.tobit or bit.cast
local x = 0; for i=1,n do x = x + f(i) end
end)
bench("bnot", function(n)
local f = bit.bnot
local x = 0; for i=1,n do x = x + f(i) end
end)
bench("bor/band/bxor", function(n)
local f = bit.bor
local x = 0; for i=1,n do x = x + f(i, 1) end
end)
bench("shifts", function(n)
local f = bit.lshift
local x = 0; for i=1,n do x = x + f(i, 1) end
end)
bench("rotates", function(n)
local f = bit.rol
local x = 0; for i=1,n do x = x + f(i, 1) end
end)
bench("bswap", function(n)
local f = bit.bswap
local x = 0; for i=1,n do x = x + f(i) end
end)

@ -0,0 +1,85 @@
-- Test cases for bit operations library. Public domain.
local bit = require"bit"
local vb = {
0, 1, -1, 2, -2, 0x12345678, 0x87654321,
0x33333333, 0x77777777, 0x55aa55aa, 0xaa55aa55,
0x7fffffff, 0x80000000, 0xffffffff
}
local function cksum(name, s, r)
local z = 0
for i=1,#s do z = (z + string.byte(s, i)*i) % 2147483629 end
if z ~= r then
error("bit."..name.." test failed (got "..z..", expected "..r..")", 0)
end
end
local function check_unop(name, r)
local f = bit[name]
local s = ""
if pcall(f) or pcall(f, "z") or pcall(f, true) then
error("bit."..name.." fails to detect argument errors", 0)
end
for _,x in ipairs(vb) do s = s..","..tostring(f(x)) end
cksum(name, s, r)
end
local function check_binop(name, r)
local f = bit[name]
local s = ""
if pcall(f) or pcall(f, "z") or pcall(f, true) then
error("bit."..name.." fails to detect argument errors", 0)
end
for _,x in ipairs(vb) do
for _,y in ipairs(vb) do s = s..","..tostring(f(x, y)) end
end
cksum(name, s, r)
end
local function check_binop_range(name, r, yb, ye)
local f = bit[name]
local s = ""
if pcall(f) or pcall(f, "z") or pcall(f, true) or pcall(f, 1, true) then
error("bit."..name.." fails to detect argument errors", 0)
end
for _,x in ipairs(vb) do
for y=yb,ye do s = s..","..tostring(f(x, y)) end
end
cksum(name, s, r)
end
local function check_shift(name, r)
check_binop_range(name, r, 0, 31)
end
-- Minimal sanity checks.
assert(0x7fffffff == 2147483647, "broken hex literals")
assert(0xffffffff == -1 or 0xffffffff == 2^32-1, "broken hex literals")
assert(tostring(-1) == "-1", "broken tostring()")
assert(tostring(0xffffffff) == "-1" or tostring(0xffffffff) == "4294967295", "broken tostring()")
-- Basic argument processing.
assert(bit.tobit(1) == 1)
assert(bit.band(1) == 1)
assert(bit.bxor(1,2) == 3)
assert(bit.bor(1,2,4,8,16,32,64,128) == 255)
-- Apply operations to test vectors and compare checksums.
check_unop("tobit", 277312)
check_unop("bnot", 287870)
check_unop("bswap", 307611)
check_binop("band", 41206764)
check_binop("bor", 51253663)
check_binop("bxor", 79322427)
check_shift("lshift", 325260344)
check_shift("rshift", 139061800)
check_shift("arshift", 111364720)
check_shift("rol", 302401155)
check_shift("ror", 302316761)
check_binop_range("tohex", 47880306, -8, 8)

@ -0,0 +1,38 @@
-- Print anything - including nested tables
local function table_print (tt, indent, done)
done = done or {}
indent = indent or 0
if type(tt) == "table" then
for key, value in pairs (tt) do
io.write(string.rep (" ", indent)) -- indent it
if type (value) == "table" and not done [value] then
done [value] = true
io.write(string.format("[%s] => table\n", tostring (key)));
io.write(string.rep (" ", indent+4)) -- indent it
io.write("(\n");
table_print (value, indent + 7, done)
io.write(string.rep (" ", indent+4)) -- indent it
io.write(")\n");
else
io.write(string.format("[%s] => %s\n",
tostring (key), tostring(value)))
end
end
else
io.write(tostring(tt) .. "\n")
end
end
local somecode = [[
extern int adder(int a, int b);
int adder(int a, int b)
{
return a+b;
}
]]
local symbols = dmrc.getsymbols(somecode)
table_print(symbols)

@ -0,0 +1,20 @@
local testfunc = [[
struct lua_State;
extern int puts(const char *);
extern int TestFunc(struct lua_State *L);
int TestFunc(struct lua_State *L)
{
puts("hello world!\n");
return 0;
}
]]
local ctx = llvm.context()
local m = ctx:newmodule()
m:compileC(testfunc)
local f = m:getfunction("TestFunc")
local callable = f:compile()
callable()

@ -13,7 +13,7 @@ function matrix.T(a: table)
end
function matrix.mul(a: table, b: table)
assert(#a[1] == #b);
assert(@integer(#a[1]) == #b);
local m: integer, n: integer, p: integer, x: table = #a, #a[1], #b[1], {};
local c: table = matrix.T(b); -- transpose for efficiency
for i = 1, m do
@ -44,9 +44,9 @@ end
--ravi.dumplua(matgen)
if ravi and ravi.jit() then
ravi.compile(matrix.T)
ravi.compile(matrix.mul, {omitArrayGetRangeCheck=1})
ravi.compile(matgen)
assert(ravi.compile(matrix.T))
assert(ravi.compile(matrix.mul, {omitArrayGetRangeCheck=1}))
assert(ravi.compile(matgen))
end
local n = arg[1] or 1000;

@ -0,0 +1,196 @@
-- MD5 test and benchmark. Public domain.
local bit = require("bit")
local tobit, tohex, bnot = bit.tobit or bit.cast, bit.tohex, bit.bnot
local bor, band, bxor = bit.bor, bit.band, bit.bxor
local lshift, rshift, rol, bswap = bit.lshift, bit.rshift, bit.rol, bit.bswap
local byte, char, sub, rep = string.byte, string.char, string.sub, string.rep
if not rol then -- Replacement function if rotates are missing.
local bor, shl, shr = bit.bor, bit.lshift, bit.rshift
function rol(a, b) return bor(shl(a, b), shr(a, 32-b)) end
end
if not bswap then -- Replacement function if bswap is missing.
local bor, band, shl, shr = bit.bor, bit.band, bit.lshift, bit.rshift
function bswap(a)
return bor(shr(a, 24), band(shr(a, 8), 0xff00),
shl(band(a, 0xff00), 8), shl(a, 24));
end
end
if not tohex then -- (Unreliable) replacement function if tohex is missing.
function tohex(a)
return string.sub(string.format("%08x", a), -8)
end
end
local function tr_f(a, b, c, d, x, s)
return rol(bxor(d, band(b, bxor(c, d))) + a + x, s) + b
end
local function tr_g(a, b, c, d, x, s)
return rol(bxor(c, band(d, bxor(b, c))) + a + x, s) + b
end
local function tr_h(a, b, c, d, x, s)
return rol(bxor(b, c, d) + a + x, s) + b
end
local function tr_i(a, b, c, d, x, s)
return rol(bxor(c, bor(b, bnot(d))) + a + x, s) + b
end
local function transform(x, a1, b1, c1, d1)
local a, b, c, d = a1, b1, c1, d1
a = tr_f(a, b, c, d, x[ 1] + 0xd76aa478, 7)
d = tr_f(d, a, b, c, x[ 2] + 0xe8c7b756, 12)
c = tr_f(c, d, a, b, x[ 3] + 0x242070db, 17)
b = tr_f(b, c, d, a, x[ 4] + 0xc1bdceee, 22)
a = tr_f(a, b, c, d, x[ 5] + 0xf57c0faf, 7)
d = tr_f(d, a, b, c, x[ 6] + 0x4787c62a, 12)
c = tr_f(c, d, a, b, x[ 7] + 0xa8304613, 17)
b = tr_f(b, c, d, a, x[ 8] + 0xfd469501, 22)
a = tr_f(a, b, c, d, x[ 9] + 0x698098d8, 7)
d = tr_f(d, a, b, c, x[10] + 0x8b44f7af, 12)
c = tr_f(c, d, a, b, x[11] + 0xffff5bb1, 17)
b = tr_f(b, c, d, a, x[12] + 0x895cd7be, 22)
a = tr_f(a, b, c, d, x[13] + 0x6b901122, 7)
d = tr_f(d, a, b, c, x[14] + 0xfd987193, 12)
c = tr_f(c, d, a, b, x[15] + 0xa679438e, 17)
b = tr_f(b, c, d, a, x[16] + 0x49b40821, 22)
a = tr_g(a, b, c, d, x[ 2] + 0xf61e2562, 5)
d = tr_g(d, a, b, c, x[ 7] + 0xc040b340, 9)
c = tr_g(c, d, a, b, x[12] + 0x265e5a51, 14)
b = tr_g(b, c, d, a, x[ 1] + 0xe9b6c7aa, 20)
a = tr_g(a, b, c, d, x[ 6] + 0xd62f105d, 5)
d = tr_g(d, a, b, c, x[11] + 0x02441453, 9)
c = tr_g(c, d, a, b, x[16] + 0xd8a1e681, 14)
b = tr_g(b, c, d, a, x[ 5] + 0xe7d3fbc8, 20)
a = tr_g(a, b, c, d, x[10] + 0x21e1cde6, 5)
d = tr_g(d, a, b, c, x[15] + 0xc33707d6, 9)
c = tr_g(c, d, a, b, x[ 4] + 0xf4d50d87, 14)
b = tr_g(b, c, d, a, x[ 9] + 0x455a14ed, 20)
a = tr_g(a, b, c, d, x[14] + 0xa9e3e905, 5)
d = tr_g(d, a, b, c, x[ 3] + 0xfcefa3f8, 9)
c = tr_g(c, d, a, b, x[ 8] + 0x676f02d9, 14)
b = tr_g(b, c, d, a, x[13] + 0x8d2a4c8a, 20)
a = tr_h(a, b, c, d, x[ 6] + 0xfffa3942, 4)
d = tr_h(d, a, b, c, x[ 9] + 0x8771f681, 11)
c = tr_h(c, d, a, b, x[12] + 0x6d9d6122, 16)
b = tr_h(b, c, d, a, x[15] + 0xfde5380c, 23)
a = tr_h(a, b, c, d, x[ 2] + 0xa4beea44, 4)
d = tr_h(d, a, b, c, x[ 5] + 0x4bdecfa9, 11)
c = tr_h(c, d, a, b, x[ 8] + 0xf6bb4b60, 16)
b = tr_h(b, c, d, a, x[11] + 0xbebfbc70, 23)
a = tr_h(a, b, c, d, x[14] + 0x289b7ec6, 4)
d = tr_h(d, a, b, c, x[ 1] + 0xeaa127fa, 11)
c = tr_h(c, d, a, b, x[ 4] + 0xd4ef3085, 16)
b = tr_h(b, c, d, a, x[ 7] + 0x04881d05, 23)
a = tr_h(a, b, c, d, x[10] + 0xd9d4d039, 4)
d = tr_h(d, a, b, c, x[13] + 0xe6db99e5, 11)
c = tr_h(c, d, a, b, x[16] + 0x1fa27cf8, 16)
b = tr_h(b, c, d, a, x[ 3] + 0xc4ac5665, 23)
a = tr_i(a, b, c, d, x[ 1] + 0xf4292244, 6)
d = tr_i(d, a, b, c, x[ 8] + 0x432aff97, 10)
c = tr_i(c, d, a, b, x[15] + 0xab9423a7, 15)
b = tr_i(b, c, d, a, x[ 6] + 0xfc93a039, 21)
a = tr_i(a, b, c, d, x[13] + 0x655b59c3, 6)
d = tr_i(d, a, b, c, x[ 4] + 0x8f0ccc92, 10)
c = tr_i(c, d, a, b, x[11] + 0xffeff47d, 15)
b = tr_i(b, c, d, a, x[ 2] + 0x85845dd1, 21)
a = tr_i(a, b, c, d, x[ 9] + 0x6fa87e4f, 6)
d = tr_i(d, a, b, c, x[16] + 0xfe2ce6e0, 10)
c = tr_i(c, d, a, b, x[ 7] + 0xa3014314, 15)
b = tr_i(b, c, d, a, x[14] + 0x4e0811a1, 21)
a = tr_i(a, b, c, d, x[ 5] + 0xf7537e82, 6)
d = tr_i(d, a, b, c, x[12] + 0xbd3af235, 10)
c = tr_i(c, d, a, b, x[ 3] + 0x2ad7d2bb, 15)
b = tr_i(b, c, d, a, x[10] + 0xeb86d391, 21)
return tobit(a+a1), tobit(b+b1), tobit(c+c1), tobit(d+d1)
end
-- Note: this is copying the original string and NOT particularly fast.
-- A library for struct unpacking would make this task much easier.
local function md5(msg)
local len = #msg
msg = msg.."\128"..rep("\0", 63 - band(len + 8, 63))
..char(band(lshift(len, 3), 255), band(rshift(len, 5), 255),
band(rshift(len, 13), 255), band(rshift(len, 21), 255))
.."\0\0\0\0"
local a, b, c, d = 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476
local x, k = {}, 1
for i=1,#msg,4 do
local m0, m1, m2, m3 = byte(msg, i, i+3)
x[k] = bor(m0, lshift(m1, 8), lshift(m2, 16), lshift(m3, 24))
if k == 16 then
a, b, c, d = transform(x, a, b, c, d)
k = 1
else
k = k + 1
end
end
return tohex(bswap(a))..tohex(bswap(b))..tohex(bswap(c))..tohex(bswap(d))
end
assert(md5('') == 'd41d8cd98f00b204e9800998ecf8427e')
assert(md5('a') == '0cc175b9c0f1b6a831c399e269772661')
assert(md5('abc') == '900150983cd24fb0d6963f7d28e17f72')
assert(md5('message digest') == 'f96b697d7cb7938d525a2f31aaf161d0')
assert(md5('abcdefghijklmnopqrstuvwxyz') == 'c3fcd3d76192e4007dfb496cca67e13b')
assert(md5('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') ==
'd174ab98d277d9f5a5611c2c9f419d9f')
assert(md5('12345678901234567890123456789012345678901234567890123456789012345678901234567890') ==
'57edf4a22be3c955ac49da2e2107b67a')
if arg and arg[1] == "bench" then
-- Credits: William Shakespeare, Romeo and Juliet
local txt = [[Rebellious subjects, enemies to peace,
Profaners of this neighbour-stained steel,--
Will they not hear? What, ho! you men, you beasts,
That quench the fire of your pernicious rage
With purple fountains issuing from your veins,
On pain of torture, from those bloody hands
Throw your mistemper'd weapons to the ground,
And hear the sentence of your moved prince.
Three civil brawls, bred of an airy word,
By thee, old Capulet, and Montague,
Have thrice disturb'd the quiet of our streets,
And made Verona's ancient citizens
Cast by their grave beseeming ornaments,
To wield old partisans, in hands as old,
Canker'd with peace, to part your canker'd hate:
If ever you disturb our streets again,
Your lives shall pay the forfeit of the peace.
For this time, all the rest depart away:
You Capulet; shall go along with me:
And, Montague, come you this afternoon,
To know our further pleasure in this case,
To old Free-town, our common judgment-place.
Once more, on pain of death, all men depart.]]
txt = txt..txt..txt..txt
txt = txt..txt..txt..txt
local function bench()
local n = 80
repeat
local tm = os.clock()
local res
for i=1,n do
res = md5(txt)
end
assert(res == 'a831e91e0f70eddcb70dc61c6f82f6cd')
tm = os.clock() - tm
if tm > 1 then return tm*(1000000000/(n*#txt)) end
n = n + n
until false
end
io.write(string.format("MD5 %7.1f ns/char\n", bench()))
end

@ -0,0 +1,32 @@
-- This is the (naive) Sieve of Eratosthenes. Public domain.
local bit = require("bit")
local band, bxor, rshift, rol = bit.band, bit.bxor, bit.rshift, bit.rol
local function nsieve(p, m)
local count = 0
for i=0,rshift(m, 5) do p[i] = -1 end
for i=2,m do
if band(rshift(p[rshift(i, 5)], i), 1) ~= 0 then
count = count + 1
for j=i+i,m,i do
local jx = rshift(j, 5)
p[jx] = band(p[jx], rol(-2, j))
end
end
end
return count
end
if arg and arg[1] then
local N = tonumber(arg[1]) or 1
if N < 2 then N = 2 end
local primes = {}
for i=0,2 do
local m = (2^(N-i))*10000
io.write(string.format("Primes up to %8d %8d\n", m, nsieve(primes, m)))
end
else
assert(nsieve({}, 10000) == 1229)
end

@ -95,5 +95,15 @@ checkmessage('local mt: number[] = {}; local t: table = {}; setmetatable(t, mt)'
checkmessage('for i=1,10 do i="a" end', 'Invalid assignment: integer expected')
checkmessage('for i=1,10 do local f = function() i="a" end; f(); end', 'upvalue of integer type, cannot be set to non integer value')
checkmessage('local x: number[] = {1,2}; x:try()', 'attempt to incorrectly index a table value')
checkmessage('@integer ""', 'unexpected symbol near @integer') -- FIXME bad error message
checkmessage('@string 1', 'unexpected symbol near @string') -- FIXME bad error message
checkmessage('@MyType 1', "unexpected symbol near '@'") -- FIXME bad error message
checkmessage('local function x(y: MyType) end x(1)', 'type mismatch: expected MyType')
checkmessage('local function x(y: string) end x(1)', 'string expected')
checkmessage('local function x(y: closure) end x(1)', 'closure expected')
checkmessage('local function x() local s: string; s = 1 end', "Invalid assignment: string expected near 'end'")
checkmessage('function x() local s: string; s = (function() return 1 end)() end; x()', 'string expected')
checkmessage('function x() local s: User; s = (function() return 1 end)() end; x()', 'type mismatch: expected User')
print 'Ok'

@ -0,0 +1,21 @@
local tests = {}
tests.RETURN = function()
return
end
tests.LOADK = function()
return 1, 4.2, 'hello'
end
tests.MOVE = function(a, b)
local c,d = a,b
return c,d
end
for k,v in pairs(tests) do
print(k)
ravi.dumplua(v)
--v()
end

@ -11,8 +11,10 @@ opcodes_coverage.LOADBOOL = 0
opcodes_coverage.LOADNIL = 0
opcodes_coverage.GETUPVAL = 0
opcodes_coverage.GETTABUP = 0
opcodes_coverage.GETTABUP_SK = 0
opcodes_coverage.GETTABLE = 0
opcodes_coverage.SETTABUP = 0
opcodes_coverage.SETTABUP_SK = 0
opcodes_coverage.SETUPVAL = 0
opcodes_coverage.SETTABLE = 0
opcodes_coverage.NEWTABLE = 0
@ -109,11 +111,16 @@ opcodes_coverage.GETTABLE_I = 0
opcodes_coverage.GETTABLE_S = 0
opcodes_coverage.SETTABLE_I = 0
opcodes_coverage.SETTABLE_S = 0
opcodes_coverage.SETTABLE_SK = 0
opcodes_coverage.GETTABLE_SK = 0
opcodes_coverage.TOTAB = 0
opcodes_coverage.MOVETAB = 0
opcodes_coverage.SETUPVALT = 0
opcodes_coverage.SELF_S = 0
opcodes_coverage.TOTYPE = 0
opcodes_coverage.TOSTRING = 0
opcodes_coverage.TOCLOSURE = 0
opcodes_coverage.SELF_SK = 0
local compile = function(f)
if ravi.jit() then
@ -154,7 +161,7 @@ end
-- some basic instructions
check(function ()
(function () end){f()}
end, 'CLOSURE', 'NEWTABLE', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN')
end, 'CLOSURE', 'NEWTABLE', 'GETTABUP_SK', 'CALL', 'SETLIST', 'CALL', 'RETURN')
-- sequence of LOADNILs
check(function ()
@ -208,8 +215,8 @@ check(function ()
end,
'LOADNIL',
'MUL',
'DIV', 'ADD', 'GETTABLE', 'SUB', 'GETTABLE', 'POW',
'UNM', 'SETTABLE', 'SETTABLE', 'RETURN')
'DIV', 'ADD', 'GETTABLE', 'SUB', 'GETTABLE_SK', 'POW',
'UNM', 'SETTABLE', 'SETTABLE_I', 'RETURN')
-- direct access to constants
check(function ()
@ -223,7 +230,7 @@ check(function ()
a[true] = false
end,
'LOADNIL',
'SETTABLE', 'SETTABLE', 'SETTABLE', 'SUB', 'DIV', 'LOADK',
'SETTABLE_SK', 'SETTABLE_SK', 'SETTABLE', 'SUB', 'DIV', 'LOADK',
'SETTABLE', 'RETURN')
@ -256,7 +263,7 @@ checkequal(function () if (a==nil) then a=1 end; if a~=nil then a=1 end end,
function () if (a==9) then a=1 end; if a~=9 then a=1 end end)
check(function () if a==nil then a=1 end end,
'GETTABUP', 'EQ', 'JMP', 'SETTABUP', 'RETURN')
'GETTABUP_SK', 'EQ', 'JMP', 'SETTABUP', 'RETURN')
-- de morgan
checkequal(function () local a; if not (a or b) then b=a end end,
@ -421,7 +428,7 @@ assert(x(5.1) == 2.0)
assert(x(4.0) == 3.0)
print("test 8 OK")
-- test 10
-- test 9
x = function (y: integer, z)
if y == 1 then
if z == 1 then
@ -447,7 +454,7 @@ assert(x(5) == 2.0)
assert(x(4) == 3.0)
print("test 9 OK")
-- test 11
-- test 10
x = function()
local function tryme()
local i,j = 5,6
@ -458,14 +465,14 @@ x = function()
assert(i+j == 11)
end
compile(x)
check(x, 'CLOSURE', 'GETTABUP', 'GETUPVAL',
check(x, 'CLOSURE', 'GETTABUP_SK', 'GETUPVAL',
'MOVE', 'CALL', 'CALL', 'MOVE', 'CALL', 'TOINT', 'TOINT',
'GETTABUP', 'ADDII', 'EQ_II', 'JMP', 'LOADBOOL', 'LOADBOOL',
'GETTABUP_SK', 'ADDII', 'EQ_II', 'JMP', 'LOADBOOL', 'LOADBOOL',
'CALL', 'RETURN')
x()
print("test 10 OK")
-- test 12
-- test 11
function x()
local a : number[], j:number = {}
for i=1,10 do
@ -483,7 +490,7 @@ compile(x)
assert(x() == 55.0)
print("test 11 OK")
-- test 13
-- test 12
function pisum()
local sum : number
for j = 1,500 do
@ -504,7 +511,7 @@ assert(compile(pisum))
assert(math.abs(pisum()-1.644834071848065) < 1e-12)
print("test 12 OK")
-- test 15
-- test 13
function y()
local i,j = 5.1,"6.2"
return i,j
@ -521,7 +528,7 @@ assert(compile(x))
assert(math.abs(x(y) - 11.3) < 0.0001)
print("test 13 OK")
-- test 16
-- test 14
function tryme(x,y)
if x < y then
return 1
@ -539,7 +546,7 @@ assert(tryme(1,2) == 1)
assert(tryme(2,1) == 0)
print("test 14 OK")
-- test 17
-- test 15
function tryme(x,y)
return x < y
end
@ -551,18 +558,18 @@ assert(tryme(1,2))
assert(not tryme(2,1))
print("test 15 OK")
-- test 18
-- test 16
function tabtest(x)
x[1] = 5
return x[1]
end
assert(tabtest({}) == 5)
check(tabtest, 'SETTABLE', 'GETTABLE', 'RETURN', 'RETURN')
check(tabtest, 'SETTABLE_I', 'GETTABLE_I', 'RETURN', 'RETURN')
compile(tabtest)
assert(tabtest({}) == 5)
print("test 16 OK")
-- test 19
-- test 17
function optest()
local a,b,c = 1, 5
c = a and b
@ -575,7 +582,7 @@ compile(optest)
assert(optest() == 5)
print("test 17 OK")
-- test 20
-- test 18
function optest()
local a,b,c = 1, 5
c = a or b
@ -588,7 +595,7 @@ compile(optest)
assert(optest() == 1)
print("test 18 OK")
-- test 21
-- test 19
function optest()
local a,b = 1, 5
if a and b then
@ -603,7 +610,7 @@ compile(optest)
assert(optest() == 5)
print("test 19 OK")
-- test 22
-- test 20
function optest()
local a,b = nil, 5
if a or b then
@ -618,7 +625,7 @@ compile(optest)
assert(optest() == 5)
print("test 20 OK")
-- test 29
-- test 21
z = function()
local x=function()
local j:number[] = {}
@ -628,18 +635,18 @@ z = function()
y=x()
y[1] = 99.67
assert(y[1], 99.67)
assert(#y == 1)
assert(@integer (#y) == 1)
end
check(z, 'CLOSURE', 'GETUPVAL', 'MOVE', 'CALL',
'MOVE', 'CALL', 'SETUPVAL', 'SETTABUP', 'GETTABUP', 'GETTABUP',
'LOADK', 'CALL', 'GETTABUP', 'GETUPVAL', 'LEN', 'EQ_II',
'MOVE', 'CALL', 'SETUPVAL', 'SETTABUP', 'GETTABUP_SK', 'GETTABUP',
'LOADK', 'CALL', 'GETTABUP_SK', 'GETUPVAL', 'LEN', 'TOINT', 'EQ_II',
'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL', 'RETURN')
z()
compile(z)
z()
print("test 21 OK")
-- test 30
-- test 22
z = function()
local days: table = {"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturda"}
@ -658,19 +665,19 @@ z = function()
assert(x() == "SundayMondayTuesdayWednesdayThursdayFridaySaturday")
end
check(z, 'NEWTABLE', 'LOADK', 'LOADK', 'LOADK', 'LOADK',
'LOADK', 'LOADK', 'LOADK', 'SETLIST', 'GETTABUP', 'GETTABLE_I',
'EQ', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL', 'GETTABUP', 'LEN',
'EQ_II', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL', 'GETTABUP', 'GETTABLE_I',
'LOADK', 'LOADK', 'LOADK', 'SETLIST', 'GETTABUP_SK', 'GETTABLE_I',
'EQ', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL', 'GETTABUP_SK', 'LEN', 'TOINT',
'EQ_II', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL', 'GETTABUP_SK', 'GETTABLE_I',
'EQ', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL', 'GETTABLE_I', 'LOADK',
'CONCAT', 'SETTABLE_I', 'CLOSURE', 'SETUPVAL', 'GETTABUP', 'GETUPVAL',
'GETUPVAL', 'CALL', 'CALL', 'GETTABUP', 'GETUPVAL', 'CALL', 'EQ',
'CONCAT', 'SETTABLE_I', 'CLOSURE', 'SETUPVAL', 'GETTABUP_SK', 'GETUPVAL',
'GETUPVAL', 'CALL', 'CALL', 'GETTABUP_SK', 'GETUPVAL', 'CALL', 'EQ',
'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL', 'RETURN')
z()
compile(z)
z()
print("test 22 OK")
-- test 31
-- test 23
x = function(a)
return not a
end
@ -684,7 +691,7 @@ assert(y(x(false)))
assert(not y(x(true)))
print("test 23 OK")
-- test 36
-- test 24
t = { name_ = "ravi" }
function t:name()
return self.name_
@ -695,9 +702,9 @@ end
assert(compile(t.name))
assert(compile(z))
assert(z(t) == "ravi")
print("test 25 OK")
print("test 24 OK")
-- test 38
-- test 25
-- test ravi integer array
function f()
local x: integer[] = { 1, 5 }
@ -710,9 +717,9 @@ function f()
end
assert(compile(f))
assert(f() == 6)
print("test 26 OK")
print("test 25 OK")
-- test 39
-- test 26
function f()
local x: number[] = { 5.0, 6.1 }
x[3] = x[1] + x[2]
@ -721,9 +728,9 @@ end
--ravi.dumplua(f)
assert(compile(f))
assert(math.abs(f()-11.1) < 1e-12)
print("test 27 OK")
print("test 26 OK")
-- test 41
-- test 27
-- Ravi arrays support for ipairs()
-- Plus special slot at [0]
x = function()
@ -739,9 +746,9 @@ x = function()
end
assert(compile(x))
assert(x() == 28)
print("test 28 OK")
print("test 27 OK")
-- test 42
-- test 28
-- Ravi arrays support for pairs()
-- Plus special slot at [0]
x = function()
@ -757,9 +764,9 @@ x = function()
end
assert(compile(x))
assert(x() == 28)
print("test 29 OK")
print("test 28 OK")
-- test 43
-- test 29
-- test creation of arrays and slice
x = function()
local zeros: integer[] = table.intarray(10, 0)
@ -781,9 +788,9 @@ x = function()
end
assert(compile(x))
assert(x() == true)
print("test 30 OK")
print("test 29 OK")
-- test 44
-- test 30
matrix = {}
matrix.new = function (m, n)
local t = {m, n, table.numarray(m*n, 0)}
@ -829,9 +836,9 @@ assert(compile(matrix.getcol))
assert(compile(matrix.getdata))
assert(compile(x))
assert(x() == 65)
print("test 31 OK")
print("test 30 OK")
-- test 23
-- test 31
function testadd(a,b)
return a+b
end
@ -840,9 +847,9 @@ assert(testadd(1,1) == 2)
assert(testadd(1.5,1.6) == 3.1)
assert(testadd("1.5",1.6) == 3.1)
assert(testadd("1.5","1.6") == 3.1)
print("test 32 OK")
print("test 31 OK")
-- test 24
-- test 32
function testsub(a,b)
return a-b
end
@ -851,9 +858,9 @@ assert(testsub(1,1) == 0)
assert(math.abs(testsub(1.5,1.6)-(-0.1)) < 1e-6)
assert(math.abs(testsub("1.5",1.6)-(-0.1)) < 1e-6)
assert(math.abs(testsub("1.5","1.6")-(-0.1)) < 1e-6)
print("test 33 OK")
print("test 32 OK")
-- test 25
-- test 33
function testmul(a,b)
return a*b
end
@ -862,10 +869,10 @@ assert(testmul(2,2) == 4)
assert(math.abs(testmul(1.5,1.6)-2.4) < 1e-12)
assert(math.abs(testmul("1.5",1.6)-2.4) < 1e-12)
assert(math.abs(testmul("1.5","1.6")-2.4) < 1e-12)
print("test 34 OK")
print("test 33 OK")
-- test 26
-- test 34
function testdiv(a,b)
return a/b
end
@ -874,10 +881,10 @@ assert(testdiv(2,2) == 1.0)
assert(math.abs(testdiv(1.5,1.6)-0.9375) < 1e-12)
assert(math.abs(testdiv("1.5",1.6)-0.9375) < 1e-12)
assert(math.abs(testdiv("1.5","1.6")-0.9375) < 1e-12)
print("test 35 OK")
print("test 34 OK")
-- test 37
-- test 35
-- this tests that within the for loop
-- the locals get mapped correctly to upvalues
function f()
@ -900,11 +907,9 @@ assert(t[1]() == 10)
assert(t[2]() == 10)
assert(t[1]() == 20)
assert(t[2]() == 20)
print("test 36 OK")
print("test 35 OK")
-- test 27
-- test 36
-- upvalues
local x = 1
local y=function()
@ -919,9 +924,9 @@ local f = y()
assert(f() == 1)
x=5
assert(f() == 5)
print("test 37 OK")
print("test 36 OK")
-- test 28
-- test 37
-- upvalues
x1 = 3
local y=function()
@ -940,9 +945,9 @@ local f = y()
assert(f() == 3)
x1=5
assert(f() == 5)
print("test 38 OK")
print("test 37 OK")
-- test 35
-- test 38
function x()
local x = 1
local f = function()
@ -955,7 +960,7 @@ f=x()
assert(compile(f))
assert(f() == 2)
assert(f() == 3)
print("test 39 OK")
print("test 38 OK")
-- test setupval, getupval
function x()
@ -969,9 +974,9 @@ compile(y)
assert(y(2) == 2)
assert(y(2) == 4)
assert(y(3) == 7)
print('test 40 Ok')
print('test 39 OK')
-- test 32
-- test 40
x=function(a,b)
return a%b
end
@ -980,9 +985,9 @@ assert(compile(x))
-- if ravi.jit() then ravi.compile(x) end
assert(x(5,2) == 1)
assert(math.abs(x(5.1,2.1)-0.9) < 1e-6)
print("test 41 OK")
print("test 40 OK")
-- test 33
-- test 41
x=function(a,b)
return a//b
end
@ -991,9 +996,9 @@ assert(compile(x))
-- if ravi.jit() then ravi.compile(x) end
assert(x(5,2) == 2)
assert(math.abs(x(5.5,2.1)-2.0) < 1e-6)
print("test 42 OK")
print("test 41 OK")
-- test 6
-- test 42
x = function ()
local j = 0
for i=2.0,6.0,3.1 do
@ -1003,10 +1008,10 @@ x = function ()
end
if (not compile(x)) then
print("test 6 FAILED to compile")
print("test FAILED to compile")
end
assert(x() == 5.1)
print("test 43 OK")
print("test 42 OK")
-- test parameter types
x = function (a: integer, b: number)
@ -1018,7 +1023,7 @@ end
assert(x(1,5.5) == 6.5)
compile(x)
assert(x(1,5.5) == 6.5)
print'test 44 OK'
print'test 43 OK'
x=function (a:number[], b:integer)
local j: number = a[b]
@ -1033,9 +1038,9 @@ assert(y() == 4.2)
compile(x)
compile(y)
assert(y() == 4.2)
print'test 45 OK'
print'test 44 OK'
-- test 40
-- test 45
function x(t) return t; end
function f()
local tt: integer[] = {1}
@ -1051,23 +1056,19 @@ function f()
tt = x({})
end
--ravi.dumplua(f)
print'+'
assert(compile(f))
assert(not pcall(f))
print'+'
function f()
local tt: integer[] = {1}
local ss: number[] = { 55.5 }
ss = x(tt)
end
print'+'
assert(compile(f))
assert(not pcall(f))
print("test 46 OK")
print("test 45 OK")
-- test 41
-- test 47
function test_idiv()
local t = {}
t.__idiv = function(...) return 'idiv' end
@ -1105,8 +1106,8 @@ function test_tableaccess()
return t.name, t.data.city
end
check(f, 'NEWTABLE', 'SETTABLE_S', 'NEWTABLE',
'SETTABLE_S', 'GETTABLE_S', 'SETTABLE',
'GETTABLE_S', 'GETTABLE_S' , 'GETTABLE',
'SETTABLE_S', 'GETTABLE_S', 'SETTABLE_SK',
'GETTABLE_S', 'GETTABLE_S' , 'GETTABLE_SK',
'RETURN', 'RETURN')
local a,b = f()
assert(a == 'dibyendu')
@ -1127,8 +1128,8 @@ function test_tableaccess()
return t[1], t[2][1]
end
check(f, 'NEWTABLE', 'SETTABLE_I', 'NEWTABLE',
'SETTABLE_I', 'GETTABLE_I', 'SETTABLE',
'GETTABLE_I', 'GETTABLE_I' , 'GETTABLE',
'SETTABLE_I', 'GETTABLE_I', 'SETTABLE_I',
'GETTABLE_I', 'GETTABLE_I' , 'GETTABLE_I',
'RETURN', 'RETURN')
local a,b = f()
assert(a == 'dibyendu')
@ -1145,18 +1146,18 @@ function test_self_s()
local t : table = {}
t.name_ = 'dibyendu majumdar'
t.name = function (t:table) return t.name_ end
print(t:name())
assert(t:name())
return t:name()
end
check(test_self_s, 'NEWTABLE', 'SETTABLE_S', 'CLOSURE',
'SETTABLE_S', 'GETTABUP', 'SELF_S', 'CALL', 'CALL', 'SELF_S', 'TAILCALL',
'SETTABLE_S', 'GETTABUP_SK', 'SELF_S', 'CALL', 'CALL', 'SELF_S', 'TAILCALL',
'RETURN')
assert(test_self_s() == 'dibyendu majumdar')
compile(test_self_s)
assert(test_self_s() == 'dibyendu majumdar')
print 'Test 49 OK'
-- issue #73
-- issue #73
function bug_index_event()
local t1 = { name='dibyendu' }
local t2 = { surname='majumdar' }
@ -1250,21 +1251,21 @@ function test_longkey()
assert(t[s] == 4.4)
assert(t.s == nil)
end
check(test_longkey, 'NEWTABLE', 'SETTABLE', 'GETTABUP', 'GETTABLE',
'EQ', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL', 'SETTABLE_S', 'GETTABUP',
check(test_longkey, 'NEWTABLE', 'SETTABLE', 'GETTABUP_SK', 'GETTABLE',
'EQ', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL', 'SETTABLE_S', 'GETTABUP_SK',
'GETTABLE_S', 'EQ', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL', 'SETTABLE_S',
'GETTABUP', 'GETTABLE_S', 'EQ', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL',
'LOADK', 'GETTABUP', 'GETTABLE', 'EQ', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL',
'GETTABUP', 'GETTABLE_S', 'EQ', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL',
'GETTABUP_SK', 'GETTABLE_S', 'EQ', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL',
'LOADK', 'GETTABUP_SK', 'GETTABLE', 'EQ', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL',
'GETTABUP_SK', 'GETTABLE_S', 'EQ', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL',
'RETURN')
assert(pcall(test_longkey));
compile(test_longkey);
assert(pcall(test_longkey));
print 'Test 53 OK'
print 'Test 54 OK'
function test_yields_in_metamethods()
print"testing yields inside metamethods"
--print"testing yields inside metamethods"
local mt = {
__eq = function(a:table,b:table) coroutine.yield(nil, "eq"); return a.x == b.x end,
__lt = function(a:table,b:table) coroutine.yield(nil, "lt"); return a.x < b.x end,
@ -1392,7 +1393,7 @@ end
assert(pcall(test_yields_in_metamethods));
compile(test_longkey);
assert(pcall(test_yields_in_metamethods));
print 'Test 54 Ok'
print 'Test 55 OK'
function test_upvaluejoin()
local debug = require'debug'
@ -1441,13 +1442,157 @@ end
assert(pcall(test_upvaluejoin));
compile(test_upvaluejoin);
assert(pcall(test_upvaluejoin));
print 'Test 55 Ok'
print 'Test 56 OK'
function test_idiv(y: integer)
local era: integer
era = y // 400
return era
end
check(test_idiv, 'TOINT', 'LOADNIL', 'LOADIZ', 'IDIV', 'RETURN', 'RETURN')
assert(test_idiv(1900) == 4)
compile(test_idiv)
assert(test_idiv(1900) == 4)
print 'Test 57 OK'
function from_dmy1(y: integer, m: integer, d: integer)
if m <= 2 then
y = y - 1
end
local era: integer
if y >= 0 then
era = y // 400
else
era = (y-399) // 400
end
local yoe: integer = y - era * 400
local tmp: integer
if m > 2 then
tmp = -3
else
tmp = 9
end
local doy: integer = (153 * (m + tmp) + 2)//5 + d-1
local doe: integer = yoe * 365 + yoe//4 - yoe//100 + doy
return era * 146097 + doe - 719468
end
function from_dmy2(y, m, d)
if m <= 2 then
y = y - 1
end
local era
if y >= 0 then
era = y // 400
else
era = (y-399) // 400
end
local yoe = y - era * 400
local tmp
if m > 2 then
tmp = -3
else
tmp = 9
end
local doy = (153 * (m + tmp) + 2)//5 + d-1
local doe = yoe * 365 + yoe//4 - yoe//100 + doy
return era * 146097 + doe - 719468
end
assert(from_dmy1(1900, 1, 1) == -25567)
assert(from_dmy1(1900, 1, 1) == from_dmy2(1900, 1, 1))
compile(from_dmy1)
compile(from_dmy2)
assert(from_dmy1(1900, 1, 1) == -25567)
assert(from_dmy1(1900, 1, 1) == from_dmy2(1900, 1, 1))
check(from_dmy1, 'TOINT', 'TOINT', 'TOINT', 'LE_II', 'JMP',
'SUBII','LOADNIL','LOADIZ','LE_II','JMP','IDIV','JMP','SUBII',
'IDIV','MULII','SUBII','LOADNIL','LOADIZ','LT_II','JMP','LOADK',
'JMP','LOADK','ADDII','MULII','ADDII','IDIV','ADDII','SUBII',
'MULII','IDIV','ADDII','IDIV','SUBII','ADDII','MULII','ADDII',
'SUBII','RETURN','RETURN')
print 'Test 58 OK'
function x(s1: string, s2: string)
return @string( s1 .. s2 )
end
check(x, 'TOSTRING', 'TOSTRING', 'MOVE', 'MOVE', 'CONCAT', 'TOSTRING', 'RETURN', 'RETURN')
assert(x('a', 'b') == 'ab')
compile(x)
assert(x('a', 'b') == 'ab')
print 'Test 59 OK'
function x(f: closure)
local g = @closure f
return g()
end
check(x, 'TOCLOSURE', 'MOVE', 'MOVE', 'TAILCALL', 'RETURN', 'RETURN')
local called = 0
function y()
called = called + 1
end
x(y)
assert(called == 1)
compile(x)
compile(y)
x(y)
assert(called == 2)
print 'Test 60 OK'
local mt = { __name='MyType'}
debug.getregistry().MyType = mt
local t = {}
setmetatable(t, mt)
function x(s: MyType)
local assert = assert
assert(@MyType s == @MyType t)
assert(@MyType t == t)
end
x(t)
compile(x)
x(t)
print 'Test 61 OK'
function x()
local a: MyType
return function (b) a = b end
end
f = x()
assert(pcall(f, t)) -- t is of MyType so okay
assert(pcall(f, nil)) -- nil is okay
assert(not pcall(f, 'hello')) -- string not okay
ravi.compile(f)
assert(pcall(f, t))
assert(pcall(f, nil))
assert(not pcall(f, 'hello'))
print 'Test 62 OK'
function x()
local f: closure = function() end
f = nil
local f
f = 'a'
return f
end
assert(x() == 'a')
ravi.compile(x)
assert(x() == 'a')
print 'Test 63 OK'
-- Codegen bug #issue 148
function x()
assert(({pcall(function() comp 'x for __result' end)})[2]
:find'not contain __ prefix')
end
check(x, 'GETTABUP_SK', 'NEWTABLE', 'GETTABUP_SK', 'CLOSURE',
'CALL', 'SETLIST', 'GETTABLE_I', 'SELF_SK', 'LOADK',
'CALL', 'CALL', 'RETURN')
print 'Test 64 OK'
for k,v in pairs(opcodes_coverage)
do
print(k, v)
end
--ravi.dumplua(test_yields_in_metamethods)
-- ravi.dumplua(test_yields_in_metamethods)
print 'OK'

@ -13,8 +13,10 @@ opcodes_coverage.LOADBOOL = 0
opcodes_coverage.LOADNIL = 0
opcodes_coverage.GETUPVAL = 0
opcodes_coverage.GETTABUP = 0
opcodes_coverage.GETTABUP_SK = 0
opcodes_coverage.GETTABLE = 0
opcodes_coverage.SETTABUP = 0
opcodes_coverage.SETTABUP_SK = 0
opcodes_coverage.SETUPVAL = 0
opcodes_coverage.SETTABLE = 0
opcodes_coverage.NEWTABLE = 0
@ -111,10 +113,15 @@ opcodes_coverage.GETTABLE_I = 0
opcodes_coverage.GETTABLE_S = 0
opcodes_coverage.SETTABLE_I = 0
opcodes_coverage.SETTABLE_S = 0
opcodes_coverage.SETTABLE_SK = 0
opcodes_coverage.GETTABLE_SK = 0
opcodes_coverage.TOTAB = 0
opcodes_coverage.MOVETAB = 0
opcodes_coverage.SETUPVALT = 0
opcodes_coverage.SELF_S = 0
opcodes_coverage.TOTYPE = 0
opcodes_coverage.TOSTRING = 0
opcodes_coverage.TOCLOSURE = 0
local compile = function(f)
@ -164,13 +171,13 @@ x = function()
assert(i == 2)
assert(n == 4.2)
end
check(x, {'LOADK', 'LOADK', 'GETTABUP', 'EQ_II',
check(x, {'LOADK', 'LOADK', 'GETTABUP_SK', 'EQ_II',
'JMP', 'EQ_FF', 'JMP', 'LOADBOOL', 'LOADBOOL',
'CALL', 'NEWTABLE', 'LOADK', 'LOADK', 'LOADK',
'LOADK', 'LOADK', 'SETLIST', 'GETTABLE', 'TOINT',
'MOVEI', 'GETTABLE', 'TOFLT', 'MOVEF', 'GETTABUP',
'LOADK', 'LOADK', 'SETLIST', 'GETTABLE_I', 'TOINT',
'MOVEI', 'GETTABLE_I', 'TOFLT', 'MOVEF', 'GETTABUP_SK',
'EQ_II', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL',
'GETTABUP', 'EQ_FF', 'JMP', 'LOADBOOL', 'LOADBOOL',
'GETTABUP_SK', 'EQ_FF', 'JMP', 'LOADBOOL', 'LOADBOOL',
'CALL', 'RETURN'})
x()
compile(x)
@ -182,7 +189,7 @@ function x()
assert(c == a and b == d)
end
check(x, {'LOADK', 'LOADK', 'TOINT', 'MOVE',
'TOINT', 'MOVE', 'GETTABUP', 'EQ', 'JMP',
'TOINT', 'MOVE', 'GETTABUP_SK', 'EQ', 'JMP',
'EQ', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL',
'RETURN'})
x()
@ -205,9 +212,9 @@ assert(y == 61 and math.abs(z - 19.9) < 1e-5)
compile(x)
y,z = x()
assert(y == 61 and math.abs(z - 19.9) < 1e-10)
check(x, {'LOADK', 'LOADK', 'LOADK', 'GETTABUP',
'GETTABLE', 'TOINT', 'GETTABUP', 'TOINT', 'TOINT',
'MULII', 'ADDII', 'LOADK', 'GETTABUP', 'GETTABLE',
check(x, {'LOADK', 'LOADK', 'LOADK', 'GETTABUP_SK',
'GETTABLE_I', 'TOINT', 'GETTABUP', 'TOINT', 'TOINT',
'MULII', 'ADDII', 'LOADK', 'GETTABUP_SK', 'GETTABLE_I',
'TOFLT', 'GETTABUP', 'TOFLT', 'MULFF', 'TOFLT',
'SUBFF', 'MOVE', 'MOVE', 'RETURN', 'RETURN'})

@ -0,0 +1,106 @@
-- These tests are for new backend
local compile = function(f)
if ravi.jit() then
assert(ravi.compile(f))
end
return true
end
local x = function() end
compile(x)
x = function() return 42 end
compile(x)
assert(x() == 42)
x = function() return 4.256 end
compile(x)
assert(x() == 4.256)
x = function() return 'hello' end
compile(x)
assert(x() == 'hello')
x = function()
local j
for i=1,10 do
for k = 0,5,5 do
j = k
end
end
return j
end
compile(x)
assert(x() == 5)
x = function()
local a,b = false, true
return a
end
compile(x)
assert(not x())
x = function()
local a
if 2 < 5 then
a = true
else
a = false
end
end
compile(x)
assert(not x())
local y
y = function()
return x()
end
compile(y)
assert(not y())
x = function()
print 'Good if this prints'
end
compile(x)
x()
x = function()
if 8 > 9 then
return 8
elseif 5 >= 4 then
return 5
else
return 9
end
end
compile(x)
assert(x() == 5)
x = function()
local j = -99
for i = 10,1,-1 do
j = i
end
return j
end
ravi.compile(x)
assert(x() == 1)
x = function()
local j = -9.9
for i = 10.5,1.5,-1.0 do
j = i
end
return j
end
ravi.compile(x)
assert(x() == 1.5)
print'Ok'

@ -12,6 +12,7 @@ Contents:
:maxdepth: 2
ravi-overview
lua-introduction.rst
lua_bytecode_reference.rst
lua-parser
ravi-internals
@ -24,7 +25,6 @@ Contents:
llvm-bindings
ravi-benchmarks
ravi-jit-status
ravi-jit-libgccjit
Indices and tables

@ -0,0 +1,489 @@
===================
Introduction to Lua
===================
Introduction
============
`Lua <https://www.lua.org>`_ is a small but powerful interpreted language that is implemented as a C library. This guide is meant to help you quickly become familiar with the main features of Lua. This guide assumes you know C, C++, or Java, and perhaps a scripting language like Python - it is not a beginner's guide. Nor is it a tutorial for Lua.
Key Features of Lua
===================
* Lua versions matter
* Lua is dynamically typed like Python
* By default variables in Lua are global unless declared local
* There is a single complex / aggregate type called a 'table', which combines hash table/map and array features
* Functions in Lua are values stored in variables; in particular functions do not have names
* Globals in Lua are just values stored in a special Lua table
* Functions in Lua are closures - they can capture variables from outer scope and such variables live on even though the surrounding scope is no longer alive
* Lua functions can return multiple values
* Lua has integer (since 5.3) and floating point types that map to native C types
* A special ``nil`` value represents non-existent value
* Any value that is not ``false`` or ``nil`` is true
* The result of logical ``and`` and logical ``or`` is not true or false; these operators select one of the values
* ``'~='`` is not equals operator and ``'..'`` is string concatenation operator
* Lua has some nice syntactic sugar for tables and functions
* A Lua script is called a chunk - and is the unit of compilation in Lua
* The Lua stack is a heap allocated structure - and you can think of Lua as a library that manipulates this stack
* Lua functions can be yielded from and resumed later on, i.e., Lua supports coroutines
* Lua is single threaded but its VM is small and encapsulated in a single data structure - hence each OS thread can be given its own
Lua VM
* Lua's error handling is based on C setjmp/longjmp, and errors are caught via a special function call mechanism
* Lua has a meta mechanism that enables a DIY class / object system with some syntactic sugar to make it look nice
* Lua supports operator overloading via 'meta' methods
* You can create user defined types in C and make them available in Lua
* Lua compiles code to bytecode before execution
* Lua bytecode is not officially documented and changes from one Lua version to another; moreover the binary dump of the bytecodes is
not portable across architectures and also can change between versions
* Lua's compiler is designed to be fast and frugal - it generates code as it parses, there is no intermediate AST construction
* Like C, Lua comes with a very small standard library - in fact Lua's standard library is just a wrapper for C standard library
plus some basic utilities for Lua
* Lua's standard library includes pattern matching for strings in which the patterns themselves are strings, rather like regular expressions in Python or Perl, but simpler.
* Lua provides a debug API that can be used to manipulate Lua's internals to a degree - and can be used to implement a debugger
* Lua has an incremental garbage collector
* Lua is Open Source but has a closed development model - external contributions are not possible
* LuaJIT is a JIT compiler for Lua but features an optional high performance C interface mechanism that makes it incompatible with Lua
In the rest of this document I will expand on each of these aspects of Lua.
Lua versions matter
===================
For all practical purposes only Lua versions 5.1, 5.2 and 5.3 matter. Note however that each of these is considered a major version and therefore is not fully backward compatible (e.g. Lua 5.3 cannot necessarily run Lua 5.1 code) although there is a large common subset.
* Lua 5.2 has a new mechanism for resolving undeclared variables compared to 5.1
* Lua 5.3 has integer number subtype and bitwise operators that did not exist in 5.1 or 5.2
* LuaJIT is 5.1 based but supports a large subset of 5.2 features with some notable exceptions such as the change mentioned above
Mostly what this document covers should be applicable to all these versions, except as otherwise noted.
Lua is dynamically typed
========================
This means that values have types but variables do not. Example::
x = 1 -- x holds an integer
x = 5.0 -- x now holds a floating pont value
x = {} -- x now holds an empty table
x = function() end -- x now holds a function with empty body
Variables are global unless declared local
==========================================
In the example above, ``x`` is global.
But saying::
local x = 1
makes ``x`` local, i.e. its scope and visibility is constrained to the enclosing block of code, and any nested blocks. Note that
local variables avoid a lookup in the 'global' table and hence are more efficient. Thus it is common practice to cache values in
local variables. For example, ``print`` is a global function - and following creates a local variable that caches it::
local print = print -- caches global print() function
print('hello world!') -- calls the same function as global print()
There are some exceptions to the rule:
* the iterator variables declared in a ``for`` loop are implicitly local.
* function parameters are local to the function
The 'table' type
================
Lua's only complex / aggregate data type is a table. Tables are used for many things in Lua, even internally within Lua.
Here are some examples::
local a = {} -- creates an empty table
local b = {10,20,30} -- creates a table with three array elements at positions 1,2,3
-- this is short cut for:
-- local b = {}
-- b[1] = 10
-- b[2] = 20
-- b[3] = 30
local c = { name='Ravi' } -- creates a table with one hash map entry
-- this is short cut for:
-- local c = {}
-- c['name'] = 'Ravi'
Internally the table is a composite hash table / array structure. Consecutive values starting at integer index 1 are inserted into the array, else the values go into the hash table. Hence, in the example below::
local t = {}
t[1] = 20 -- goes into array
t[2] = 10 -- goes into array
t[100] = 1 -- goes into hash table as not consecutive
t.name = 'Ravi' -- goes into hash table
-- t.name is syntactic sugar for t['name']
To iterate over array values you can write::
for i = 1,#t do
print(t[i])
end
Note that above will only print 20,10.
To iterate over all values write::
for k,v in pairs(t) do
print(k,v)
end
Unfortunately, you need to get a good understanding of when values will go into the array part of a table, because some Lua library functions work only on the array part. Example::
table.sort(t)
You will see that only values at indices 1 and 2 were sorted.
Another frequent problem is that the only way to reliably know the total number of elements in a table is to count the values.
The ``#`` operator returns the length of the consecutive array elements starting at index 1.
Functions are values stored in variables
========================================
You already saw that we can write::
local x = function()
end
This creates a function and stores it in local variable ``x``. This is the same as::
local function x()
end
Omitting the ``local`` keyword would create ``x`` in global scope.
Functions can be defined within functions - in fact all Lua functions are defined within a 'chunk' of code, which gets wrapped inside a Lua function.
Internally a function has a 'prototype' that holds the compiled code and other meta data regarding the function. An instance of the
function in created when the code executes. You can think of the 'prototype' as the 'class' of the function, and the function instance is akin to an object created from this class.
Globals are just values in a special table
==========================================
Globals are handled in an interesting way. Whenever a name is used that is not found in any of the enclosing scopes and is not declared ``local``, then Lua will access/create a variable in a table accessed by the name ``_ENV`` (this applies to Lua 5.2 and above - Lua 5.1 had a different mechanism). Actually ``_ENV`` is just a captured value that points to a special table in Lua by default. This table access becomes evident when you look at the bytecode generated for some Lua code::
function hello()
print('hello world')
end
Generates following (in Lua 5.3)::
function <stdin:1,3> (4 instructions at 00000151C0AA9530)
0 params, 2 slots, 1 upvalue, 0 locals, 2 constants, 0 functions
1 [2] GETTABUP 0 0 -1 ; _ENV "print"
2 [2] LOADK 1 -2 ; "hello world"
3 [2] CALL 0 2 1
4 [3] RETURN 0 1
constants (2) for 00000151C0AA9530:
1 "print"
2 "hello world"
locals (0) for 00000151C0AA9530:
upvalues (1) for 00000151C0AA9530:
0 _ENV 0 0
The ``GETTABUP`` instruction looks up the name 'print' in the captured table variable ``_ENV``. Lua uses the term 'upvalue' for captured variables.
Functions in Lua are closures
=============================
Lua functions can reference variables in outer scopes - and such references can be captured by the function so that even if the outer scope does not exist anymore the variable still lives on::
-- x() returns two anonymous functions
x = function()
local a = 1
return function(b)
a = a+b
return a
end,
function(b)
a = a+b
return a
end
end
-- call x
m,n = x()
m(1) -- returns 2
n(1) -- returns 3
In the example above, the local variable ``a`` in function ``x()`` is captured inside the two anonymous functions that reference it. You can see this if you dump Lua 5.3 bytecode for ``m``::
function <stdin:1,1> (6 instructions at 00000151C0AD3AB0)
1 param, 2 slots, 1 upvalue, 1 local, 0 constants, 0 functions
1 [1] GETUPVAL 1 0 ; a
2 [1] ADD 1 1 0
3 [1] SETUPVAL 1 0 ; a
4 [1] GETUPVAL 1 0 ; a
5 [1] RETURN 1 2
6 [1] RETURN 0 1
constants (0) for 00000151C0AD3AB0:
locals (1) for 00000151C0AD3AB0:
0 b 1 7
upvalues (1) for 00000151C0AD3AB0:
0 a 1 0
The ``GETUPVAL`` and ``SETUPVAL`` instructions access captured variables or upvalues as they are known in Lua.
Lua functions can return multiple values
========================================
An example of this already appeared above. Here is another::
function foo()
return 1, 'text'
end
x,y = foo()
Lua has integer and floating point numeric types
================================================
Since Lua 5.3 Lua's number type has integer and floating point representations. This is automatically managed; however a library function is provided to tell you what Lua thinks the number type is.
::
x = 1 -- integer
y = 4.2 -- double
print(math.type(x)) -- says 'integer'
print(math.type(y)) -- says 'float'
On 64-bit architecture by default an integer is represented as C ``int64_t`` and floating point as ``double``. The representation of the numeric type as native C types is one of the secrets of Lua's performance, as the numeric types do not require 'boxing'.
In Lua 5.3, there is a special division operator ``//`` that does integer division if the operands are both integer. Example::
x = 4
y = 3
print(x//y) -- integer division results in 0
print(x/y) -- floating division results in 1.3333333333333
Note that officially the ``//`` operator does floor division, hence if one or both of its operands is floating point then the result is also a floating point representing the floor of the division of its operands.
Having integer types has also made it natural to have support for bitwise operators in Lua 5.3.
A special ``nil`` value represents non-existent value
=====================================================
Lua has special value ``nil`` that represents no value, and evaluates to false in boolean expressions.
Any value that is not ``false`` or ``nil`` is true
==================================================
As mentioned above ``nil`` evaluates to false.
Logical ``and`` and logical ``or`` select one of the values
===========================================================
When you perform a logical ``and`` or ``or`` the result is not boolean; these operators select one of the values. This is best
illustrated via examples::
false or 'hello' -- selects 'hello'
'hello' and 'world' -- selects 'world'
false and 'hello' -- selects false
nil or false -- selects false
nil and false -- selects nil
* ``and`` selects the first value if it evaluates to false else the second value.
* ``or`` selects the first value if it evaluates to true else the second value.
``'~='`` is not equals operator and ``'..'`` is string concatenation operator
=============================================================================
For example::
print(1 ~= 2) -- prints 'true'
print('hello ' .. 'world!') -- prints 'hello world!')
Lua has some nice syntactic sugar for tables and functions
==========================================================
If you are calling a Lua function with a single string or table argument then the parenthesis can be omitted::
print 'hello world' -- syntactic sugar for print('hello world')
options { verbose=true, debug=true } -- syntactic sugar for options( { ... } )
Above is often used to create a DSL. For instance, see:
* `Lua's bug list <https://github.com/lua/lua/blob/master/bugs>`_
* `Premake <https://github.com/premake/premake-core/wiki/Your-First-Script>`_ - a tool similar to CMake
You have already seen that::
t = { surname = 'majumdar' } -- t.surname is sugar for t['surname']
t.name = 'dibyendu' -- syntactic sugar for t['name'] = 'dibyendu'
A useful use case for tables is as modules. Thus a standard library module like ``math`` is simply a table of functions. Here is an example::
module = { print, type }
module.print('hello')
module.print 'hello'
module.type('hello')
Finally, you can emulate an object oriented syntax using the ``:`` operator::
x:foo('hello') -- syntactic sugar for foo(x, 'hello')
As we shall see, this feature enables Lua to support object orientation.
A Lua script is called a chunk - and is the unit of compilation in Lua
======================================================================
When you present a script to Lua, it is compiled. The script can be a file or a string. Internally the content of the script is wrapped inside a Lua function. So that means that a script can have ``local`` variables, as these live in the wrapping function.
It is common practice for scripts to return a table of functions - as then the script can be treated as a module. There is a library function 'require' which loads a script as a module.
Suppose you have following script saved in a file ``sample.lua``::
-- sample script
local function foo() end
local function bar() end
return { foo=foo, bar=bar } -- i.e. ['foo'] = foo, ['bar'] = bar
Above script returns a table containing two functions.
Now another script can load this as follows::
local sample = require 'sample' -- Will call sample.lua script and save its table of functions
The library function ``require()`` does more than what is described above, of course. For instance it ensures that the module is only loaded once, and it uses various search paths to locate the script. It can even load C modules. Anyway, now the table returned from
the sample script is stored in the local variable 'sample' and we can write::
sample.foo()
sample.bar()
The Lua stack is a heap allocated structure
===========================================
Lua's code operates on heap allocated stacks, rather than the native machine stack. Since Lua is also a C library you can think of Lua as a library that manipulates the heap allocated stacks. In particular, Lua's C api exposes the Lua stack, and requires you to push/pop values on the stack; this approach is unique to Lua.
Lua functions can be yielded from and resumed later
===================================================
Lua allows functions to be suspended and resumed. The function suspends itself by calling a library function to yield. Sometime later
the function may be resumed by the caller or something else - when resumed, the Lua function continues from the point of suspension.
When yielding you can pass values back to the caller. Similarly when resuming the caller can pass values to the function.
This is perhaps the most advanced feature in Lua, and not one that can be easily demonstrated in a simple way. Following is the simplest example I could think of.
::
function test()
local message = coroutine.yield('hello')
print(message)
end
-- create a new Lua stack (thread)
thread = coroutine.create(test)
-- start the coroutine
status,message = coroutine.resume(thread) -- initial start
-- coroutine suspended so we have got control back
-- the coroutine yielded message to us - lets print it
print(message) -- says 'hello', the value returned by yield
-- Resume the coroutine / send it the message 'world'
status,message = coroutine.resume(thread, 'world')
-- above will print 'world'
-- status above will be true
-- but now the coroutine has ended so further calls to resume will return status as false
By the fact that 'hello' is printed before 'world' we can tell that the coroutine was suspended and then resumed.
In the Lua documentation, the return value from ``coroutine.create()`` is called a ``thread``. However don't confuse this with threads as in C++ or Java. You can think of a Lua ``thread`` as just another Lua stack. Basically whenever Lua executes any code - the code operates on a Lua stack. Initially there is only one stack (main thread). When you create a coroutine, a new stack is allocated, and the all functions called from the coroutine will operate on this new stack. Since the Lua stack is a heap allocated structure - suspending the coroutine is equivalent to returning back to the caller using a ``longjmp()``. The stack is preserved, so that the function that yielded can be resumed later from wherever it suspended itself.
There is no automatic scheduling of Lua coroutines, a coroutine has to be explicitly resumed by the program.
Note also that Lua is single threaded - so you cannot execute the different Lua stacks in parallel in multiple OS threads; a particular Lua instance always runs in a single OS thread. At any point in time only one Lua stack can be active.
Lua's error handling is based on C setjmp/longjmp
=================================================
You raise an error in Lua by calling library functions ``error()`` or ``assert()``. Lua library functions can also raise errors. When an error is raised Lua does a C ``longjmp`` to the nearest location in the call stack where the caller used a 'protected call'. A 'protected call' is a function calling mechanism that does a C ``setjmp``.
Here is how a protected call is done::
function foo(message)
-- raise error if message is nil
if not message then
error('message expected')
else
print(message)
return 4.2
end
end
-- call foo('hello') in protected mode
-- this is done using the Lua library function pcall()
status,returnvalue = pcall(foo, 'hello')
-- since this call should succeed, status will be true
-- returnvalue should contain 4.2
assert(returnvalue == 4.2)
-- call foo() without arguments in protected mode
status, returnvalue = pcall(foo)
-- above will fail and status will be false
-- But returnvalue will now have the error message
assert(not status)
print(returnvalue)
-- above prints 'message expected'
The Lua error handling mechanism has following issues:
* The code that can raise errors must be encapsulated in a function as ``pcall()`` can only call functions
* The return values from ``pcall()`` depend upon whether the call terminated normally or due to an error - so caller needs to check the status of the call and only then proceed
* On raising an error the ``longjmp`` unwinds the stack - there is no mechanism for any intermediate objects to perform cleanup as is possible in C++ using destructors, or in Java, C++, Python using ``finally`` blocks, or as done by the ``defer`` statement in Go
* You can setup a finalizer on Lua user types that will eventually execute when the value is garbage collected - this is typically used to free up memory used by the value - but you have no control over when the finalizer will run, hence relying upon finalizers for cleanup is problematic
Lua is single threaded but each OS thread can be given its own Lua VM
=====================================================================
All of Lua's VM is encapsulated in a single data structure - the Lua State. Lua does not have global state. Thus, you can create as many Lua instances in a single process as you want. Since the VM is so small it is quite feasible to allocate a Lua VM per OS thread.
Lua has a meta mechanism that enables a DIY class / object system
=================================================================
Firstly simple object oriented method calls can be emulated in Lua by relying upon the ``:`` operator described earlier. Recollect that::
object:method(arg) -- is syntactic sugar for method(object, arg)
The next bit of syntactic sugar is shown below::
object = {}
function object:method(arg)
print('method called with ', self, arg) -- self is automatic parameter and is really object
end
Above is syntactic sugar for following equivalent code::
object = {}
object.method = function(self, arg)
print('method called with ', self, arg)
end
As the object is passed as the ``self`` argument, the method can access other properties and methods contained in the object, which is just a normal table.
::
object:method('hello') -- calls method(object, 'hello')
This mechanism is fine for Lua code but doesn't work for user defined values created in C. Lua supports another more sophisticated approach that makes use of a facility in Lua called metatables. A ``metatable`` is simply an ordinary table that you can associate with any table or user defined type created in C code. The advantage of using the ``metatable`` approach is that it also works for user defined types created in C code. Here we will look at how it can be applied to Lua code.
Keeping to the same example above, this approach requires us to populate a ``metatable`` with the methods. We can think of the ``metatable`` as the class of the object.::
Class = {} -- our metatable
Class.__index = Class -- This is a meta property (see description below)
-- define method function in Class
function Class:method(arg)
print('method called with ', self, arg)
end
-- define factory for creating new objects
function Class:new()
local object = {}
setmetatable(object, self)
return object
end
* Notice that we set the field ``__index`` in the ``Class`` table to point to itself. This is a special field that Lua recognizes and whenever you access a field in an object, if the field is not found in the object and if the object has a ``metatable`` with ``__index`` field set, the Lua will lookup the field you want in the ``metatable``.
* Secondly we set ``Class`` to be the ``metatable`` for the object in the new method.
As a result of above, in the example below::
object = Class:new()
object:method('hello')
Lua notices that there is no ``method`` field in object. But object has a ``metatable`` assigned to it, and this has ``__index`` set, so Lua looks up ``Class.__index['method']`` and finds the method.
Essentially this approach enables the concept of a shared class (e.g. Class in this example) that holds common fields. These fields can be methods or other ordinary values - and since the ``metatable`` is shared by all objects created using the ``Class:new()`` method, then we have a simple OO system!
This feature can be extended to support inheritance as well, but personally I do not find this useful, and suggest you look up Lua documentation if you want to play with inheritance. My advice is to avoid implementing complex object systems in Lua. However, the ``metatable`` approach is invaluable for user defined types created in C as these types can be used in more typesafe manner by using OO notation.

@ -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,9 +24,14 @@ 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
* 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
===========
* `Experimental Type Annotations`_ for user defined types was implemented in Oct 2017.
* A new `X86-64 VM written in assembler <https://github.com/dibyendumajumdar/ravi/tree/master/vmbuilder>`_ using `dynasm <https://luajit.org/dynasm.html>`_ tool is under development currently.
Documentation
=============
See `Ravi Documentation <http://the-ravi-programming-language.readthedocs.org/en/latest/index.html>`_.
@ -34,14 +39,17 @@ As more stuff is built I will keep updating the documentation so please revisit
Also see the slides I presented at the `Lua 2015 Workshop <http://www.lua.org/wshop15.html>`_.
Lua Goodies
===========
* `An Introduction to Lua <http://the-ravi-programming-language.readthedocs.io/en/latest/lua-introduction.html>`_ attempts to provide a quick overview of Lua for folks coming from other languages.
* `Lua 5.3 Bytecode Reference <http://the-ravi-programming-language.readthedocs.io/en/latest/lua_bytecode_reference.html>`_ is my attempt to bring up to date the `Lua 5.1 Bytecode Reference <http://luaforge.net/docman/83/98/ANoFrillsIntroToLua51VMInstructions.pdf>`_.
JIT Implementation
==================
The LLVM JIT compiler is functional. The Lua and Ravi bytecodes currently implemented in LLVM are described in `JIT Status <http://the-ravi-programming-language.readthedocs.org/en/latest/ravi-jit-status.html>`_ page.
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
==========================
@ -60,6 +68,8 @@ Ravi allows you to annotate ``local`` variables and function parameters with sta
``table``
a Lua table
Additionally there are some `Experimental Type Annotations`_.
Declaring the types of ``local`` variables and function parameters has following advantages.
* ``integer`` and ``number`` types are automatically initialized to zero
@ -183,6 +193,61 @@ The type assertion operator is a unary operator and binds to the expression foll
For a real example of how type assertions can be used, please have a look at the test program `gaussian2.lua <https://github.com/dibyendumajumdar/ravi/blob/master/ravi-tests/gaussian2.lua>`_
Experimental Type Annotations
-----------------------------
Following type annotations have experimental support. These type annotations are not always statically enforced. Furthermore using these types does not affect the JIT code generation, i.e. variables annotated using these types are still treated as dynamic types.
The scenarios where these type annotations have an impact are:
* Function parameters containing these annotations lead to type assertions at runtime.
* The type assertion operator @ can be applied to these types - leading to runtime assertions.
* Annotating ``local`` declarations results in type assertions.
``string``
denotes a string
``closure``
denotes a function
Name
Denotes a value that has a `metatable registered under Name <https://www.lua.org/pil/28.2.html>`_ in the Lua registry. The Name must be a valid Lua name - hence periods in the name are not allowed.
The main use case for these annotations is to help with type checking of larger Ravi programs. These type checks, particularly the one for user defined types, are executed directly by the VM and hence are more efficient than performing the checks in other ways.
All three types above allow ``nil`` assignment.
Examples::
-- Create a metatable
local mt = { __name='MyType'}
-- Register the metatable in Lua registry
debug.getregistry().MyType = mt
-- Create an object and assign the metatable as its type
local t = {}
setmetatable(t, mt)
-- Use the metatable name as the object's type
function x(s: MyType)
local assert = assert
assert(@MyType(s) == @MyType(t))
assert(@MyType(t) == t)
end
-- Here we use the string type
function x(s1: string, s2: string)
return @string( s1 .. s2 )
end
-- Following demonstrates an error caused by the type checking
-- Note that this error is raised at runtime
function x()
local s: string
-- call a function that returns integer value
-- and try to assign to s
s = (function() return 1 end)()
end
x() -- will fail at runtime
Array Slices
------------
Since release 0.6 Ravi supports array slices. An array slice allows a portion of a Ravi array to be treated as if it is an array - this allows efficient access to the underlying array elements. Following new functions are available:
@ -275,16 +340,17 @@ A JIT api is available with following functions:
``ravi.dumplua(func)``
dumps the Lua bytecode of the function
``ravi.dumpir(func)``
dumps the IR of the compiled function (only if function was compiled; only LLVM version)
(deprecated) dumps the IR of the compiled function (only if function was compiled; only available in LLVM 4.0 and earlier)
``ravi.dumpasm(func)``
dumps the machine code using the currently set optimization level (only if function was compiled; only LLVM)
(deprecated) dumps the machine code using the currently set optimization level (only if function was compiled; only available in LLVM version 4.0 and earlier)
``ravi.optlevel([n])``
sets LLVM optimization level (0, 1, 2, 3); defaults to 2
sets LLVM optimization level (0, 1, 2, 3); defaults to 2. These levels are handled by reusing LLVMs default pass definitions which are geared towards C/C++ programs, but appear to work well here. If level is set to 0, then an attempt is made to use fast instruction selection to further speed up compilation.
``ravi.sizelevel([n])``
sets LLVM size level (0, 1, 2); defaults to 0
``ravi.tracehook([b])``
Enables support for line hooks via the debug api. Note that enabling this option will result in inefficient JIT as a call to a C function will be inserted at beginning of every Lua bytecode
boundary; use this option only when you want to use the debug api to step through code line by line
Enables support for line hooks via the debug api. Note that enabling this option will result in inefficient JIT as a call to a C function will be inserted at beginning of every Lua bytecode boundary; use this option only when you want to use the debug api to step through code line by line
``ravi.verbosity([b])``
Controls the amount of verbose messages generated during compilation. Currently only available for LLVM.
Performance
===========
@ -324,6 +390,12 @@ When JIT compilation is enabled there are following additional constraints:
Building Ravi
=============
Quick build without JIT
-----------------------
A Makefile is supplied for a simple build without the JIT. Just run ``make`` and follow instructions. You may need to customize the Makefiles.
For building Ravi with JIT options please read on.
Build Dependencies
------------------
@ -331,10 +403,12 @@ Build Dependencies
Ravi can be built with or without LLVM. Following versions of LLVM work with Ravi.
* LLVM 3.7 or 3.8 or 3.9 or 4.0
* LLVM 3.7 or 3.8 or 3.9 or 4.0 or 5.0
* LLVM 3.5 and 3.6 should also work but have not been recently tested
Unless otherwise noted the instructions below should work for LLVM 3.7 or later.
Unless otherwise noted the instructions below should work for LLVM 3.9 and later.
Since LLVM 5.0 Ravi has begun to use the new ORC JIT apis. These apis are more memory efficient compared to the MCJIT apis because they release the Module IR as early as possible, whereas with MCJIT the Module IR hangs around as long as the compiled code is held. Because of this significant improvement, I recommend using LLVM 5.0 and above.
Building LLVM on Windows
------------------------
@ -370,19 +444,19 @@ Building Ravi with JIT enabled
------------------------------
I am developing Ravi using Visual Studio 2017 Community Edition on Windows 10 64bit, gcc on Unbuntu 64-bit, and clang/Xcode on MAC OS X. I was also able to successfully build a Ubuntu version on Windows 10 using the newly released Ubuntu/Linux sub-system for Windows 10.
.. note:: Location of cmake files has moved in LLVM 3.9; the new path is ``$LLVM_INSTALL_DIR/lib/cmake/llvm``.
.. note:: Location of cmake files prior to LLVM 3.9 was ``$LLVM_INSTALL_DIR/share/llvm/cmake``.
Assuming that LLVM has been installed as described above, then on Windows I invoke the cmake config as follows::
cd build
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=c:\ravi -DLLVM_DIR=c:\LLVM37\share\llvm\cmake -G "Visual Studio 15 2017 Win64" ..
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=c:\ravi -DLLVM_DIR=c:\LLVM\lib\cmake\llvm -G "Visual Studio 15 2017 Win64" ..
I then open the solution in VS2017 and do a build from there.
On Ubuntu I use::
cd build
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM/share/llvm/cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" ..
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM/lib/cmake/llvm -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" ..
make
Note that on a clean install of Ubuntu 15.10 I had to install following packages:
@ -394,7 +468,7 @@ Note that on a clean install of Ubuntu 15.10 I had to install following packages
On MAC OS X I use::
cd build
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM/share/llvm/cmake -DCMAKE_BUILD_TYPE=Release -G "Xcode" ..
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM/lib/cmake/llvm -DCMAKE_BUILD_TYPE=Release -G "Xcode" ..
I open the generated project in Xcode and do a build from there. You can also use the command line build tools if you wish - generate the make files in the same way as for Linux.
@ -429,15 +503,19 @@ 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
* 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:
- I would like Ravi to be backward compatible with Lua 5.1 and 5.2 as far as possible
- Lua function inlining
- Improve performance of Ravi
- Additional type annotations
* 2015
- Implemented JIT compilation using LLVM
- Implemented libgccjit based alternative JIT (now discontinued)
* 2016
- Implemented debugger for Ravi and Lua 5.3 for `Visual Studio Code <https://github.com/dibyendumajumdar/ravi/tree/master/vscode-debugger>`_
* 2017
- Embedded C compiler using dmrC project (C JIT compiler)
- Additional type annotations
* 2018
- 1.0 release of Ravi
- More testing and test cases
- ASM VM for X86-64 platform
- Better support for earlier Lua versions (5.1 especially)
License
=======

@ -0,0 +1,357 @@
# Makefile for building Ravi based on Lua Makefile
# This Makefile builds an interpreter only version right now - no JIT
# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================
# Your platform. See PLATS for possible values.
PLAT= none
#CC= gcc -std=gnu99
CFLAGS= -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_COMPAT_5_1 $(SYSCFLAGS) $(MYCFLAGS) -I../include
CXXFLAGS=$(CFLAGS) -fno-rtti -Wno-sign-compare -std=c++14 -fno-exceptions -I../include
LDFLAGS= $(SYSLDFLAGS) $(MYLDFLAGS)
LIBS= -lm $(SYSLIBS) $(MYLIBS)
VPATH=../include
AR= ar rcu
RANLIB= ranlib
RM= rm -f
SYSCFLAGS=
SYSLDFLAGS=
SYSLIBS=
MYCFLAGS=
MYLDFLAGS=
MYLIBS=
MYOBJS=
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
PLATS= aix bsd c89 freebsd generic linux macosx mingw posix solaris
LUA_A= libravinojit.a
CORE_CPP_O=ravijit.o
CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o \
lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o \
ltm.o lundump.o lvm.o lzio.o ravi_profile.o ravi_membuf.o \
ravi_jitshared.o ravi_nojit.o $(CORE_CPP_O)
LIB_O= lauxlib.o lbaselib.o lbitlib.o lcorolib.o ldblib.o liolib.o \
lmathlib.o loslib.o lstrlib.o ltablib.o lutf8lib.o loadlib.o linit.o \
bit.o
BASE_O= $(CORE_O) $(LIB_O) $(MYOBJS)
LUA_T= ravi
LUA_O= lua.o
ALL_O= $(BASE_O) $(LUA_O)
ALL_T= $(LUA_A) $(LUA_T)
ALL_A= $(LUA_A)
# Targets start here.
default: $(PLAT)
all: $(ALL_T)
o: $(ALL_O)
a: $(ALL_A)
$(LUA_A): $(BASE_O)
$(AR) $@ $(BASE_O)
$(RANLIB) $@
$(LUA_T): $(LUA_O) $(LUA_A)
$(CC) -o $@ $(LDFLAGS) $(LUA_O) $(LUA_A) $(LIBS)
clean:
$(RM) $(ALL_T) $(ALL_O)
depend:
@$(CC) $(CFLAGS) -MM *.c
@$(CC) $(CXXFLAGS) -MM ravijit.cpp
echo:
@echo "PLAT= $(PLAT)"
@echo "CC= $(CC)"
@echo "CFLAGS= $(CFLAGS)"
@echo "LDFLAGS= $(SYSLDFLAGS)"
@echo "LIBS= $(LIBS)"
@echo "AR= $(AR)"
@echo "RANLIB= $(RANLIB)"
@echo "RM= $(RM)"
# Convenience targets for popular platforms
ALL= all
none:
@echo "Please do 'make PLATFORM' where PLATFORM is one of these:"
@echo " $(PLATS)"
aix:
$(MAKE) $(ALL) CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-ldl" SYSLDFLAGS="-brtl -bexpall"
bsd:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-Wl,-E"
c89:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_C89" CC="gcc -std=c89"
@echo ''
@echo '*** C89 does not guarantee 64-bit integers for Lua.'
@echo ''
freebsd:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -lreadline"
generic: $(ALL)
linux:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline"
macosx:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX" SYSLIBS="-lreadline" CC=cc
mingw:
$(MAKE) "LUA_A=ravi.dll" "LUA_T=ravi.exe" \
"AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \
"SYSCFLAGS=-DLUA_BUILD_AS_DLL" "SYSLIBS=" "SYSLDFLAGS=-s" ravi.exe
posix:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX"
solaris:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN -D_REENTRANT" SYSLIBS="-ldl"
# list targets that do not create files (but not all makes understand .PHONY)
.PHONY: all $(PLATS) default o a clean depend echo none
# DO NOT DELETE
bit.o: bit.c ../include/lua.h ../include/luaconf.h ../include/lauxlib.h \
../include/lua.h
lapi.o: lapi.c ../include/lprefix.h ../include/lua.h ../include/luaconf.h \
../include/lapi.h ../include/llimits.h ../include/lua.h \
../include/lstate.h ../include/lobject.h ../include/ltm.h \
../include/lzio.h ../include/lmem.h ../include/ldebug.h ../include/ldo.h \
../include/lfunc.h ../include/lgc.h ../include/lmem.h \
../include/lobject.h ../include/lstate.h ../include/lstring.h \
../include/lgc.h ../include/ltable.h ../include/ltm.h \
../include/lundump.h ../include/lvm.h ../include/ldo.h
lauxlib.o: lauxlib.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lauxlib.h ../include/lua.h
lbaselib.o: lbaselib.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lauxlib.h ../include/lua.h \
../include/lualib.h
lbitlib.o: lbitlib.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lauxlib.h ../include/lua.h \
../include/lualib.h
lcode.o: lcode.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lcode.h ../include/llex.h \
../include/lobject.h ../include/llimits.h ../include/lua.h \
../include/lzio.h ../include/lmem.h ../include/lopcodes.h \
../include/lparser.h ../include/ldebug.h ../include/lstate.h \
../include/ltm.h ../include/ldo.h ../include/lgc.h ../include/llex.h \
../include/lmem.h ../include/lobject.h ../include/lopcodes.h \
../include/lparser.h ../include/lstring.h ../include/lgc.h \
../include/ltable.h ../include/lvm.h ../include/ldo.h
lcorolib.o: lcorolib.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lauxlib.h ../include/lua.h \
../include/lualib.h
lctype.o: lctype.c ../include/lprefix.h ../include/lctype.h \
../include/lua.h ../include/luaconf.h ../include/llimits.h
ldblib.o: ldblib.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lauxlib.h ../include/lua.h \
../include/lualib.h
ldebug.o: ldebug.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lapi.h ../include/llimits.h \
../include/lua.h ../include/lstate.h ../include/lobject.h \
../include/ltm.h ../include/lzio.h ../include/lmem.h ../include/lcode.h \
../include/llex.h ../include/lopcodes.h ../include/lparser.h \
../include/ldebug.h ../include/ldo.h ../include/lfunc.h \
../include/lobject.h ../include/lopcodes.h ../include/lstate.h \
../include/lstring.h ../include/lgc.h ../include/ltable.h \
../include/ltm.h ../include/lvm.h ../include/ldo.h
ldo.o: ldo.c ../include/lprefix.h ../include/lua.h ../include/luaconf.h \
../include/lapi.h ../include/llimits.h ../include/lua.h \
../include/lstate.h ../include/lobject.h ../include/ltm.h \
../include/lzio.h ../include/lmem.h ../include/ldebug.h ../include/ldo.h \
../include/lfunc.h ../include/lgc.h ../include/lmem.h \
../include/lobject.h ../include/lopcodes.h ../include/lparser.h \
../include/lstate.h ../include/lstring.h ../include/lgc.h \
../include/ltable.h ../include/ltm.h ../include/lundump.h \
../include/lvm.h ../include/ldo.h ../include/lzio.h ../include/ravijit.h \
../include/ravi_jitshared.h ../include/lprefix.h ../include/lauxlib.h \
../include/ldebug.h ../include/lfunc.h ../include/lopcodes.h \
../include/lstring.h ../include/ltable.h ../include/lvm.h \
../include/ravi_membuf.h
ldump.o: ldump.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lobject.h ../include/llimits.h \
../include/lua.h ../include/lstate.h ../include/lobject.h \
../include/ltm.h ../include/lzio.h ../include/lmem.h \
../include/lundump.h
lfunc.o: lfunc.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lfunc.h ../include/lobject.h \
../include/llimits.h ../include/lua.h ../include/lgc.h \
../include/lstate.h ../include/ltm.h ../include/lzio.h ../include/lmem.h \
../include/lmem.h ../include/lobject.h ../include/lstate.h \
../include/ravijit.h
lgc.o: lgc.c ../include/lprefix.h ../include/lua.h ../include/luaconf.h \
../include/ldebug.h ../include/lstate.h ../include/lua.h \
../include/lobject.h ../include/llimits.h ../include/ltm.h \
../include/lzio.h ../include/lmem.h ../include/ldo.h ../include/lfunc.h \
../include/lgc.h ../include/lmem.h ../include/lobject.h \
../include/lstate.h ../include/lstring.h ../include/lgc.h \
../include/ltable.h ../include/ltm.h
linit.o: linit.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lualib.h ../include/lua.h \
../include/lauxlib.h
liolib.o: liolib.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lauxlib.h ../include/lua.h \
../include/lualib.h
llex.o: llex.c ../include/lprefix.h ../include/lua.h ../include/luaconf.h \
../include/lctype.h ../include/lua.h ../include/llimits.h \
../include/ldebug.h ../include/lstate.h ../include/lobject.h \
../include/ltm.h ../include/lzio.h ../include/lmem.h ../include/ldo.h \
../include/lgc.h ../include/llex.h ../include/lobject.h \
../include/lparser.h ../include/lstate.h ../include/lstring.h \
../include/lgc.h ../include/ltable.h ../include/lzio.h
lmathlib.o: lmathlib.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lauxlib.h ../include/lua.h \
../include/lualib.h
lmem.o: lmem.c ../include/lprefix.h ../include/lua.h ../include/luaconf.h \
../include/ldebug.h ../include/lstate.h ../include/lua.h \
../include/lobject.h ../include/llimits.h ../include/ltm.h \
../include/lzio.h ../include/lmem.h ../include/ldo.h ../include/lgc.h \
../include/lmem.h ../include/lobject.h ../include/lstate.h
loadlib.o: loadlib.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lauxlib.h ../include/lua.h \
../include/lualib.h
lobject.o: lobject.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lctype.h ../include/lua.h \
../include/llimits.h ../include/ldebug.h ../include/lstate.h \
../include/lobject.h ../include/ltm.h ../include/lzio.h \
../include/lmem.h ../include/ldo.h ../include/lmem.h \
../include/lobject.h ../include/lstate.h ../include/lstring.h \
../include/lgc.h ../include/lvm.h ../include/ldo.h
lopcodes.o: lopcodes.c ../include/lprefix.h ../include/lopcodes.h \
../include/llimits.h ../include/lua.h ../include/luaconf.h \
../include/lobject.h ../include/lstate.h ../include/lobject.h \
../include/ltm.h ../include/lzio.h ../include/lmem.h ../include/ldebug.h \
../include/lstate.h
loslib.o: loslib.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lauxlib.h ../include/lua.h \
../include/lualib.h
lparser.o: lparser.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lcode.h ../include/llex.h \
../include/lobject.h ../include/llimits.h ../include/lua.h \
../include/lzio.h ../include/lmem.h ../include/lopcodes.h \
../include/lparser.h ../include/ldebug.h ../include/lstate.h \
../include/ltm.h ../include/ldo.h ../include/lfunc.h ../include/llex.h \
../include/lmem.h ../include/lobject.h ../include/lopcodes.h \
../include/lparser.h ../include/lstate.h ../include/lstring.h \
../include/lgc.h ../include/ltable.h
lstate.o: lstate.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lapi.h ../include/llimits.h \
../include/lua.h ../include/lstate.h ../include/lobject.h \
../include/ltm.h ../include/lzio.h ../include/lmem.h ../include/ldebug.h \
../include/ldo.h ../include/lfunc.h ../include/lgc.h ../include/llex.h \
../include/lmem.h ../include/lstate.h ../include/lstring.h \
../include/lgc.h ../include/ltable.h ../include/ltm.h \
../include/ravijit.h ../include/ravi_profile.h ../include/lopcodes.h
lstring.o: lstring.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/ldebug.h ../include/lstate.h \
../include/lua.h ../include/lobject.h ../include/llimits.h \
../include/ltm.h ../include/lzio.h ../include/lmem.h ../include/ldo.h \
../include/lmem.h ../include/lobject.h ../include/lstate.h \
../include/lstring.h ../include/lgc.h
lstrlib.o: lstrlib.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lauxlib.h ../include/lua.h \
../include/lualib.h
ltable.o: ltable.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/ldebug.h ../include/lstate.h \
../include/lua.h ../include/lobject.h ../include/llimits.h \
../include/ltm.h ../include/lzio.h ../include/lmem.h ../include/ldo.h \
../include/lgc.h ../include/lmem.h ../include/lobject.h \
../include/lstate.h ../include/lstring.h ../include/lgc.h \
../include/ltable.h ../include/lvm.h ../include/ldo.h
ltablib.o: ltablib.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lauxlib.h ../include/lua.h \
../include/lualib.h
ltests.o: ltests.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lapi.h ../include/llimits.h \
../include/lua.h ../include/lstate.h ../include/lobject.h \
../include/ltm.h ../include/lzio.h ../include/lmem.h \
../include/lauxlib.h ../include/lcode.h ../include/llex.h \
../include/lopcodes.h ../include/lparser.h ../include/lctype.h \
../include/ldebug.h ../include/ldo.h ../include/lfunc.h \
../include/lmem.h ../include/lopcodes.h ../include/lstate.h \
../include/lstring.h ../include/lgc.h ../include/ltable.h \
../include/lualib.h
ltm.o: ltm.c ../include/lprefix.h ../include/lua.h ../include/luaconf.h \
../include/ldebug.h ../include/lstate.h ../include/lua.h \
../include/lobject.h ../include/llimits.h ../include/ltm.h \
../include/lzio.h ../include/lmem.h ../include/ldo.h \
../include/lobject.h ../include/lstate.h ../include/lstring.h \
../include/lgc.h ../include/ltable.h ../include/ltm.h ../include/lvm.h \
../include/ldo.h
lua.o: lua.c ../include/lprefix.h ../include/lua.h ../include/luaconf.h \
../include/lauxlib.h ../include/lua.h ../include/lualib.h
luac.o: luac.c ../include/lprefix.h ../include/lua.h ../include/luaconf.h \
../include/lauxlib.h ../include/lua.h ../include/lobject.h \
../include/llimits.h ../include/lstate.h ../include/lobject.h \
../include/ltm.h ../include/lzio.h ../include/lmem.h \
../include/lundump.h ../include/ldebug.h ../include/lstate.h \
../include/lopcodes.h
lundump.o: lundump.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/ldebug.h ../include/lstate.h \
../include/lua.h ../include/lobject.h ../include/llimits.h \
../include/ltm.h ../include/lzio.h ../include/lmem.h ../include/ldo.h \
../include/lfunc.h ../include/lmem.h ../include/lobject.h \
../include/lstring.h ../include/lgc.h ../include/lundump.h \
../include/lzio.h
lutf8lib.o: lutf8lib.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lauxlib.h ../include/lua.h \
../include/lualib.h
lvm.o: lvm.c ../include/lprefix.h ../include/lua.h ../include/luaconf.h \
../include/ldebug.h ../include/lstate.h ../include/lua.h \
../include/lobject.h ../include/llimits.h ../include/ltm.h \
../include/lzio.h ../include/lmem.h ../include/ldo.h ../include/lfunc.h \
../include/lgc.h ../include/lobject.h ../include/lopcodes.h \
../include/lstate.h ../include/lstring.h ../include/lgc.h \
../include/ltable.h ../include/ltm.h ../include/lvm.h ../include/ldo.h \
../include/ravi_profile.h ../include/lopcodes.h
lzio.o: lzio.c ../include/lprefix.h ../include/lua.h ../include/luaconf.h \
../include/llimits.h ../include/lua.h ../include/lmem.h \
../include/llimits.h ../include/lstate.h ../include/lobject.h \
../include/ltm.h ../include/lzio.h ../include/lmem.h ../include/lzio.h
ravi_jitshared.o: ravi_jitshared.c ../include/ravi_jitshared.h \
../include/lprefix.h ../include/lauxlib.h ../include/lua.h \
../include/luaconf.h ../include/ldebug.h ../include/lstate.h \
../include/lobject.h ../include/llimits.h ../include/ltm.h \
../include/lzio.h ../include/lmem.h ../include/ldo.h ../include/lfunc.h \
../include/lopcodes.h ../include/lstring.h ../include/lgc.h \
../include/ltable.h ../include/lvm.h ../include/ravi_membuf.h
ravi_membuf.o: ravi_membuf.c ../include/ravi_membuf.h
ravi_nojit.o: ravi_nojit.c ../include/ravijit.h \
../include/ravi_jitshared.h ../include/lprefix.h ../include/lauxlib.h \
../include/lua.h ../include/luaconf.h ../include/ldebug.h \
../include/lstate.h ../include/lobject.h ../include/llimits.h \
../include/ltm.h ../include/lzio.h ../include/lmem.h ../include/ldo.h \
../include/lfunc.h ../include/lopcodes.h ../include/lstring.h \
../include/lgc.h ../include/ltable.h ../include/lvm.h \
../include/ravi_membuf.h
ravi_profile.o: ravi_profile.c ../include/ravi_profile.h ../include/lua.h \
../include/luaconf.h ../include/lopcodes.h ../include/llimits.h \
../include/lstate.h ../include/lobject.h ../include/ltm.h \
../include/lzio.h ../include/lmem.h
ravijit.o: ravijit.cpp ../include/ravijit.h ../include/ravi_jitshared.h \
../include/lprefix.h ../include/lauxlib.h ../include/lua.h \
../include/luaconf.h ../include/ldebug.h ../include/lstate.h \
../include/lobject.h ../include/llimits.h ../include/ltm.h \
../include/lzio.h ../include/lmem.h ../include/ldo.h ../include/lfunc.h \
../include/lopcodes.h ../include/lstring.h ../include/lgc.h \
../include/ltable.h ../include/lvm.h ../include/ravi_membuf.h \
../include/lapi.h ../include/lauxlib.h ../include/lfunc.h \
../include/lobject.h ../include/lopcodes.h ../include/lstate.h \
../include/lua.h

@ -0,0 +1,130 @@
/*
** Lua BitOp -- a bit operations library for Lua 5.1/5.2.
** http://bitop.luajit.org/
**
** Copyright (C) 2008-2012 Mike Pall. All rights reserved.
**
** 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.
**
** [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
*/
#define LUA_BITOP_VERSION "1.0.2"
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include <stdint.h>
typedef int32_t SBits;
typedef uint32_t UBits;
/* Convert argument to bit type. */
static inline UBits barg(lua_State *L, int idx)
{
return (UBits)luaL_checkinteger(L, idx);
}
/* Return bit type. */
#define BRET(b) lua_pushinteger(L, (lua_Integer)(SBits)(b)); return 1;
static int bit_tobit(lua_State *L) { BRET(barg(L, 1)) }
static int bit_bnot(lua_State *L) { BRET(~barg(L, 1)) }
#define BIT_OP(func, opr) \
static int func(lua_State *L) { int i; UBits b = barg(L, 1); \
for (i = lua_gettop(L); i > 1; i--) b opr barg(L, i); BRET(b) }
BIT_OP(bit_band, &=)
BIT_OP(bit_bor, |=)
BIT_OP(bit_bxor, ^=)
#define bshl(b, n) (b << n)
#define bshr(b, n) (b >> n)
#define bsar(b, n) ((SBits)b >> n)
#define brol(b, n) ((b << n) | (b >> (32-n)))
#define bror(b, n) ((b << (32-n)) | (b >> n))
#define BIT_SH(func, fn) \
static int func(lua_State *L) { \
UBits b = barg(L, 1); UBits n = barg(L, 2) & 31; BRET(fn(b, n)) }
BIT_SH(bit_lshift, bshl)
BIT_SH(bit_rshift, bshr)
BIT_SH(bit_arshift, bsar)
BIT_SH(bit_rol, brol)
BIT_SH(bit_ror, bror)
static int bit_bswap(lua_State *L)
{
UBits b = barg(L, 1);
b = (b >> 24) | ((b >> 8) & 0xff00) | ((b & 0xff00) << 8) | (b << 24);
BRET(b)
}
static int bit_tohex(lua_State *L)
{
UBits b = barg(L, 1);
SBits n = lua_isnone(L, 2) ? 8 : (SBits)barg(L, 2);
const char *hexdigits = "0123456789abcdef";
char buf[8];
int i;
if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; }
if (n > 8) n = 8;
for (i = (int)n; --i >= 0; ) { buf[i] = hexdigits[b & 15]; b >>= 4; }
lua_pushlstring(L, buf, (size_t)n);
return 1;
}
static const struct luaL_Reg bit_funcs[] = {
{ "tobit", bit_tobit },
{ "bnot", bit_bnot },
{ "band", bit_band },
{ "bor", bit_bor },
{ "bxor", bit_bxor },
{ "lshift", bit_lshift },
{ "rshift", bit_rshift },
{ "arshift", bit_arshift },
{ "rol", bit_rol },
{ "ror", bit_ror },
{ "bswap", bit_bswap },
{ "tohex", bit_tohex },
{ NULL, NULL }
};
/* Signed right-shifts are implementation-defined per C89/C99.
** But the de facto standard are arithmetic right-shifts on two's
** complement CPUs. This behaviour is required here, so test for it.
*/
#define BAD_SAR (bsar(-8, 2) != (SBits)-2)
LUALIB_API int luaopen_bit(lua_State *L)
{
UBits b;
lua_pushnumber(L, (lua_Number)1437217655L);
b = barg(L, -1);
if (b != (UBits)1437217655L || BAD_SAR) { /* Perform a simple self-test. */
const char *msg = "compiled with incompatible luaconf.h";
if (BAD_SAR)
msg = "arithmetic right-shift broken";
luaL_error(L, "bit library self-test failed (%s)", msg);
}
luaL_newlib(L, bit_funcs);
return 1;
}

@ -670,14 +670,13 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L);
t = index2addr(L, idx);
if (ttisLtable(t) || !ttistable(t)) {
if (luaV_fastget(L, t, n, slot, luaH_getint)) {
if (luaV_fastgeti(L, t, n, slot)) {
setobj2s(L, L->top, slot);
api_incr_top(L);
}
else {
setivalue(L->top, n);
api_incr_top(L);
luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
TValue aux;
setivalue(&aux, n);
luaV_finishget(L, t, &aux, L->top, slot);
}
}
else {
@ -694,8 +693,8 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
setnilvalue(L->top);
}
}
api_incr_top(L);
}
api_incr_top(L);
lua_unlock(L);
return ttnov(L->top - 1);
}
@ -964,8 +963,10 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *slot;
TString *str = luaS_new(L, k);
api_checknelems(L, 1);
if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1))
if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
luaV_finishfastset(L, t, slot, L->top - 1);
L->top--; /* pop value */
}
else {
setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */
api_incr_top(L);
@ -1007,13 +1008,13 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
api_checknelems(L, 1);
t = index2addr(L, idx);
if (ttisLtable(t) || !ttistable(t)) {
if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1))
L->top--; /* pop value */
if (luaV_fastgeti(L, t, n, slot)) {
luaV_finishfastset(L, t, slot, L->top - 1);
}
else {
setivalue(L->top, n);
api_incr_top(L);
luaV_finishset(L, t, L->top - 1, L->top - 2, slot);
L->top -= 2; /* pop value and key */
TValue aux;
setivalue(&aux, n);
luaV_finishset(L, t, &aux, L->top - 1, slot);
}
}
else {
@ -1041,8 +1042,8 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
luaG_runerror(L, "value cannot be converted to integer");
}
}
L->top--;
}
L->top--; /* pop value */
lua_unlock(L);
}
@ -1559,7 +1560,7 @@ static const char *aux_upvalue (StkId fi, int n, TValue **val,
*val = f->upvals[n-1]->v;
if (uv) *uv = f->upvals[n - 1];
name = p->upvalues[n-1].name;
*type = p->upvalues[n - 1].type;
*type = p->upvalues[n - 1].ravi_type;
return (name == NULL) ? "(*no name)" : getstr(name);
}
default: return NULL; /* not a closure */
@ -1631,7 +1632,7 @@ static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf, ravity
api_check(L, ttisLclosure(fi), "Lua function expected");
f = clLvalue(fi);
api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index");
if (type) *type = f->p->upvalues[n - 1].type;
if (type) *type = f->p->upvalues[n - 1].ravi_type;
if (pf) *pf = f;
return &f->upvals[n - 1]; /* get its upvalue pointer */
}

@ -1077,12 +1077,12 @@ LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) {
(LUAI_UACNUMBER)ver, (LUAI_UACNUMBER)*v);
}
LUALIB_API int (raviL_dumpast) (lua_State *L) {
(void) L;
return 0;
}
#if 0
/* The normal Lua metatable functions in C use string
keys - these are expensive as the key needs to be
converted to Lua string, hash code computed etc.
@ -1143,3 +1143,5 @@ LUALIB_API void *raviL_checkudata(lua_State *L, int arg_index,
luaL_argerror(L, arg_index, meta_key);
return p;
}
#endif

@ -600,16 +600,16 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
freereg(fs, e->u.ind.t);
/* TODO we should do this for upvalues too */
/* table access - set specialized op codes if array types are detected */
if (e->ravi_type == RAVI_TARRAYFLT && e->u.ind.key_type == RAVI_TNUMINT)
if (e->ravi_type == RAVI_TARRAYFLT && e->u.ind.key_ravi_type == RAVI_TNUMINT)
op = OP_RAVI_GETTABLE_AF;
else if (e->ravi_type == RAVI_TARRAYINT && e->u.ind.key_type == RAVI_TNUMINT)
else if (e->ravi_type == RAVI_TARRAYINT && e->u.ind.key_ravi_type == RAVI_TNUMINT)
op = OP_RAVI_GETTABLE_AI;
/* Check that we have a short string constant */
else if (e->ravi_type == RAVI_TTABLE && e->u.ind.key_type == RAVI_TSTRING && isshortstr(fs, e->u.ind.idx))
else if (e->ravi_type == RAVI_TTABLE && e->u.ind.key_ravi_type == RAVI_TSTRING && isshortstr(fs, e->u.ind.idx))
op = OP_RAVI_GETTABLE_S;
else if (e->ravi_type == RAVI_TTABLE && e->u.ind.key_type == RAVI_TNUMINT)
else if (/* e->ravi_type == RAVI_TTABLE &&*/ e->u.ind.key_ravi_type == RAVI_TNUMINT)
op = OP_RAVI_GETTABLE_I;
else if (e->u.ind.key_type == RAVI_TSTRING && isshortstr(fs, e->u.ind.idx))
else if (e->u.ind.key_ravi_type == RAVI_TSTRING && isshortstr(fs, e->u.ind.idx))
op = OP_RAVI_GETTABLE_SK;
else
op = OP_GETTABLE;
@ -621,7 +621,10 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
}
else {
lua_assert(e->u.ind.vt == VUPVAL);
op = OP_GETTABUP; /* 't' is in an upvalue */
if (e->u.ind.key_ravi_type == RAVI_TSTRING && isshortstr(fs, e->u.ind.idx))
op = OP_RAVI_GETTABUP_SK;
else
op = OP_GETTABUP; /* 't' is in an upvalue */
}
e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx);
e->k = VRELOCABLE;
@ -674,7 +677,8 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
case VNONRELOC: {
if (reg != e->u.info) {
/* code a MOVEI or MOVEF if the target register is a local typed variable */
int ravi_type = raviY_get_register_typeinfo(fs, reg);
TString *usertype = NULL;
int ravi_type = raviY_get_register_typeinfo(fs, reg, &usertype);
switch (ravi_type) {
case RAVI_TNUMINT:
luaK_codeABC(fs, OP_RAVI_MOVEI, reg, e->u.info, 0);
@ -693,6 +697,12 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
break;
default:
luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0);
if (ravi_type == RAVI_TSTRING)
luaK_codeABC(fs, OP_RAVI_TOSTRING, reg, 0, 0);
else if (ravi_type == RAVI_TFUNCTION)
luaK_codeABC(fs, OP_RAVI_TOCLOSURE, reg, 0, 0);
else if (ravi_type == RAVI_TUSERDATA && usertype)
luaK_codeABx(fs, OP_RAVI_TOTYPE, reg, luaK_stringK(fs, usertype));
break;
}
}
@ -855,7 +865,10 @@ static void check_valid_store(FuncState *fs, expdesc *var, expdesc *ex) {
var->ravi_type == RAVI_TNUMINT ||
var->ravi_type == RAVI_TARRAYFLT ||
var->ravi_type == RAVI_TARRAYINT ||
var->ravi_type == RAVI_TTABLE)) {
var->ravi_type == RAVI_TTABLE ||
var->ravi_type == RAVI_TSTRING ||
var->ravi_type == RAVI_TFUNCTION ||
var->ravi_type == RAVI_TUSERDATA)) {
/* handled by MOVEI, MOVEF, MOVEAI, MOVEAF at runtime */
return;
}
@ -895,13 +908,43 @@ static void check_valid_store(FuncState *fs, expdesc *var, expdesc *ex) {
"Invalid assignment: %s expected",
var->ravi_type == RAVI_TTABLE ? "table" : (var->ravi_type == RAVI_TARRAYFLT ? "number[]" : "integer[]")));
}
else if (var->ravi_type == RAVI_TSTRING) {
if (ex->ravi_type == RAVI_TNIL || (ex->ravi_type == var->ravi_type && ex->k != VINDEXED))
return;
luaX_syntaxerror(
fs->ls,
luaO_pushfstring(
fs->ls->L,
"Invalid assignment: string expected"));
}
else if (var->ravi_type == RAVI_TFUNCTION) {
if (ex->ravi_type == RAVI_TNIL || (ex->ravi_type == var->ravi_type && ex->k != VINDEXED))
return;
luaX_syntaxerror(
fs->ls,
luaO_pushfstring(
fs->ls->L,
"Invalid assignment: function expected"));
}
else if (var->ravi_type == RAVI_TUSERDATA) {
if (ex->ravi_type == RAVI_TNIL ||
(ex->ravi_type == var->ravi_type && var->usertype && var->usertype == ex->usertype && ex->k != VINDEXED))
return;
luaX_syntaxerror(
fs->ls,
luaO_pushfstring(
fs->ls->L,
"Invalid assignment: usertype %s expected", (var->usertype ? getstr(var->usertype) : "UNKNOWN")));
}
}
static OpCode check_valid_setupval(FuncState *fs, expdesc *var, expdesc *ex) {
static OpCode check_valid_setupval(FuncState *fs, expdesc *var, expdesc *ex,
int reg) {
OpCode op = OP_SETUPVAL;
if ((var->ravi_type == RAVI_TNUMINT || var->ravi_type == RAVI_TNUMFLT ||
var->ravi_type == RAVI_TARRAYFLT || var->ravi_type == RAVI_TARRAYINT ||
var->ravi_type == RAVI_TTABLE) &&
var->ravi_type == RAVI_TTABLE || var->ravi_type == RAVI_TSTRING ||
var->ravi_type == RAVI_TFUNCTION || var->ravi_type == RAVI_TUSERDATA) &&
var->ravi_type != ex->ravi_type) {
if (var->ravi_type == RAVI_TNUMINT)
op = OP_RAVI_SETUPVALI;
@ -913,12 +956,21 @@ static OpCode check_valid_setupval(FuncState *fs, expdesc *var, expdesc *ex) {
op = OP_RAVI_SETUPVALAF;
else if (var->ravi_type == RAVI_TTABLE)
op = OP_RAVI_SETUPVALT;
else if (var->ravi_type == RAVI_TSTRING)
luaK_codeABC(fs, OP_RAVI_TOSTRING, reg, 0, 0);
else if (var->ravi_type == RAVI_TFUNCTION)
luaK_codeABC(fs, OP_RAVI_TOCLOSURE, reg, 0, 0);
else if (var->ravi_type == RAVI_TUSERDATA) {
TString *usertype = fs->f->upvalues[var->u.info].usertype;
luaK_codeABx(fs, OP_RAVI_TOTYPE, reg, luaK_stringK(fs, usertype));
}
else
luaX_syntaxerror(fs->ls,
luaO_pushfstring(fs->ls->L, "Invalid assignment of "
"upvalue: upvalue type "
"%s, expression type %s",
raviY_typename(var->ravi_type), raviY_typename(ex->ravi_type)));
luaX_syntaxerror(fs->ls, luaO_pushfstring(fs->ls->L,
"Invalid assignment of "
"upvalue: upvalue type "
"%s, expression type %s",
raviY_typename(var->ravi_type),
raviY_typename(ex->ravi_type)));
}
return op;
}
@ -933,8 +985,8 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
return;
}
case VUPVAL: {
OpCode op = check_valid_setupval(fs, var, ex);
int e = luaK_exp2anyreg(fs, ex);
OpCode op = check_valid_setupval(fs, var, ex, e);
luaK_codeABC(fs, op, e, var->u.info, 0);
break;
}
@ -943,7 +995,7 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
if (op == OP_SETTABLE) {
/* table value set - if array access then use specialized versions */
if (var->ravi_type == RAVI_TARRAYFLT &&
var->u.ind.key_type == RAVI_TNUMINT) {
var->u.ind.key_ravi_type == RAVI_TNUMINT) {
if (!(ex->ravi_type == RAVI_TNUMFLT || (ex->k == VINDEXED && ex->ravi_type == RAVI_TARRAYFLT)))
/* input value may need conversion */
op = OP_RAVI_SETTABLE_AF;
@ -951,21 +1003,21 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
/* input value is known to be number */
op = OP_RAVI_SETTABLE_AFF;
} else if (var->ravi_type == RAVI_TARRAYINT &&
var->u.ind.key_type == RAVI_TNUMINT) {
var->u.ind.key_ravi_type == RAVI_TNUMINT) {
if (!(ex->ravi_type == RAVI_TNUMINT || (ex->k == VINDEXED && ex->ravi_type == RAVI_TARRAYINT)))
/* input value may need conversion */
op = OP_RAVI_SETTABLE_AI;
else
/* input value is known to be integer */
op = OP_RAVI_SETTABLE_AII;
} else if (var->ravi_type == RAVI_TTABLE && var->u.ind.key_type == RAVI_TNUMINT) {
} else if (/* var->ravi_type == RAVI_TTABLE &&*/ var->u.ind.key_ravi_type == RAVI_TNUMINT) {
/* table with integer key */
op = OP_RAVI_SETTABLE_I;
} else if (var->ravi_type == RAVI_TTABLE && var->u.ind.key_type == RAVI_TSTRING && isshortstr(fs, var->u.ind.idx)) {
} else if (var->ravi_type == RAVI_TTABLE && var->u.ind.key_ravi_type == RAVI_TSTRING && isshortstr(fs, var->u.ind.idx)) {
/* table with string key */
op = OP_RAVI_SETTABLE_S;
}
else if (var->u.ind.key_type == RAVI_TSTRING && isshortstr(fs, var->u.ind.idx)) {
else if (var->u.ind.key_ravi_type == RAVI_TSTRING && isshortstr(fs, var->u.ind.idx)) {
/* table with string key */
op = OP_RAVI_SETTABLE_SK;
}
@ -995,10 +1047,12 @@ void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
key->k == VK &&
key->ravi_type == RAVI_TSTRING &&
ttisshrstring(&fs->f->k[key->u.info]);
int table_and_string =
e->ravi_type == RAVI_TTABLE &&
is_string_constant_key;
luaK_exp2anyreg(fs, e);
// The check below needs to be
// after exp2anyreg as this can modify e->ravi_type
int table_and_string =
e->ravi_type == RAVI_TTABLE &&
is_string_constant_key;
ereg = e->u.info; /* register where 'e' was placed */
freeexp(fs, e);
e->u.info = fs->freereg; /* base register for op_self */
@ -1140,7 +1194,8 @@ static void codenot (FuncState *fs, expdesc *e) {
void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
lua_assert(!hasjumps(t) && (vkisinreg(t->k) || t->k == VUPVAL));
t->u.ind.t = t->u.info; /* register or upvalue index */
t->u.ind.key_type = k->ravi_type; /* RAVI record the key type */
t->u.ind.key_ravi_type = k->ravi_type; /* RAVI record the key type */
t->u.ind.usertype = k->usertype; /* RAVI record the key type */
t->u.ind.idx = luaK_exp2RK(fs, k); /* R/K index for key */
t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL : VLOCAL;
t->k = VINDEXED;
@ -1209,14 +1264,22 @@ static int constfolding (FuncState *fs, int op, expdesc *e1,
** Expression to produce final result will be encoded in 'e'.
*/
static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) {
ravitype_t e_type = e->ravi_type;
int r = luaK_exp2anyreg(fs, e); /* opcodes operate only on registers */
freeexp(fs, e);
if (op == OP_BNOT && e->ravi_type == RAVI_TNUMINT)
op = OP_RAVI_BNOT_I;
e->u.info = luaK_codeABC(fs, op, 0, r, 0); /* generate opcode */
e->k = VRELOCABLE; /* all those operations are relocatable */
if (op == OP_LEN)
e->ravi_type = RAVI_TNUMINT;
if (op == OP_LEN) {
if (e_type == RAVI_TARRAYINT || e_type == RAVI_TARRAYFLT)
e->ravi_type = RAVI_TNUMINT;
else if (e_type == RAVI_TTABLE) {
luaK_exp2anyreg(fs, e);
luaK_codeABC(fs, OP_RAVI_TOINT, e->u.info, 0, 0);
e->ravi_type = RAVI_TNUMINT;
}
}
luaK_fixline(fs, line);
}
@ -1317,6 +1380,10 @@ static void codebinexpval (FuncState *fs, OpCode op,
else if ((op == OP_DIV)
&& e1->ravi_type == RAVI_TNUMINT && e2->ravi_type == RAVI_TNUMINT)
e1->ravi_type = RAVI_TNUMFLT;
else if ((op == OP_IDIV)
&& (e1->ravi_type == RAVI_TNUMINT)
&& (e2->ravi_type == RAVI_TNUMINT))
e1->ravi_type = RAVI_TNUMINT;
else if ((op == OP_BAND || op == OP_BOR || op == OP_BXOR || op == OP_SHL || op == OP_SHR)
&& e1->ravi_type == RAVI_TNUMINT && e2->ravi_type == RAVI_TNUMINT)
e1->ravi_type = RAVI_TNUMINT;
@ -1391,7 +1458,7 @@ static void codecomp (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
** operator that takes one operand - a register location - and
** asserts that the register contains a value of the required type.
*/
static void code_type_assertion(FuncState *fs, UnOpr op, expdesc *e) {
static void code_type_assertion(FuncState *fs, UnOpr op, expdesc *e, TString *usertype) {
luaK_dischargevars(fs, e);
switch (e->k) {
case VKFLT: {
@ -1408,6 +1475,13 @@ static void code_type_assertion(FuncState *fs, UnOpr op, expdesc *e) {
}
break;
}
case VK: {
if (op == OPR_TO_STRING) {
if (e->ravi_type == RAVI_TSTRING)
return;
}
break;
}
case VRELOCABLE:
case VNONRELOC: {
discharge2anyreg(fs, e);
@ -1447,18 +1521,36 @@ static void code_type_assertion(FuncState *fs, UnOpr op, expdesc *e) {
opcode = OP_RAVI_TOARRAYF;
tt = RAVI_TARRAYFLT;
}
else if (op == OPR_TO_TABLE && e->ravi_type != RAVI_TTABLE) {
else if (op == OPR_TO_TABLE && e->ravi_type != RAVI_TTABLE) {
opcode = OP_RAVI_TOTAB;
tt = RAVI_TTABLE;
}
else if (op == OPR_TO_STRING && e->ravi_type != RAVI_TSTRING) {
opcode = OP_RAVI_TOSTRING;
tt = RAVI_TSTRING;
}
else if (op == OPR_TO_CLOSURE && e->ravi_type != RAVI_TFUNCTION) {
opcode = OP_RAVI_TOCLOSURE;
tt = RAVI_TFUNCTION;
}
else if (op == OPR_TO_TYPE) {
opcode = OP_RAVI_TOTYPE;
tt = RAVI_TUSERDATA;
}
else {
/* nothing to do*/
return;
}
/* Must already be NONRELOC */
luaK_codeABC(fs, opcode, e->u.info, 0, 0);
if (opcode == OP_RAVI_TOTYPE) {
luaK_codeABx(fs, opcode, e->u.info, luaK_stringK(fs, usertype));
}
else
luaK_codeABC(fs, opcode, e->u.info, 0, 0);
e->ravi_type = tt;
e->k = VNONRELOC;
if (opcode == OP_RAVI_TOTYPE)
e->usertype = usertype;
return;
}
default: break;
@ -1469,7 +1561,7 @@ static void code_type_assertion(FuncState *fs, UnOpr op, expdesc *e) {
/*
** Apply prefix operation 'op' to expression 'e'.
*/
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line, TString *usertype) {
expdesc ef = {.ravi_type = RAVI_TANY,
.pc = -1,
.t = NO_JUMP,
@ -1485,8 +1577,10 @@ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line);
break;
case OPR_TO_INTEGER: case OPR_TO_NUMBER: case OPR_TO_INTARRAY:
case OPR_TO_NUMARRAY: case OPR_TO_TABLE:
code_type_assertion(fs, op, e); break;
case OPR_TO_NUMARRAY: case OPR_TO_TABLE: case OPR_TO_STRING: case OPR_TO_CLOSURE:
code_type_assertion(fs, op, e, NULL); break;
case OPR_TO_TYPE:
code_type_assertion(fs, op, e, usertype); break;
case OPR_NOT: codenot(fs, e); break;
default: lua_assert(0);
}

@ -548,10 +548,10 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
/* all other instructions can call only through metamethods */
/* Ravi: added GETTABLE_SK and SELF_SK because the call may be through metamethod rather than table */
case OP_SELF: case OP_GETTABUP: case OP_GETTABLE:
case OP_RAVI_SELF_SK: case OP_RAVI_GETTABUP_SK: case OP_RAVI_GETTABLE_SK:
case OP_RAVI_SELF_SK: case OP_RAVI_GETTABUP_SK: case OP_RAVI_GETTABLE_SK: case OP_RAVI_GETTABLE_I:
tm = TM_INDEX;
break;
case OP_SETTABUP: case OP_SETTABLE: case OP_RAVI_SETTABLE_SK:
case OP_SETTABUP: case OP_SETTABLE: case OP_RAVI_SETTABLE_SK: case OP_RAVI_SETTABLE_I:
tm = TM_NEWINDEX;
break;
case OP_ADD: case OP_SUB: case OP_MUL: case OP_MOD:
@ -694,6 +694,7 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
CallInfo *ci = L->ci;
const char *msg;
va_list argp;
luaC_checkGC(L); /* error message uses memory */
va_start(argp, fmt);
msg = luaO_pushvfstring(L, fmt, argp); /* format message */
va_end(argp);

@ -33,6 +33,7 @@
#include "lvm.h"
#include "lzio.h"
#include "ravijit.h"
#include "ravi_jitshared.h"
#define errorstatus(s) ((s) > LUA_YIELD)
@ -376,6 +377,8 @@ static int moveresults (lua_State *L, const TValue *firstResult, StkId res,
*/
int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) {
StkId res;
lua_assert(L->magic == 42);
lua_assert(ci->magic == 42);
int wanted = ci->nresults;
if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
if (L->hookmask & LUA_MASKRET) {
@ -465,8 +468,8 @@ int luaD_precall (lua_State *L, StkId func, int nresults, int op_call) {
callhook(L, ci);
if (L == G(L)->mainthread && p->ravi_jit.jit_status == RAVI_JIT_NOT_COMPILED) {
/* not compiled */
ravi_compile_options_t options = { 0 };
options.verification_level = 1;
ravi_compile_options_t options;
memset(&options, 0, sizeof options);
raviV_compile(L, p, &options);
}
if (L == G(L)->mainthread && p->ravi_jit.jit_function) {
@ -535,6 +538,25 @@ static void stackerror (lua_State *L) {
luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
}
#ifdef RAVI_USE_ASMVM
/* following is a temporary solution to decide whether we can use ASM VM */
extern int ravi_luaV_interp(lua_State * L);
int asvm_compatible(Proto *p) {
static unsigned char opcodes_supported[NUM_OPCODES] = {
[OP_RETURN] = 1,
[OP_LOADK] = 1,
[OP_MOVE] = 1,
[OP_RAVI_FORLOOP_IP] = 1,
[OP_RAVI_FORLOOP_I1] = 1,
[OP_RAVI_FORPREP_I1] = 1,
[OP_RAVI_FORPREP_IP] = 1};
for (int i = 0; i < p->sizecode; i++) {
int op = GET_OPCODE(p->code[i]);
if (!opcodes_supported[op]) return 0;
}
return 1;
}
#endif
/*
** Call a function (C or Lua). The function to be called is at *func.
@ -545,8 +567,23 @@ static void stackerror (lua_State *L) {
void luaD_call (lua_State *L, StkId func, int nResults) {
if (++L->nCcalls >= LUAI_MAXCCALLS)
stackerror(L);
if (!luaD_precall(L, func, nResults, 0)) /* is a Lua function? */
if (!luaD_precall(L, func, nResults, 0)) /* is a Lua function? */ {
#ifdef RAVI_USE_ASMVM
// This is a temporary hack to test the under development ASM VM.
CallInfo *ci = L->ci;
LClosure *cl = clLvalue(ci->func); /* local reference to function's closure */
if (cl->p->sizecode <= 10 &&
asvm_compatible(cl->p)) {
fprintf(stderr, "Invoking ASM VM\n");
ravi_luaV_interp(L);
}
else {
luaV_execute(L); /* call it */
}
#else
luaV_execute(L); /* call it */
#endif
}
L->nCcalls--;
}

@ -162,13 +162,15 @@ static void DumpDebug (const Proto *f, DumpState *D) {
DumpInt(f->locvars[i].startpc, D);
DumpInt(f->locvars[i].endpc, D);
DumpByte(f->locvars[i].ravi_type, D);
DumpString(f->locvars[i].usertype, D);
}
/* n = (D->strip) ? 0 : f->sizeupvalues; */
n = f->sizeupvalues;
DumpInt(n, D);
for (i = 0; i < n; i++) {
DumpString((D->strip) ? NULL : f->upvalues[i].name, D);
DumpByte(f->upvalues[i].type, D);
DumpByte(f->upvalues[i].ravi_type, D);
DumpString(f->upvalues[i].usertype, D);
}
}

@ -145,18 +145,87 @@ static int iscleared (global_State *g, const TValue *o) {
else return iswhite(gcvalue(o));
}
/*
Following description is taken from:
http://wiki.luajit.org/New-Garbage-Collector#gc-algorithms_tri-color-incremental-mark-sweep
Newly allocated objects are white. The mark phase starts at the GC roots.
Marking a reachable object means flipping the color of it from white to
gray and pushing it onto a gray stack (or re-chaining it onto a gray list).
The gray stack is iteratively processed, removing one gray object at a time.
A gray object is traversed and all objects reachable from it are marked,
like above. After an object has been traversed, it's turned from gray to
black. The sweep phase works just like the two-color algorithm above.
This algorithm is incremental: the collector can operate in small steps,
processing only a couple of objects from the gray stack and then let the
mutator run again for a while. This spreads out the GC pauses into
many short intervals, which is important for highly interactive
workloads (e.g. games or internet servers).
But there's one catch: the mutator might get in the way of the collector
and store a reference to a white (unprocessed) object at a black
(processed) object. This object would never be marked and will be
freed by the sweep, even though it's clearly still referenced from a
reachable object, i.e. it should be kept alive.
To avoid this scenario, one has to preserve the tri-color invariant:
a black object may never hold a reference to a white object. This is
done with a write barrier, which has to be checked after every write.
If the invariant has been violated, a fixup step is needed.
There are two alternatives:
1. Either turn the black object gray and push it back onto the gray stack.
This is moving the barrier "back", because the object has to be reprocessed
later on. This is beneficial for container objects, because they usually
receive several stores in succession. This avoids a barrier for the next
objects that are stored into it (which are likely white, too).
2. Or immediately mark the white object, turning it gray and push it onto
the gray stack. This moves the barrier "forward", because it implicitly
drives the GC forward. This works best for objects that only receive
isolated stores.
There are many optimizations to turn this into a practical algorithm.
Here are the most important:
* Stacks should always be kept gray and re-traversed just before the
final sweep phase. This avoids a write barrier for stores to stack slots,
which are the most common kind of stores.
* Objects which have no references to child objects can immediately be
turned from white to black and don't need to go through the gray stack.
* The sweep phase can be made incremental by using two whites and
flipping between them just before entering the sweep phase. Objects with
the 'current' white need to be kept. Only objects with the
'other' white should be freed.
In Lua, Tables use backward barriers, all other traversable objects
use forward barriers.
*/
/*
** barrier that moves collector forward, that is, mark the white object
** being pointed by a black object. (If in sweep phase, clear the black
** object to white [sweep it] to avoid other barrier calls for this
** same object.)
**
** Here we have a black object pointing / referencing a white object
** So to preserve tri-color invariant the white object must
** be marked and turned gray or black. Userdata, strings and upvalues
** are turned black, whereas functions, threads, tables and protos are turned
** gray.
**
** Example: userdata o references user value v, or
** function proto o references newly added constant v
*/
void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
global_State *g = G(L);
lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
if (keepinvariant(g)) /* must keep invariant? */
reallymarkobject(g, v); /* restore invariant */
if (keepinvariant(g)) /* must keep invariant? (not in sweep phase) */
reallymarkobject(g, v); /* restore invariant - turn white object to gray or black */
else { /* sweep phase */
lua_assert(issweepphase(g));
makewhite(g, o); /* mark main obj. as white to avoid other barriers */
@ -167,6 +236,10 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
/*
** barrier that moves collector backward, that is, mark the black object
** pointing to a white object as gray again.
**
** Here we have a container (table) being assigned a value, so the
** table if black must be turned to gray as black objects cannot point
** to white objects.
*/
void luaC_barrierback_ (lua_State *L, Table *t) {
global_State *g = G(L);
@ -228,7 +301,8 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
/*
** mark an object. Userdata, strings, and closed upvalues are visited
** and turned black here. Other objects are marked gray and added
** and turned black here. Other objects (functions, tables, threads, protos)
** are marked gray and added
** to appropriate list to be visited (and turned black) later. (Open
** upvalues are already linked in 'headuv' list.)
*/
@ -485,12 +559,16 @@ static int traverseproto (global_State *g, Proto *f) {
markobjectN(g, f->source);
for (i = 0; i < f->sizek; i++) /* mark literals */
markvalue(g, &f->k[i]);
for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */
for (i = 0; i < f->sizeupvalues; i++) { /* mark upvalue names */
markobjectN(g, f->upvalues[i].name);
markobjectN(g, f->upvalues[i].usertype); /* RAVI change */
}
for (i = 0; i < f->sizep; i++) /* mark nested protos */
markobjectN(g, f->p[i]);
for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */
for (i = 0; i < f->sizelocvars; i++) { /* mark local-variable names */
markobjectN(g, f->locvars[i].varname);
markobjectN(g, f->locvars[i].usertype); /* RAVI change */
}
return sizeof(Proto) + sizeof(Instruction) * f->sizecode +
sizeof(Proto *) * f->sizep +
sizeof(TValue) * f->sizek +

@ -34,6 +34,9 @@
#include "lualib.h"
#include "lauxlib.h"
#if USE_DMR_C
LUAMOD_API int raviopen_dmrcluaapi(lua_State *L);
#endif
/*
** these libs are loaded by lua.c and are readily available to any Lua
@ -54,9 +57,13 @@ static const luaL_Reg loadedlibs[] = {
#ifdef USE_LLVM
{LUA_LLVMLIBNAME, raviopen_llvmluaapi},
#endif
#if USE_DMR_C
{ "dmrc", raviopen_dmrcluaapi },
#endif
#if defined(LUA_COMPAT_BITLIB)
{LUA_BITLIBNAME, luaopen_bit32},
#endif
{LUAJIT_BITLIBNAME, luaopen_bit },
{NULL, NULL}
};

@ -46,7 +46,7 @@ static const char *const luaX_tokens [] = {
"<<", ">>", "::", "<eof>",
"<number>", "<integer>", "<name>", "<string>",
"@integer", "@number", "@integer[]", "@number[]",
"@table"
"@table", "@string", "@closure"
};
@ -459,8 +459,12 @@ static int casttoken(LexState *ls, SemInfo *seminfo) {
/* @table */
else if (strncmp(s, "@table", n) == 0)
tok = TK_TO_TABLE;
else if (strncmp(s, "@string", n) == 0)
tok = TK_TO_STRING;
else if (strncmp(s, "@closure", n) == 0)
tok = TK_TO_CLOSURE;
else {
seminfo->ts = luaX_newstring(ls, s, n);
seminfo->ts = luaX_newstring(ls, s+1, n-1); /* omit @ */
tok = '@';
}
luaZ_buffremove(ls->buff, n); /* rewind but buffer still holds the saved characters */

@ -109,30 +109,35 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
"TOFLT", /* A R(A) := tofloat(R(A)) */
"TOARRAYI", /* A R(A) := to_arrayi(R(A)) */
"TOARRAYF", /* A R(A) := to_arrayf(R(A)) */
"TOTAB", /* A R(A) := to_table(R(A)) */
"TOSTRING",
"TOCLOSURE",
"TOTYPE",
"MOVEI", /* A B R(A) := R(B) */
"MOVEF", /* A B R(A) := R(B) */
"MOVEAI", /* A B R(A) := R(B), check R(B) is array of int */
"MOVEAF", /* A B R(A) := R(B), check R(B) is array of floats */
"MOVETAB", /* A B R(A) := R(B), check R(B) is a table */
"GETTABLE_AI",/* A B C R(A) := R(B)[RK(C)] where R(B) is array of integers and RK(C) is int */
"GETTABLE_AF",/* A B C R(A) := R(B)[RK(C)] where R(B) is array of floats and RK(C) is int */
"SETTABLE_AI",/* A B C R(A)[RK(B)] := RK(C) where RK(B) is an int, R(A) is array of ints, and RK(C) is an int */
"SETTABLE_AF",/* A B C R(A)[RK(B)] := RK(C) where RK(B) is an int, R(A) is array of floats, and RK(C) is an float */
"SETTABLE_AII",/* A B C R(A)[RK(B)] := RK(C) where RK(B) is an int, R(A) is array of ints, and RK(C) is an int */
"SETTABLE_AFF",/* A B C R(A)[RK(B)] := RK(C) where RK(B) is an int, R(A) is array of floats, and RK(C) is an float */
"FORLOOP_IP",
"FORLOOP_I1",
"FORPREP_IP",
"FORPREP_I1",
"SETUPVALI",
"SETUPVALF",
"SETUPVALAI",
"SETUPVALAF",
"SETTABLE_AII",/* A B C R(A)[RK(B)] := RK(C) where RK(B) is an int, R(A) is array of ints, and RK(C) is an int */
"SETTABLE_AFF",/* A B C R(A)[RK(B)] := RK(C) where RK(B) is an int, R(A) is array of floats, and RK(C) is an float */
"SETUPVALI", /* A B UpValue[B] := tointeger(R(A)) */
"SETUPVALF", /* A B UpValue[B] := tonumber(R(A)) */
"SETUPVALAI", /* A B UpValue[B] := toarrayint(R(A)) */
"SETUPVALAF", /* A B UpValue[B] := toarrayflt(R(A)) */
"SETUPVALT", /* A B UpValue[B] := to_table(R(A)) */
"BAND_II",/* A B C R(A) := RK(B) & RK(C) */
"BOR_II", /* A B C R(A) := RK(B) | RK(C) */
@ -148,14 +153,12 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
"LE_II", /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
"LE_FF", /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
"GETTABLE_I", /* A B C R(A) := R(B)[RK(C)], integer key */
"GETTABLE_S", /* A B C R(A) := R(B)[RK(C)], string key */
"SETTABLE_I", /* A B C R(A)[RK(B)] := RK(C), integer key */
"SETTABLE_S", /* A B C R(A)[RK(B)] := RK(C), string key */
"TOTAB", /* A R(A) := to_table(R(A)) */
"MOVETAB", /* A B R(A) := R(B), check R(B) is a table */
"SETUPVALT", /* A B UpValue[B] := to_table(R(A)) */
"SELF_S", /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
"GETTABLE_I", /* A B C R(A) := R(B)[RK(C)], integer key */
"SETTABLE_I", /* A B C R(A)[RK(B)] := RK(C), integer key */
"GETTABLE_SK", /* _SK */ /* A B C R(A) := R(B)[RK(C)], string key */
"SELF_SK", /* _SK*/ /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
"SETTABLE_SK", /*_SK */ /* A B C R(A)[RK(B)] := RK(C), string key */
@ -247,29 +250,36 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
,opmode(0, 1, OpArgN, OpArgN, iABC) /* OP_RAVI_TOFLT A R(A) := tonumber(R(A)) */
,opmode(0, 1, OpArgN, OpArgN, iABC) /* OP_RAVI_TOARRAYI A R(A) := check_array_of_int(R(A)) */
,opmode(0, 1, OpArgN, OpArgN, iABC) /* OP_RAVI_TOARRAYF A R(A) := check_array_of_float(R(A)) */
,opmode(0, 1, OpArgN, OpArgN, iABC) /* OP_RAVI_TOTAB A R(A) := check_table(R(A)) */
,opmode(0, 1, OpArgN, OpArgN, iABC) /* OP_RAVI_TOSTRING */
,opmode(0, 1, OpArgN, OpArgN, iABC) /* OP_RAVI_TOCLOSURE */
,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_RAVI_TOTYPE */
,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_RAVI_MOVEI A B R(A) := tointeger(R(B)) */
,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_RAVI_MOVEF A B R(A) := tonumber(R(B)) */
,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_RAVI_MOVEAI A B R(A) := R(B), check R(B) is array of int */
,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_RAVI_MOVEAF A B R(A) := R(B), check R(B) is array of floats */
,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_RAVI_MOVETAB A B R(A) := R(B), check R(B) is a table */
,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_RAVI_GETTABLE_AI A B C R(A) := R(B)[RK(C)] where R(B) is array of integers and RK(C) is int */
,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_RAVI_GETTABLE_AF A B C R(A) := R(B)[RK(C)] where R(B) is array of floats and RK(C) is int */
,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_RAVI_SETTABLE_AI A B C R(A)[RK(B)] := RK(C) where RK(B) is an int, R(A) is array of ints, and RK(C) is an int */
,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_RAVI_SETTABLE_AF A B C R(A)[RK(B)] := RK(C) where RK(B) is an int, R(A) is array of floats, and RK(C) is an float */
,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_RAVI_SETTABLE_AII A B C R(A)[RK(B)] := RK(C) where RK(B) is an int, R(A) is array of ints, and RK(C) is an int */
,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_RAVI_SETTABLE_AFF A B C R(A)[RK(B)] := RK(C) where RK(B) is an int, R(A) is array of floats, and RK(C) is an float */
,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_RAVI_FORLOOP_IP */
,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_RAVI_FORLOOP_I1 */
,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_RAVI_FORPREP_IP */
,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_RAVI_FORPREP_I1 */
,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RAVI_SETUPVALI */
,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RAVI_SETUPVALF */
,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RAVI_SETUPVALAI */
,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RAVI_SETUPVALAF */
,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RAVI_SETUPVALT */
,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_RAVI_SETTABLE_AII A B C R(A)[RK(B)] := RK(C) where RK(B) is an int, R(A) is array of ints, and RK(C) is an int */
,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_RAVI_SETTABLE_AFF A B C R(A)[RK(B)] := RK(C) where RK(B) is an int, R(A) is array of floats, and RK(C) is an float */
,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_RAVI_BAND_II */
,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_RAVI_BOR_II */
,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_RAVI_BXOR_II */
@ -284,19 +294,16 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_RAVI_LE_II */
,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_RAVI_LE_FF */
,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_RAVI_GETTABLE_I */
,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_RAVI_GETTABLE_S */
,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_RAVI_SETTABLE_I */
,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_RAVI_SETTABLE_S */
,opmode(0, 1, OpArgN, OpArgN, iABC) /* OP_RAVI_TOTAB A R(A) := check_table(R(A)) */
,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_RAVI_MOVETAB A B R(A) := R(B), check R(B) is a table */
,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RAVI_SETUPVALT */
,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_RAVI_SELF_S */
,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_RAVI_GETTABLE_I */
,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_RAVI_SETTABLE_I */
,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_RAVI_GETTABLE_SK */
,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_RAVI_SELF_SK */
,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_RAVI_SETTABLE_SK */
,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_RAVI_GETTABUP_SK */
,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_RAVI_GETTABUP_SK */
};
@ -631,19 +638,7 @@ static char *buildop2(Proto *p, int pc, char *buff, size_t len) {
int line = getfuncline(p, pc);
char tbuf[100];
raviP_instruction_to_str(tbuf, sizeof tbuf, p->code[pc]);
/* This is a temporary hack to output old opcode names to prevent tests from breaking */
if (strncmp(tbuf, luaP_opnames[OP_RAVI_GETTABLE_SK], strlen(luaP_opnames[OP_RAVI_GETTABLE_SK])) == 0 ||
strncmp(tbuf, luaP_opnames[OP_RAVI_SELF_SK], strlen(luaP_opnames[OP_RAVI_SELF_SK])) == 0 ||
strncmp(tbuf, luaP_opnames[OP_RAVI_GETTABUP_SK], strlen(luaP_opnames[OP_RAVI_GETTABUP_SK])) == 0 ||
strncmp(tbuf, luaP_opnames[OP_RAVI_SETTABLE_SK], strlen(luaP_opnames[OP_RAVI_SETTABLE_SK])) == 0) {
char *cp = strstr(tbuf, "_SK ");
if (cp != NULL) {
cp[0] = ' ';
cp[1] = ' ';
cp[2] = ' ';
}
}
snprintf(buff, len, "(%4d) %4d - %s", line, pc, tbuf);
snprintf(buff, len, "(%4d) %4d - %s", line, pc, tbuf);
return buff;
}

@ -122,7 +122,7 @@ static void print_expdesc(FILE *fp, FuncState *fs, const expdesc *e) {
break;
case VNONRELOC:
fprintf(fp, "{p=%p, k=VNONRELOC, register=%d %s, type=%s, pc=%d}", e, e->u.info,
raviY_typename(raviY_get_register_typeinfo(fs, e->u.info)),
raviY_typename(raviY_get_register_typeinfo(fs, e->u.info, NULL)),
raviY_typename(e->ravi_type),
e->pc);
break;
@ -158,7 +158,7 @@ static void print_expdesc(FILE *fp, FuncState *fs, const expdesc *e) {
fprintf(
fp, "{p=%p, k=VCALL, pc=%d, instruction=(%s %s), type=%s}", e,
e->u.info, raviP_instruction_to_str(buf, sizeof buf, getinstruction(fs, e)),
raviY_typename(raviY_get_register_typeinfo(fs, GETARG_A(getinstruction(fs, e)))),
raviY_typename(raviY_get_register_typeinfo(fs, GETARG_A(getinstruction(fs, e)), NULL)),
raviY_typename(e->ravi_type));
break;
case VVARARG:
@ -312,20 +312,22 @@ static TString *str_checkname (LexState *ls) {
* expression kind in e->k, e->u.info may have a register
* or bytecode
*/
static void init_exp (expdesc *e, expkind k, int info, ravitype_t tt) {
static void init_exp (expdesc *e, expkind k, int info, ravitype_t tt, TString *usertype) {
e->f = e->t = NO_JUMP;
e->k = k;
e->u.info = info;
/* RAVI change; added type */
e->ravi_type = tt;
e->usertype = usertype;
e->pc = -1;
e->u.ind.usertype = NULL; /* Just for safey */
}
/* create a string constant expression, constant's location stored in
* e->u.info, e->ravi_type = RAVI_TSTRING, e->k = VK
*/
static void codestring (LexState *ls, expdesc *e, TString *s) {
init_exp(e, VK, luaK_stringK(ls->fs, s), RAVI_TSTRING);
init_exp(e, VK, luaK_stringK(ls->fs, s), RAVI_TSTRING, NULL);
}
/* verify that current token is a string, create a string constant
@ -340,7 +342,7 @@ static void checkname (LexState *ls, expdesc *e) {
* variable's index in ls->f->locvars.
* RAVI change - added the type of the variable.
*/
static int registerlocalvar (LexState *ls, TString *varname, int ravi_type) {
static int registerlocalvar (LexState *ls, TString *varname, unsigned int ravi_type, TString *usertype) {
FuncState *fs = ls->fs;
Proto *f = fs->f;
int oldsize = f->sizelocvars;
@ -351,22 +353,27 @@ static int registerlocalvar (LexState *ls, TString *varname, int ravi_type) {
f->locvars[oldsize].startpc = -1;
f->locvars[oldsize].endpc = -1;
f->locvars[oldsize].ravi_type = RAVI_TANY;
f->locvars[oldsize].usertype = NULL;
f->locvars[oldsize++].varname = NULL;
}
f->locvars[fs->nlocvars].varname = varname;
f->locvars[fs->nlocvars].ravi_type = ravi_type;
if (ravi_type == RAVI_TUSERDATA && usertype != NULL) {
// Store a reference to the usertype name
f->locvars[fs->nlocvars].usertype = usertype;
}
luaC_objbarrier(ls->L, f, varname);
return fs->nlocvars++;
}
/* create a new local variable in function scope, and set the
* variable type (RAVI - added type tt) */
static void new_localvar (LexState *ls, TString *name, ravitype_t tt) {
static void new_localvar (LexState *ls, TString *name, ravitype_t tt, TString *usertype) {
FuncState *fs = ls->fs;
Dyndata *dyd = ls->dyd;
/* register variable and get its index */
/* RAVI change - record type info for local variable */
int reg = registerlocalvar(ls, name, tt);
int reg = registerlocalvar(ls, name, tt, usertype);
checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,
MAXVARS, "local variables");
luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1,
@ -382,7 +389,7 @@ static void new_localvar (LexState *ls, TString *name, ravitype_t tt) {
*/
static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) {
/* RAVI change - add type */
new_localvar(ls, luaX_newstring(ls, name, sz), RAVI_TANY);
new_localvar(ls, luaX_newstring(ls, name, sz), RAVI_TANY, NULL);
}
/* create a new local variable
@ -419,7 +426,7 @@ static int register_to_locvar_index(FuncState *fs, int reg) {
* return the type associated with the variable.
* This is a RAVI function
*/
ravitype_t raviY_get_register_typeinfo(FuncState *fs, int reg) {
ravitype_t raviY_get_register_typeinfo(FuncState *fs, int reg, TString **pusertype) {
int idx;
LocVar *v;
/* Due to the way Lua parser works it is not safe to look beyond nactvar */
@ -431,6 +438,8 @@ ravitype_t raviY_get_register_typeinfo(FuncState *fs, int reg) {
idx = fs->ls->dyd->actvar.arr[fs->firstlocal + reg].idx;
lua_assert(idx < fs->nlocvars);
v = &fs->f->locvars[idx];
if (pusertype != NULL)
*pusertype = v->usertype;
/* Variable in scope so return the type if we know it */
return v->ravi_type;
}
@ -479,12 +488,15 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,
Upvaldesc, MAXUPVAL, "upvalues");
while (oldsize < f->sizeupvalues)
f->upvalues[oldsize++].name = NULL;
while (oldsize < f->sizeupvalues) {
f->upvalues[oldsize].name = NULL;
f->upvalues[oldsize++].usertype = NULL;
}
f->upvalues[fs->nups].instack = (v->k == VLOCAL);
f->upvalues[fs->nups].idx = cast_byte(v->u.info);
f->upvalues[fs->nups].name = name;
f->upvalues[fs->nups].type = v->ravi_type;
f->upvalues[fs->nups].ravi_type = v->ravi_type;
f->upvalues[fs->nups].usertype = v->usertype;
luaC_objbarrier(fs->ls->L, f, name);
return fs->nups++;
}
@ -520,13 +532,14 @@ static void markupval (FuncState *fs, int level) {
*/
static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
if (fs == NULL) /* no more levels? */
init_exp(var, VVOID, 0, RAVI_TANY); /* default is global */
init_exp(var, VVOID, 0, RAVI_TANY, NULL); /* default is global */
else {
int v = searchvar(fs, n); /* look up locals at current level */
if (v >= 0) { /* found? */
/* RAVI set type of local var / expr if possible */
ravitype_t tt = raviY_get_register_typeinfo(fs, v);
init_exp(var, VLOCAL, v, tt); /* variable is local, RAVI set type */
TString *usertype = NULL;
ravitype_t tt = raviY_get_register_typeinfo(fs, v, &usertype);
init_exp(var, VLOCAL, v, tt, usertype); /* variable is local, RAVI set type */
if (!base)
markupval(fs, v); /* local will be used as an upval */
}
@ -539,7 +552,7 @@ static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
/* else was LOCAL or UPVAL */
idx = newupvalue(fs, n, var); /* will be a new upvalue */
}
init_exp(var, VUPVAL, idx, fs->f->upvalues[idx].type); /* RAVI : set upvalue type */
init_exp(var, VUPVAL, idx, fs->f->upvalues[idx].ravi_type, fs->f->upvalues[idx].usertype); /* RAVI : set upvalue type */
}
}
}
@ -563,7 +576,7 @@ static void singlevar (LexState *ls, expdesc *var) {
/* RAVI code an instruction to coerce the type, reg is the register,
and ravi_type is the type we want */
static void ravi_code_typecoersion(LexState *ls, int reg, ravitype_t ravi_type) {
static void ravi_code_typecoersion(LexState *ls, int reg, ravitype_t ravi_type, TString *typename /* only if tt is USERDATA */) {
/* do we need to convert ? */
if (ravi_type == RAVI_TNUMFLT || ravi_type == RAVI_TNUMINT)
/* code an instruction to convert in place */
@ -577,14 +590,23 @@ static void ravi_code_typecoersion(LexState *ls, int reg, ravitype_t ravi_type)
else if (ravi_type == RAVI_TTABLE)
luaK_codeABC(ls->fs, OP_RAVI_TOTAB,
reg, 0, 0);
// TODO handle string, function, userdata, boolean types
else if (ravi_type == RAVI_TUSERDATA)
luaK_codeABx(ls->fs, OP_RAVI_TOTYPE,
reg, luaK_stringK(ls->fs, typename));
else if (ravi_type == RAVI_TSTRING)
luaK_codeABC(ls->fs, OP_RAVI_TOSTRING,
reg, 0, 0);
else if (ravi_type == RAVI_TFUNCTION)
luaK_codeABC(ls->fs, OP_RAVI_TOCLOSURE,
reg, 0, 0);
}
/* RAVI code an instruction to initialize a scalar typed value
For array and table types however raise an error as uninitialized value
would cause a null pointer and therefore memory fault
*/
static void ravi_code_setzero(FuncState *fs, int reg, ravitype_t ravi_type) {
static void ravi_code_setzero(FuncState *fs, int reg, ravitype_t ravi_type, TString *usertype) {
(void) usertype;
if (ravi_type == RAVI_TNUMFLT || ravi_type == RAVI_TNUMINT)
/* code an instruction to convert in place */
luaK_codeABC(fs, ravi_type == RAVI_TNUMFLT ? OP_RAVI_LOADFZ : OP_RAVI_LOADIZ, reg, 0, 0);
@ -624,8 +646,9 @@ static void ravi_coercetype(LexState *ls, expdesc *v, int n)
*/
int idx = register_to_locvar_index(ls->fs, i);
ravitype_t ravi_type = ls->fs->f->locvars[idx].ravi_type; /* get variable's type */
TString *usertype = ls->fs->f->locvars[idx].usertype;
/* do we need to convert ? */
ravi_code_typecoersion(ls, i, ravi_type);
ravi_code_typecoersion(ls, i, ravi_type, usertype);
}
}
@ -640,8 +663,9 @@ static void ravi_setzero(FuncState *fs, int from, int n) {
*/
int idx = register_to_locvar_index(fs, i);
ravitype_t ravi_type = fs->f->locvars[idx].ravi_type; /* get variable's type */
TString *usertype = fs->f->locvars[idx].usertype;
/* do we need to convert ? */
ravi_code_setzero(fs, i, ravi_type);
ravi_code_setzero(fs, i, ravi_type, usertype);
}
}
@ -897,7 +921,7 @@ static Proto *addprototype (LexState *ls) {
*/
static void codeclosure (LexState *ls, expdesc *v) {
FuncState *fs = ls->fs->prev;
init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1), RAVI_TFUNCTION);
init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1), RAVI_TFUNCTION, NULL);
luaK_exp2nextreg(fs, v); /* fix it at the last register */
DEBUG_VARS(raviY_printf(ls->fs, "codeclosure -> closure created %e\n", v));
}
@ -1109,9 +1133,9 @@ static void constructor (LexState *ls, expdesc *t) {
struct ConsControl cc;
cc.na = cc.nh = cc.tostore = 0;
cc.t = t;
init_exp(t, VRELOCABLE, pc, RAVI_TTABLE); /* RAVI TODO - set table of type */
t->pc = pc; /* RAVI save pc of OP_NEWTABLE instruction */
init_exp(&cc.v, VVOID, 0, RAVI_TANY); /* no value (yet) */
init_exp(t, VRELOCABLE, pc, RAVI_TTABLE, NULL); /* RAVI initial type may be modified */
t->pc = pc; /* RAVI save pc of OP_NEWTABLE instruction so that the correct type can be set later */
init_exp(&cc.v, VVOID, 0, RAVI_TANY, NULL); /* no value (yet) */
luaK_exp2nextreg(ls->fs, t); /* fix it at stack top */
checknext(ls, '{');
do {
@ -1129,12 +1153,48 @@ static void constructor (LexState *ls, expdesc *t) {
/* }====================================================================== */
/*
* We would like to allow user defined types to contain the sequence
* NAME [. NAME]+
* The initial NAME is supplied.
* Returns extended name.
* Note that the returned string will be anchored in the Lexer and must
* be anchored somewhere else by the time parsing finishes
*/
static TString *user_defined_type_name(LexState *ls, TString *typename) {
char buffer[128];
size_t len = 0;
if (testnext(ls, '.')) {
char buffer[128] = { 0 };
const char *str = getstr(typename);
len = strlen(str);
if (len >= sizeof buffer) {
luaX_syntaxerror(ls, "User defined type name is too long");
return typename;
}
snprintf(buffer, sizeof buffer, "%s", str);
do {
typename = str_checkname(ls);
str = getstr(typename);
size_t newlen = len + strlen(str) + 1;
if (newlen >= sizeof buffer) {
luaX_syntaxerror(ls, "User defined type name is too long");
return typename;
}
snprintf(buffer + len, sizeof buffer - len, ".%s", str);
len = newlen;
} while (testnext(ls, '.'));
typename = luaX_newstring(ls, buffer, strlen(buffer));
}
return typename;
}
/* RAVI Parse
* name : type
* where type is 'integer', 'integer[]',
* 'number', 'number[]'
*/
static ravitype_t declare_localvar(LexState *ls) {
static ravitype_t declare_localvar(LexState *ls, TString **pusertype) {
/* RAVI change - add type */
TString *name = str_checkname(ls);
/* assume a dynamic type */
@ -1142,6 +1202,7 @@ static ravitype_t declare_localvar(LexState *ls) {
/* if the variable name is followed by a colon then we have a type
* specifier
*/
if (testnext(ls, ':')) {
TString *typename = str_checkname(ls); /* we expect a type name */
const char *str = getstr(typename);
@ -1154,14 +1215,21 @@ static ravitype_t declare_localvar(LexState *ls) {
tt = RAVI_TNUMFLT;
else if (strcmp(str, "closure") == 0)
tt = RAVI_TFUNCTION;
else if (strcmp(str, "userdata") == 0)
tt = RAVI_TUSERDATA;
else if (strcmp(str, "table") == 0)
tt = RAVI_TTABLE;
else if (strcmp(str, "string") == 0)
tt = RAVI_TSTRING;
else if (strcmp(str, "boolean") == 0)
tt = RAVI_TBOOLEAN;
else if (strcmp(str, "any") == 0)
tt = RAVI_TANY;
else {
/* default is a userdata type */
tt = RAVI_TUSERDATA;
typename = user_defined_type_name(ls, typename);
str = getstr(typename);
*pusertype = typename;
}
if (tt == RAVI_TNUMFLT || tt == RAVI_TNUMINT) {
/* if we see [] then it is an array type */
if (testnext(ls, '[')) {
@ -1170,7 +1238,7 @@ static ravitype_t declare_localvar(LexState *ls) {
}
}
}
new_localvar(ls, name, tt);
new_localvar(ls, name, tt, *pusertype);
return tt;
}
@ -1179,13 +1247,16 @@ static void parlist (LexState *ls) {
FuncState *fs = ls->fs;
Proto *f = fs->f;
int nparams = 0;
enum { N = MAXVARS + 10 };
int vars[N] = { 0 };
TString *typenames[N] = { NULL };
f->is_vararg = 0;
if (ls->t.token != ')') { /* is 'parlist' not empty? */
do {
switch (ls->t.token) {
case TK_NAME: { /* param -> NAME */
/* RAVI change - add type */
declare_localvar(ls);
vars[nparams] = declare_localvar(ls, &typenames[nparams]);
nparams++;
break;
}
@ -1202,10 +1273,13 @@ static void parlist (LexState *ls) {
f->numparams = cast_byte(fs->nactvar);
luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */
for (int i = 0; i < f->numparams; i++) {
ravitype_t tt = raviY_get_register_typeinfo(fs, i);
TString *usertype = NULL;
ravitype_t tt = raviY_get_register_typeinfo(fs, i, &usertype);
lua_assert(i < nparams && vars[i] == tt || 1);
lua_assert(i < nparams && usertype == typenames[i] || 1);
DEBUG_VARS(raviY_printf(fs, "Parameter [%d] = %v\n", i + 1, getlocvar(fs, i)));
/* do we need to convert ? */
ravi_code_typecoersion(ls, i, tt);
ravi_code_typecoersion(ls, i, tt, usertype);
}
}
@ -1244,75 +1318,61 @@ static int explist (LexState *ls, expdesc *v) {
return n;
}
/* TODO instead of using vars here could we just rely upon register_typeinfo? */
static void ravi_typecheck(LexState *ls, expdesc *v, int *vars, int nvars,
int n) {
ravitype_t vartype = vars[n];
/* check that the type of expression 'v' matches the type
* expected in var_types[] array where 'n' is the variable we are
* checking. The arrays 'var_types' and 'usertypes' are needed as
* 'v' may be a function call returning multiple values, in which case
* we need to check all returned values against the expected types.
*/
static void ravi_typecheck(LexState *ls, expdesc *v, int *var_types,
TString **usertypes, int nvars, int n) {
/* NOTE that 'v' may not have register assigned yet */
ravitype_t vartype = var_types[n];
if (n < nvars && vartype != RAVI_TANY && v->ravi_type != vartype) {
if (v->ravi_type != vartype &&
(vartype == RAVI_TARRAYFLT || vartype == RAVI_TARRAYINT) &&
v->k == VNONRELOC) {
#if 0
/* as the bytecode for generating a table is already emitted by this stage
* we have to amend the generated byte code - not sure if there is a
* better approach. We look for the last bytecode that is OP_NEWTABLE
* and that has the same destination register as v->u.info which is our
* variable
* local a:int[] = { 1 }
* ^ We are just past this and
* about to assign to a
*/
int i = ls->fs->pc - 1;
for (; i >= 0; i--) {
Instruction *pc = &ls->fs->f->code[i];
OpCode op = GET_OPCODE(*pc);
int reg;
if (op != OP_NEWTABLE)
continue;
reg = GETARG_A(*pc);
if (reg != v->u.info)
continue;
op =
(vartype == RAVI_TARRAYINT) ? OP_RAVI_NEWARRAYI : OP_RAVI_NEWARRAYF;
lua_assert(v->pc == i);
SET_OPCODE(*pc, op); /* modify opcode */
DEBUG_CODEGEN(
raviY_printf(ls->fs, "[%d]* %o ; modify opcode\n", i, *pc));
break;
}
if (i < 0)
luaX_syntaxerror(ls, "expecting array initializer");
#else
* better approach. The location of the OP_NEWTABLE instruction is in
* v->pc and we check that this has the same destination register as
* v->u.info which is our variable */
// local a:int[] = { 1 }
// ^ We are just past this
// and about to assign to a
int ok = 0;
if (v->pc >= 0) {
Instruction *pc = &ls->fs->f->code[v->pc];
Instruction *pc =
&ls->fs->f->code[v->pc]; /* Get the OP_NEWTABLE instruction */
OpCode op = GET_OPCODE(*pc);
if (op == OP_NEWTABLE) {
if (op == OP_NEWTABLE) { /* check before making changes */
int reg = GETARG_A(*pc);
if (reg == v->u.info) {
op = (vartype == RAVI_TARRAYINT) ? OP_RAVI_NEWARRAYI : OP_RAVI_NEWARRAYF;
if (reg ==
v->u.info) { /* double check that register is as expected */
op = (vartype == RAVI_TARRAYINT) ? OP_RAVI_NEWARRAYI
: OP_RAVI_NEWARRAYF;
SET_OPCODE(*pc, op); /* modify opcode */
DEBUG_CODEGEN(
raviY_printf(ls->fs, "[%d]* %o ; modify opcode\n", v->pc, *pc));
raviY_printf(ls->fs, "[%d]* %o ; modify opcode\n", v->pc, *pc));
ok = 1;
}
}
}
if (!ok)
if (!ok)
luaX_syntaxerror(ls, "expecting array initializer");
#endif
}
/* if we are calling a function then convert return types */
else if (v->ravi_type != vartype &&
(vartype == RAVI_TNUMFLT || vartype == RAVI_TNUMINT ||
vartype == RAVI_TARRAYFLT || vartype == RAVI_TARRAYINT ||
vartype == RAVI_TTABLE) &&
vartype == RAVI_TTABLE || vartype == RAVI_TSTRING ||
vartype == RAVI_TFUNCTION || vartype == RAVI_TUSERDATA) &&
v->k == VCALL) {
/* For local variable declarations that call functions e.g.
* local i = func()
* Lua ensures that the function returns values to register assigned to
* variable i and above so that no separate OP_MOVE instruction is
* necessary. So that means that we need to coerce the return values
* variable i and above so that no separate OP_MOVE instruction is
* necessary. So that means that we need to coerce the return values
* in situ.
*/
Instruction *pc =
@ -1331,13 +1391,27 @@ static void ravi_typecheck(LexState *ls, expdesc *v, int *vars, int nvars,
int i;
for (i = n; i < (n + nrets); i++)
/* do we need to convert ? */
ravi_code_typecoersion(ls, a + (i - n), vars[i]);
} else if ((vartype == RAVI_TNUMFLT || vartype == RAVI_TNUMINT) &&
v->k == VINDEXED) {
ravi_code_typecoersion(ls, a + (i - n), var_types[i], NULL);
}
else if ((vartype == RAVI_TNUMFLT || vartype == RAVI_TNUMINT) &&
v->k == VINDEXED) {
if ((vartype == RAVI_TNUMFLT && v->ravi_type != RAVI_TARRAYFLT) ||
(vartype == RAVI_TNUMINT && v->ravi_type != RAVI_TARRAYINT))
luaX_syntaxerror(ls, "Invalid local assignment");
} else {
}
else if ((vartype == RAVI_TSTRING && v->ravi_type != RAVI_TSTRING) ||
(vartype == RAVI_TFUNCTION && v->ravi_type != RAVI_TFUNCTION) ||
vartype == RAVI_TUSERDATA) {
TString *usertype = usertypes[n]; // NULL if var_types[n] is not userdata
/* we need to make sure that a register is assigned to 'v'
so that we can emit type assertion instructions. This would have
normally happened in the calling function but we do it early here -
possibly missing some optimization opportunity (i.e. avoiding register
assignment) */
luaK_exp2nextreg(ls->fs, v);
ravi_code_typecoersion(ls, v->u.info, vartype, usertype);
}
else {
luaX_syntaxerror(ls, "Invalid local assignment");
}
}
@ -1347,15 +1421,15 @@ static void ravi_typecheck(LexState *ls, expdesc *v, int *vars, int nvars,
* types provided in vars array. This is a modified version of explist() to be
* used to local variable declaration statement only.
*/
static int localvar_explist(LexState *ls, expdesc *v, int *vars, int nvars) {
static int localvar_explist(LexState *ls, expdesc *v, int *vars, TString** usertypes, int nvars) {
/* explist -> expr { ',' expr } */
int n = 1; /* at least one expression */
expr(ls, v);
ravi_typecheck(ls, v, vars, nvars, 0);
ravi_typecheck(ls, v, vars, usertypes, nvars, 0);
while (testnext(ls, ',')) {
luaK_exp2nextreg(ls->fs, v);
expr(ls, v);
ravi_typecheck(ls, v, vars, nvars, n);
ravi_typecheck(ls, v, vars, usertypes, nvars, n);
n++;
}
return n;
@ -1400,7 +1474,7 @@ static void funcargs (LexState *ls, expdesc *f, int line) {
luaK_exp2nextreg(fs, &args); /* close last argument */
nparams = fs->freereg - (base+1);
}
init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams + 1, 2), RAVI_TANY); /* RAVI TODO return value from function call not known */
init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams + 1, 2), RAVI_TANY, NULL); /* RAVI TODO return value from function call not known */
luaK_fixline(fs, line);
fs->freereg = base+1; /* call remove function and arguments and leaves
(unless changed) one result */
@ -1481,12 +1555,12 @@ static void simpleexp (LexState *ls, expdesc *v) {
constructor | FUNCTION body | suffixedexp */
switch (ls->t.token) {
case TK_FLT: {
init_exp(v, VKFLT, 0, RAVI_TNUMFLT);
init_exp(v, VKFLT, 0, RAVI_TNUMFLT, NULL);
v->u.nval = ls->t.seminfo.r;
break;
}
case TK_INT: {
init_exp(v, VKINT, 0, RAVI_TNUMINT);
init_exp(v, VKINT, 0, RAVI_TNUMINT, NULL);
v->u.ival = ls->t.seminfo.i;
break;
}
@ -1495,22 +1569,22 @@ static void simpleexp (LexState *ls, expdesc *v) {
break;
}
case TK_NIL: {
init_exp(v, VNIL, 0, RAVI_TNIL);
init_exp(v, VNIL, 0, RAVI_TNIL, NULL);
break;
}
case TK_TRUE: {
init_exp(v, VTRUE, 0, RAVI_TANY); /* RAVI TODO */
init_exp(v, VTRUE, 0, RAVI_TANY, NULL); /* RAVI TODO */
break;
}
case TK_FALSE: {
init_exp(v, VFALSE, 0, RAVI_TANY); /* RAVI TODO */
init_exp(v, VFALSE, 0, RAVI_TANY, NULL); /* RAVI TODO */
break;
}
case TK_DOTS: { /* vararg */
FuncState *fs = ls->fs;
check_condition(ls, fs->f->is_vararg,
"cannot use '...' outside a vararg function");
init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0), RAVI_TANY);
init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0), RAVI_TANY, NULL);
break;
}
case '{': { /* constructor */
@ -1542,6 +1616,9 @@ static UnOpr getunopr (int op) {
case TK_TO_INTARRAY: return OPR_TO_INTARRAY;
case TK_TO_NUMARRAY: return OPR_TO_NUMARRAY;
case TK_TO_TABLE: return OPR_TO_TABLE;
case TK_TO_STRING: return OPR_TO_STRING;
case TK_TO_CLOSURE: return OPR_TO_CLOSURE;
case '@': return OPR_TO_TYPE;
default: return OPR_NOUNOPR;
}
}
@ -1605,9 +1682,19 @@ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) {
uop = getunopr(ls->t.token);
if (uop != OPR_NOUNOPR) {
int line = ls->linenumber;
luaX_next(ls);
// RAVI change - get usertype if @<name>
TString *usertype = NULL;
if (uop == OPR_TO_TYPE) {
usertype = ls->t.seminfo.ts;
luaX_next(ls);
// Check and expand to extended name if necessary
usertype = user_defined_type_name(ls, usertype);
}
else {
luaX_next(ls);
}
subexpr(ls, v, UNARY_PRIORITY);
luaK_prefix(ls->fs, uop, v, line);
luaK_prefix(ls->fs, uop, v, line, usertype);
}
else {
simpleexp(ls, v);
@ -1721,9 +1808,9 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
expdesc e = {.ravi_type = RAVI_TANY, .pc = -1};
check_condition(ls, vkisvar(lh->v.k), "syntax error");
if (testnext(ls, ',')) { /* assignment -> ',' suffixedexp assignment */
struct LHS_assign nv;
nv.v.ravi_type = RAVI_TANY;
nv.v.pc = -1;
struct LHS_assign nv = { .v.ravi_type = RAVI_TANY, .v.pc = -1 };
//nv.v.ravi_type = RAVI_TANY;
//nv.v.pc = -1;
nv.prev = lh;
suffixedexp(ls, &nv.v);
DEBUG_EXPR(raviY_printf(ls->fs, "assignment -> suffixedexp %e\n", &nv.v));
@ -1748,7 +1835,7 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
return; /* avoid default */
}
}
init_exp(&e, VNONRELOC, ls->fs->freereg-1, RAVI_TANY); /* default assignment */
init_exp(&e, VNONRELOC, ls->fs->freereg-1, RAVI_TANY, NULL); /* default assignment */
luaK_storevar(ls->fs, &lh->v, &e);
DEBUG_EXPR(raviY_printf(ls->fs, "assignment lhs = %e, rhs = %e\n", &lh->v, &e));
}
@ -1879,6 +1966,9 @@ static int exp1 (LexState *ls, Fornuminfo *info) {
*/
expdesc e = {.ravi_type = RAVI_TANY, .pc = -1};
int reg;
int expect_int = 0;
if (ls->t.token == '#')
expect_int = 1;
expr(ls, &e);
DEBUG_EXPR(raviY_printf(ls->fs, "fornum exp -> %e\n", &e));
info->is_constant = (e.k == VKINT);
@ -1886,7 +1976,13 @@ static int exp1 (LexState *ls, Fornuminfo *info) {
luaK_exp2nextreg(ls->fs, &e);
lua_assert(e.k == VNONRELOC);
reg = e.u.info;
info->type = e.ravi_type;
if (expect_int && e.ravi_type != RAVI_TNUMINT) {
luaK_codeABC(ls->fs, OP_RAVI_TOINT, reg, 0, 0);
info->type = RAVI_TNUMINT;
}
else {
info->type = e.ravi_type;
}
return reg;
}
@ -1940,7 +2036,7 @@ static void fornum (LexState *ls, TString *varname, int line) {
new_localvarliteral(ls, "(for index)");
new_localvarliteral(ls, "(for limit)");
new_localvarliteral(ls, "(for step)");
new_localvar(ls, varname, RAVI_TANY);
new_localvar(ls, varname, RAVI_TANY, NULL);
/* The fornum sets up its own variables as above.
These are expected to hold numeric values - but from Ravi's
point of view we need to know if the variable is an integer or
@ -2000,9 +2096,9 @@ static void forlist (LexState *ls, TString *indexname) {
new_localvarliteral(ls, "(for state)");
new_localvarliteral(ls, "(for control)");
/* create declared variables */
new_localvar(ls, indexname, RAVI_TANY); /* RAVI TODO for name:type syntax? */
new_localvar(ls, indexname, RAVI_TANY, NULL); /* RAVI TODO for name:type syntax? */
while (testnext(ls, ',')) {
new_localvar(ls, str_checkname(ls), RAVI_TANY); /* RAVI change - add type */
new_localvar(ls, str_checkname(ls), RAVI_TANY, NULL); /* RAVI change - add type */
nvars++;
}
checknext(ls, TK_IN);
@ -2086,7 +2182,7 @@ static void localfunc (LexState *ls) {
expdesc b = {.ravi_type = RAVI_TANY, .pc = -1};
FuncState *fs = ls->fs;
/* RAVI change - add type */
new_localvar(ls, str_checkname(ls), RAVI_TFUNCTION); /* new local variable */
new_localvar(ls, str_checkname(ls), RAVI_TFUNCTION, NULL); /* new local variable */
adjustlocalvars(ls, 1); /* enter its scope */
body(ls, &b, 0, ls->linenumber); /* function created in next register */
/* debug information will only see the variable after this point! */
@ -2106,17 +2202,18 @@ static void localstat (LexState *ls) {
*/
enum { N = MAXVARS + 10 };
int vars[N] = { 0 };
TString *usertypes[N] = { NULL };
do {
/* RAVI changes start */
/* local name : type = value */
vars[nvars] = declare_localvar(ls);
vars[nvars] = declare_localvar(ls, &usertypes[nvars]);
/* RAVI changes end */
nvars++;
if (nvars >= N)
luaX_syntaxerror(ls, "too many local variables");
} while (testnext(ls, ','));
if (testnext(ls, '='))
nexps = localvar_explist(ls, &e, vars, nvars);
nexps = localvar_explist(ls, &e, vars, usertypes, nvars);
else {
e.k = VVOID;
nexps = 0;
@ -2286,7 +2383,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
expdesc v = {.ravi_type = RAVI_TANY, .pc = -1};
open_func(ls, fs, &bl);
fs->f->is_vararg = 1; /* main function is always declared vararg */
init_exp(&v, VLOCAL, 0, RAVI_TANY); /* create and... - RAVI TODO var arg is unknown type */
init_exp(&v, VLOCAL, 0, RAVI_TANY, NULL); /* create and... - RAVI TODO var arg is unknown type */
newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */
luaX_next(ls); /* read first token */
statlist(ls); /* parse main body */

@ -28,6 +28,10 @@
#include "ltable.h"
#include "ltm.h"
#ifdef RAVI_USE_ASMVM
#include "ravi_asmvm_defs.h"
#endif
#include "ravijit.h"
#include "ravi_profile.h"
@ -116,6 +120,7 @@ CallInfo *luaE_extendCI (lua_State *L) {
L->ci->next = ci;
ci->previous = L->ci;
ci->next = NULL;
ci->magic = 42;
L->nci++;
return ci;
}
@ -167,6 +172,7 @@ static void stack_init (lua_State *L1, lua_State *L) {
ci->next = ci->previous = NULL;
ci->callstatus = 0;
ci->jitstatus = 0; /* RAVI extension */
ci->magic = 42; /* RAVI extension */
ci->func = L1->top;
setnilvalue(L1->top++); /* 'function' entry for this 'ci' */
ci->top = L1->top + LUA_MINSTACK;
@ -243,6 +249,8 @@ static void preinit_thread (lua_State *L, global_State *g) {
L->status = LUA_OK;
L->errfunc = 0;
L->base_ci.stacklevel = 0; /* RAVI base stack level */
L->base_ci.magic = 42;
L->magic = 42; /* RAVI extension */
}
@ -315,6 +323,23 @@ void raviE_default_writestringerror(const char *fmt, const char *p) {
fflush(stderr);
}
#ifdef RAVI_USE_ASMVM
/* Initialize dispatch table used by the ASM VM */
static void dispatch_init(global_State *G) {
ASMFunction *disp = G->dispatch;
for (uint32_t i = 0; i < NUM_OPCODES; i++) {
/*
Following computes an offset for the assembly routine for the given OpCode.
The offset is relative to the global symbol ravi_vm_asm_begin that is
generated as part of the VMBuilder code generation. All the bytecode
routines are at some offset to this global symbol.
*/
/* NOTE: enabling ltests.h modifies the global_State and breaks the assumptions abou the location of the dispatch table */
disp[i] = makeasmfunc(ravi_bytecode_offsets[i]);
}
}
#endif
LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
int i;
lua_State *L;
@ -364,6 +389,10 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
close_state(L);
L = NULL;
}
#ifdef RAVI_USE_ASMVM
/* setup dispatch table - this is only used by the new ASM VM - see vmbuilder */
dispatch_init(g);
#endif
#if RAVI_BYTECODE_PROFILING_ENABLED
raviV_init_profiledata(L);
#endif

@ -327,7 +327,9 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
if (size == 0) { /* no elements to hash part? */
t->node = cast(Node *, dummynode); /* use common 'dummynode' */
t->lsizenode = 0;
t->hmask = 0;
#if RAVI_USE_NEWHASH
t->hmask = 0;
#endif
t->lastfree = NULL; /* signal that it is using dummy node */
}
else {
@ -344,7 +346,9 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
setnilvalue(gval(n));
}
t->lsizenode = cast_byte(lsize);
t->hmask = size - 1;
#if RAVI_USE_NEWHASH
t->hmask = size - 1;
#endif
t->lastfree = gnode(t, size); /* all positions are free */
}
}

@ -468,12 +468,6 @@ static char *buildop (Proto *p, int pc, char *buff) {
Instruction i = p->code[pc];
OpCode o = GET_OPCODE(i);
const char *name = luaP_opnames[o];
/* FIXME Temp hack to output old opcodes so that the tests
do not break */
if (strcmp(name, "GETTABLE_SK") == 0) name = "GETTABLE";
else if (strcmp(name, "SELF_SK") == 0) name = "SELF";
else if (strcmp(name, "SETTABLE_SK") == 0) name = "SETTABLE";
else if (strcmp(name, "GETTABUP_SK") == 0) name = "GETTABUP";
int line = getfuncline(p, pc);
sprintf(buff, "(%4d) %4d - ", line, pc);
switch (getOpMode(o)) {

@ -4,6 +4,10 @@
** See Copyright Notice in lua.h
*/
#if USE_LLVM
#include <ravi_llvm.h>
#endif
#define lua_c
#include "lprefix.h"
@ -41,9 +45,9 @@
#define LUA_INITVARVERSION LUA_INIT_VAR LUA_VERSUFFIX
#ifdef USE_LLVM
#define RAVI_OPTION_STRING3 " LLVM"
#elif USE_GCCJIT
#define RAVI_OPTION_STRING3 " gccjit"
#define ravi_xstringify(s) ravi_stringify(s)
#define ravi_stringify(s) #s
#define RAVI_OPTION_STRING3 " LLVM-" LLVM_VERSION_STRING " ORC=" ravi_xstringify(USE_ORC_JIT)
#else
#define RAVI_OPTION_STRING3 " nojit"
#endif

@ -172,11 +172,14 @@ static void LoadUpvalues (LoadState *S, Proto *f) {
n = LoadInt(S);
f->upvalues = luaM_newvector(S->L, n, Upvaldesc);
f->sizeupvalues = n;
for (i = 0; i < n; i++)
for (i = 0; i < n; i++) {
f->upvalues[i].name = NULL;
f->upvalues[i].usertype = NULL;
}
for (i = 0; i < n; i++) {
f->upvalues[i].instack = LoadByte(S);
f->upvalues[i].idx = LoadByte(S);
// FIXME f->upvalues[i].usertype = LoadString(S);
}
}
@ -190,18 +193,22 @@ static void LoadDebug (LoadState *S, Proto *f) {
n = LoadInt(S);
f->locvars = luaM_newvector(S->L, n, LocVar);
f->sizelocvars = n;
for (i = 0; i < n; i++)
for (i = 0; i < n; i++) {
f->locvars[i].varname = NULL;
f->locvars[i].usertype = NULL;
}
for (i = 0; i < n; i++) {
f->locvars[i].varname = LoadString(S);
f->locvars[i].startpc = LoadInt(S);
f->locvars[i].endpc = LoadInt(S);
f->locvars[i].ravi_type = (ravitype_t) LoadByte(S);
f->locvars[i].ravi_type = LoadByte(S);
f->locvars[i].usertype = LoadString(S);
}
n = LoadInt(S);
for (i = 0; i < n; i++) {
f->upvalues[i].name = LoadString(S);
f->upvalues[i].type = (ravitype_t) LoadByte(S);
f->upvalues[i].ravi_type = LoadByte(S);
f->upvalues[i].usertype = LoadString(S);
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,424 @@
/*
* Sparse c2xml
*
* Dumps the parse tree as an xml document
*
* Copyright (C) 2007 Rob Taylor
*
* 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 <ctype.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <allocate.h>
#include <dmr_c.h>
#include <expression.h>
#include <parse.h>
#include <port.h>
#include <symbol.h>
#include <token.h>
#include <scope.h>
#define LUA_LIB
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
struct parser_state {
lua_State *L;
struct dmr_C *C;
struct allocator int_allocator;
int idcount;
int tabidx;
int stack[30];
int stackpos;
};
static void push_tabindex(struct parser_state *S)
{
assert(S->stackpos >= -1 && S->stackpos < 28);
S->stackpos++;
S->stack[S->stackpos] = S->tabidx;
S->tabidx = 1;
}
static void pop_tabindex(struct parser_state *S)
{
assert(S->stackpos >= 0);
S->tabidx = S->stack[S->stackpos];
S->stackpos--;
}
static void *visited(struct parser_state *S, int id) {
int *p = (int *)dmrC_allocator_allocate(&S->int_allocator, 0);
*p = id;
return p;
}
static void examine_symbol(struct parser_state *S, struct symbol *sym);
static void newProp(struct parser_state *S, const char *name, const char *value)
{
lua_pushstring(S->L, name);
lua_pushstring(S->L, value);
lua_settable(S->L, -3);
}
static void newNumProp(struct parser_state *S, const char *name, int value)
{
lua_pushstring(S->L, name);
lua_pushinteger(S->L, value);
lua_settable(S->L, -3);
}
static void newIdProp(struct parser_state *S, const char *name, unsigned int id)
{
char buf[256];
snprintf(buf, 256, "_%d", id);
newProp(S, name, buf);
}
static void popNamedTable(struct parser_state *S, const char *name)
{
lua_assert(lua_istable(S->L, -1));
lua_assert(lua_istable(S->L, -2));
pop_tabindex(S);
lua_pushstring(S->L, name);
lua_pushvalue(S->L, -2); /* top table */
lua_settable(S->L, -4); /* bottom table */
lua_pop(S->L, 1); /* pop top table */
}
static void popTable(struct parser_state *S)
{
lua_assert(lua_istable(S->L, -1));
lua_assert(lua_istable(S->L, -2));
pop_tabindex(S);
int id = S->tabidx++;
lua_seti(S->L, -2, id); /* bottom table */
}
static void new_sym_node(struct parser_state *S, struct symbol *sym, const char *name)
{
const char *ident = dmrC_show_ident(S->C, sym->ident);
assert(name != NULL);
assert(sym != NULL);
lua_newtable(S->L);
push_tabindex(S);
newNumProp(S, "id", S->idcount);
newProp(S, "type", name);
if (sym->ident && ident)
newProp(S, "ident", ident);
newProp(S, "file", dmrC_stream_name(S->C, sym->pos.stream));
newNumProp(S, "startline", sym->pos.line);
newNumProp(S, "startcol", sym->pos.pos);
if (sym->endpos.type) {
newNumProp(S, "endline", sym->endpos.line);
newNumProp(S, "endcol", sym->endpos.pos);
if (sym->pos.stream != sym->endpos.stream)
newProp(S, "endfile", dmrC_stream_name(S->C, sym->endpos.stream));
}
sym->aux = visited(S, S->idcount);
S->idcount++;
}
static void examine_members(struct parser_state *S, struct symbol_list *list)
{
struct symbol *sym;
FOR_EACH_PTR(list, sym) {
examine_symbol(S, sym);
} END_FOR_EACH_PTR(sym);
}
static void examine_modifiers(struct parser_state *S, struct symbol *sym)
{
struct mod_name {
unsigned long mod;
const char *name;
} * m;
static struct mod_name mod_names[] = {
{MOD_AUTO, "auto"},
{MOD_REGISTER, "register"},
{MOD_STATIC, "static"},
{MOD_EXTERN, "extern"},
{MOD_CONST, "const"},
{MOD_VOLATILE, "volatile"},
{MOD_SIGNED, "signed"},
{MOD_UNSIGNED, "unsigned"},
{MOD_CHAR, "char"},
{MOD_SHORT, "short"},
{MOD_LONG, "long"},
{MOD_LONGLONG, "long long"},
{MOD_LONGLONGLONG, "long long long"},
{MOD_TYPEDEF, "typedef"},
{MOD_TLS, "tls"},
{MOD_INLINE, "inline"},
{MOD_ADDRESSABLE, "addressable"},
{MOD_NOCAST, "nocast"},
{MOD_NODEREF, "noderef"},
{MOD_ACCESSED, "accessed"},
{MOD_TOPLEVEL, "toplevel"},
{MOD_ASSIGNED, "assigned"},
{MOD_TYPE, "type"},
{MOD_SAFE, "safe"},
{MOD_USERTYPE, "usertype"},
{MOD_NORETURN, "noreturn"},
{MOD_EXPLICITLY_SIGNED, "explicitly-signed"},
{MOD_BITWISE, "bitwise"},
{MOD_PURE, "pure"},
};
if (sym->ns != NS_SYMBOL)
return;
for (int i = 0; i < ARRAY_SIZE(mod_names); i++) {
m = mod_names + i;
if (sym->ctype.modifiers & m->mod) {
newNumProp(S, m->name, 1);
}
}
if (dmrC_is_prototype(sym))
newNumProp(S, "prototype", 1);
}
static void
examine_layout(struct parser_state *S, struct symbol *sym)
{
dmrC_examine_symbol_type(S->C->S, sym);
newNumProp(S, "bitsize", sym->bit_size);
newNumProp(S, "alignment", sym->ctype.alignment);
newNumProp(S, "offset", sym->offset);
if (dmrC_is_bitfield_type(sym)) {
newNumProp(S, "bitoffset", sym->bit_offset);
}
}
static void examine_symbol(struct parser_state *S, struct symbol *sym)
{
const char *base;
int array_size;
if (!sym)
return;
if (sym->aux) /*already visited */
return;
if (sym->ident && sym->ident->reserved)
return;
int savedpos = lua_gettop(S->L);
new_sym_node(S, sym, dmrC_get_type_name(sym->type));
examine_modifiers(S, sym);
examine_layout(S, sym);
if (sym->ctype.base_type) {
if ((base = dmrC_builtin_typename(S->C, sym->ctype.base_type)) == NULL) {
if (!sym->ctype.base_type->aux) {
examine_symbol(S, sym->ctype.base_type);
}
newNumProp(S, "basetype", *((int *)sym->ctype.base_type->aux));
} else {
newProp(S, "builtintype", base);
}
}
if (sym->array_size) {
/* TODO: modify dmrC_get_expression_value to give error return */
array_size = dmrC_get_expression_value(S->C, sym->array_size);
newNumProp(S, "arraysize", array_size);
}
switch (sym->type) {
case SYM_STRUCT:
case SYM_UNION:
examine_members(S, sym->symbol_list);
break;
case SYM_FN: {
int savedpos2 = lua_gettop(S->L);
lua_newtable(S->L);
push_tabindex(S);
examine_members(S, sym->arguments);
popNamedTable(S, "arguments");
//examine_members(C, sym->symbol_list);
lua_assert(savedpos2 == lua_gettop(S->L));
break;
}
case SYM_UNINITIALIZED:
newProp(S, "builtintype", dmrC_builtin_typename(S->C, sym));
break;
default:
break;
}
popTable(S);
lua_assert(savedpos == lua_gettop(S->L));
return;
}
static struct position *get_expansion_end (struct token *token)
{
struct token *p1, *p2;
for (p1=NULL, p2=NULL;
!dmrC_eof_token(token);
p2 = p1, p1 = token, token = token->next);
if (p2)
return &(p2->pos);
else
return NULL;
}
static void examine_macro(struct parser_state *S, struct symbol *sym)
{
struct position *pos;
/* this should probably go in the main codebase*/
pos = get_expansion_end(sym->expansion);
if (pos)
sym->endpos = *pos;
else
sym->endpos = sym->pos;
new_sym_node(S, sym, "macro");
}
static void examine_namespace(struct parser_state *S, struct symbol *sym)
{
if (sym->ident && sym->ident->reserved)
return;
switch(sym->ns) {
case NS_MACRO:
examine_macro(S, sym);
break;
case NS_TYPEDEF:
case NS_STRUCT:
case NS_SYMBOL:
examine_symbol(S, sym);
break;
case NS_NONE:
case NS_LABEL:
case NS_ITERATOR:
case NS_UNDEF:
case NS_PREPROCESSOR:
case NS_KEYWORD:
break;
default:
break;
//dmrC_die(S->C, "Unrecognised namespace type %d",sym->ns);
}
}
static int get_stream_id (struct dmr_C *C, const char *name)
{
int i;
for (i=0; i<C->T->input_stream_nr; i++) {
if (strcmp(name, dmrC_stream_name(C, i))==0)
return i;
}
return -1;
}
static void examine_symbol_list(struct parser_state *S, int stream_id, struct symbol_list *list)
{
struct symbol *sym;
if (!list)
return;
FOR_EACH_PTR(list, sym) {
if (sym->pos.stream == stream_id)
examine_namespace(S, sym);
} END_FOR_EACH_PTR(sym);
}
static int dmrC_getsymbols(lua_State *L)
{
struct symbol_list *symlist;
struct string_list *filelist = NULL;
char *file;
struct dmr_C *C = new_dmr_C();
const char *codebuffer = luaL_checkstring(L, 1);
char *argv[] = { NULL };
int argc = 0;
symlist = dmrC_sparse_initialize(C, argc, argv, &filelist);
struct parser_state parser_state = {
.L = L,
.C = C,
.idcount = 0,
.stack = {0},
.stackpos = -1,
.tabidx = 1
};
dmrC_allocator_init(&parser_state.int_allocator, "integers", sizeof(int), __alignof__(int), CHUNK);
lua_newtable(L);
int luastack = lua_gettop(L);
push_tabindex(&parser_state);
#if 0
FOR_EACH_PTR(filelist, file) {
int fd = get_stream_id(C, file);
examine_symbol_list(C, fd, symlist);
dmrC_sparse_keep_tokens(C, file);
examine_symbol_list(C, fd, C->file_scope->symbols);
examine_symbol_list(C, fd, C->global_scope->symbols);
} END_FOR_EACH_PTR(file);
#endif
char *buffer = strdup(codebuffer);
if (dmrC_sparse_buffer(C, "buffer", buffer, 1)) {
int fd = get_stream_id(C, "buffer");
examine_symbol_list(&parser_state, fd, C->file_scope->symbols);
examine_symbol_list(&parser_state, fd, C->global_scope->symbols);
}
free(buffer);
destroy_dmr_C(C);
dmrC_allocator_destroy(&parser_state.int_allocator);
lua_assert(luastack == lua_gettop(L));
return 1;
}
static const luaL_Reg dmrclib[] = {
{ "getsymbols", dmrC_getsymbols },{ NULL, NULL } };
LUAMOD_API int raviopen_dmrcluaapi(lua_State *L) {
luaL_newlib(L, dmrclib);
return 1;
}

@ -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,262 +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;
}
// TODO we probably do not need all the headers
// below
#define LUA_CORE
#include "lua.h"
#include "lobject.h"
#include "lstate.h"
#include "lauxlib.h"
#include "ravi_gccjit.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_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

File diff suppressed because it is too large Load Diff

@ -27,36 +27,35 @@
namespace ravi {
// OP_ADD, OP_SUB, OP_MUL and OP_DIV
void RaviCodeGenerator::emit_ARITH(RaviFunctionDef *def, int A, int B, int C,
OpCode op, TMS tms, int pc) {
#if 0
bool traced = emit_debug_trace(def, op, pc);
// Code size priority so go via function calls
void RaviCodeGenerator::emit_ARITH_calls(RaviFunctionDef *def, int A, int B,
int C, OpCode op, TMS tms, int pc) {
emit_debug_trace(def, op, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
llvm::Value *rb = emit_gep_register_or_constant(def, B);
llvm::Value *rc = emit_gep_register_or_constant(def, C);
switch (op) {
case OP_ADD:
CreateCall4(def->builder, def->raviV_op_addF,
def->L, ra, rb, rc);
break;
case OP_SUB:
CreateCall4(def->builder, def->raviV_op_subF,
def->L, ra, rb, rc);
break;
case OP_MUL:
CreateCall4(def->builder, def->raviV_op_mulF,
def->L, ra, rb, rc);
break;
case OP_DIV:
CreateCall4(def->builder, def->raviV_op_divF,
def->L, ra, rb, rc);
break;
default:
lua_assert(0);
case OP_ADD:
CreateCall4(def->builder, def->raviV_op_addF, def->L, ra, rb, rc);
break;
case OP_SUB:
CreateCall4(def->builder, def->raviV_op_subF, def->L, ra, rb, rc);
break;
case OP_MUL:
CreateCall4(def->builder, def->raviV_op_mulF, def->L, ra, rb, rc);
break;
case OP_DIV:
CreateCall4(def->builder, def->raviV_op_divF, def->L, ra, rb, rc);
break;
default: lua_assert(0);
}
}
#else
// OP_ADD, OP_SUB, OP_MUL and OP_DIV
void RaviCodeGenerator::emit_ARITH_intpriority(RaviFunctionDef *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;
@ -240,12 +239,14 @@ void RaviCodeGenerator::emit_ARITH(RaviFunctionDef *def, int A, int B, int C,
def->f->getBasicBlockList().push_back(done_block);
def->builder->SetInsertPoint(done_block);
#endif
}
// OP_ADD, OP_SUB, OP_MUL and OP_DIV
void RaviCodeGenerator::emit_ARITH_new(RaviFunctionDef *def, int A, int B,
int C, OpCode op, TMS tms, int pc) {
// This version prioritizes floating point arith over integer arith
// Also slow path is slower as it goes via function calls
void RaviCodeGenerator::emit_ARITH_floatpriority(RaviFunctionDef *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;
@ -443,7 +444,7 @@ void RaviCodeGenerator::emit_ARITH_new(RaviFunctionDef *def, int A, int B,
result = def->builder->CreateFDiv(
def->builder->CreateSIToFP(lhs, def->types->lua_NumberT),
def->builder->CreateSIToFP(rhs, def->types->lua_NumberT));
break;
break;
default: lua_assert(0);
}

@ -1,27 +1,28 @@
/******************************************************************************
* 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.
******************************************************************************/
* 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 <ravijit.h>
#include "ravi_llvmcodegen.h"
#include <ravi_llvmcodegen.h>
#include <ravi_jitshared.h>
namespace ravi {
@ -108,9 +109,23 @@ void RaviCodeGenerator::attach_branch_weights(RaviFunctionDef *def,
llvm::Instruction *ins,
uint32_t true_branch,
uint32_t false_branch) {
#if RAVI_USE_LLVM_BRANCH_WEIGHTS
ins->setMetadata(llvm::LLVMContext::MD_prof,
def->jitState->types()->mdbuilder.createBranchWeights(
true_branch, false_branch));
#else
(void)def;
(void)ins;
(void)true_branch;
(void)false_branch;
#endif
}
llvm::Value *RaviCodeGenerator::emit_gep(RaviFunctionDef *def, const char *name,
llvm::Value *s, int arg1) {
llvm::SmallVector<llvm::Value *, 1> values;
values.push_back(def->types->kInt[arg1]);
return def->builder->CreateInBoundsGEP(s, values, name);
}
llvm::Value *RaviCodeGenerator::emit_gep(RaviFunctionDef *def, const char *name,
@ -353,7 +368,7 @@ llvm::Value *RaviCodeGenerator::emit_table_get_hashsize(RaviFunctionDef *def,
llvm::Value *RaviCodeGenerator::emit_table_get_hashstr(RaviFunctionDef *def,
llvm::Value *table,
TString *key) {
#if NEW_HASH
#if RAVI_USE_NEWHASH
unsigned int hash = key->hash;
llvm::Value *hmask_ptr = emit_gep(def, "hmask", table, 0, 12);
llvm::Instruction *hmask = def->builder->CreateLoad(hmask_ptr);
@ -524,7 +539,7 @@ void RaviCodeGenerator::emit_store_type_(RaviFunctionDef *def,
type == LUA_TBOOLEAN || type == LUA_TNIL);
llvm::Value *desttype = emit_gep(def, "dest.tt", value, 0, 1);
llvm::Instruction *store =
def->builder->CreateStore(def->types->kInt[type], desttype);
def->builder->CreateStore(def->types->kByte[type], desttype);
store->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_ttT);
}
@ -540,25 +555,25 @@ llvm::Value *RaviCodeGenerator::emit_is_value_of_type(RaviFunctionDef *def,
llvm::Value *value_type,
LuaTypeCode lua_type,
const char *varname) {
return def->builder->CreateICmpEQ(value_type, def->types->kInt[int(lua_type)],
return def->builder->CreateICmpEQ(value_type, def->types->kByte[int(lua_type)],
varname);
}
llvm::Value *RaviCodeGenerator::emit_is_not_value_of_type(
RaviFunctionDef *def, llvm::Value *value_type, LuaTypeCode lua_type,
const char *varname) {
return def->builder->CreateICmpNE(value_type, def->types->kInt[int(lua_type)],
return def->builder->CreateICmpNE(value_type, def->types->kByte[int(lua_type)],
varname);
}
// Compare without variants i.e. ttnov(value_type) == lua_type
llvm::Value *RaviCodeGenerator::emit_is_not_value_of_type_class(
RaviFunctionDef *def, llvm::Value *value_type, LuaTypeCode lua_type,
RaviFunctionDef *def, llvm::Value *value_type, int lua_type,
const char *varname) {
llvm::Value *novariant_type =
def->builder->CreateAnd(value_type, def->types->kInt[0x0F]);
def->builder->CreateAnd(value_type, def->types->kByte[0x0F]);
return def->builder->CreateICmpNE(novariant_type,
def->types->kInt[int(lua_type)], varname);
def->types->kByte[int(lua_type)], varname);
}
llvm::Instruction *RaviCodeGenerator::emit_load_ravi_arraytype(
@ -1048,10 +1063,10 @@ void RaviCodeGenerator::emit_extern_declarations(RaviFunctionDef *def) {
def->types->luaH_getstrT, reinterpret_cast<void *>(&luaH_getstr),
"luaH_getstr");
def->luaH_getstrF->addFnAttr(llvm::Attribute::AttrKind::ReadOnly);
def->luaH_getstrF->setDoesNotAlias(1);
def->luaH_getstrF->setDoesNotCapture(1);
def->luaH_getstrF->setDoesNotAlias(2);
def->luaH_getstrF->setDoesNotCapture(2);
// def->luaH_getstrF->setDoesNotAlias(1);
// def->luaH_getstrF->setDoesNotCapture(1);
// def->luaH_getstrF->setDoesNotAlias(2);
// def->luaH_getstrF->setDoesNotCapture(2);
def->luaV_finishgetF = def->raviF->addExternFunction(
def->types->luaV_finishgetT, reinterpret_cast<void *>(&luaV_finishget),
"luaV_finishget");
@ -1148,6 +1163,15 @@ void RaviCodeGenerator::emit_extern_declarations(RaviFunctionDef *def) {
def->raviV_gettable_sskeyF = def->raviF->addExternFunction(
def->types->raviV_gettable_sskeyT,
reinterpret_cast<void *>(&raviV_gettable_sskey), "raviV_gettable_sskey");
def->raviV_settable_iF = def->raviF->addExternFunction(
def->types->raviV_settable_iT,
reinterpret_cast<void *>(&raviV_settable_i), "raviV_settable_i");
def->raviV_gettable_iF = def->raviF->addExternFunction(
def->types->raviV_gettable_iT,
reinterpret_cast<void *>(&raviV_gettable_i), "raviV_gettable_i");
def->raviV_op_totypeF = def->raviF->addExternFunction(
def->types->raviV_op_totypeT, reinterpret_cast<void *>(&raviV_op_totype),
"raviV_op_totype");
def->ravi_dump_valueF = def->raviF->addExternFunction(
def->types->ravi_dump_valueT, reinterpret_cast<void *>(&ravi_dump_value),
@ -1203,24 +1227,6 @@ void RaviCodeGenerator::emit_extern_declarations(RaviFunctionDef *def) {
#endif
}
#define RA(i) (base + GETARG_A(i))
/* to be used after possible stack reallocation */
#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base + GETARG_B(i))
#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base + GETARG_C(i))
#define RKB(i) \
check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \
ISK(GETARG_B(i)) ? k + INDEXK(GETARG_B(i)) : base + GETARG_B(i))
#define RKC(i) \
check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \
ISK(GETARG_C(i)) ? k + INDEXK(GETARG_C(i)) : base + GETARG_C(i))
#define KBx(i) \
(k + (GETARG_Bx(i) != 0 ? GETARG_Bx(i) - 1 : GETARG_Ax(*ci->u.l.savedpc++)))
/* RAVI */
#define KB(i) \
check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k + INDEXK(GETARG_B(i)))
#define KC(i) \
check_exp(getCMode(GET_OPCODE(i)) == OpArgK, k + INDEXK(GETARG_C(i)))
void RaviCodeGenerator::link_block(RaviFunctionDef *def, int pc) {
// If we are on a jump target then check if this is a forloop
// target. Forloop targets are special as they use computed goto
@ -1301,7 +1307,10 @@ bool RaviCodeGenerator::compile(lua_State *L, Proto *p,
ravi_compile_options_t *options) {
if (p->ravi_jit.jit_status == RAVI_JIT_COMPILED) return true;
bool doVerify = options ? options->verification_level != 0 : 0;
// Avoid recursive calls
if (module->owner()->get_compiling_flag()) return false;
bool doVerify = module->owner()->get_validation() != 0;
bool omitArrayGetRangeCheck =
options ? options->omit_array_get_range_check != 0 : 0;
@ -1316,28 +1325,15 @@ bool RaviCodeGenerator::compile(lua_State *L, Proto *p,
RaviFunctionDef definition = {0};
RaviFunctionDef *def = &definition;
// The Lua GC doesn't know about memory allocated by the JIT
// compiler; this means that if lots of functions are being compiled
// such as in the test cases, then memory usage can grow very large
// as the GC is blissfully unaware of the actual memory in use
// To workaround this issue we provide an option that can be used to
// force a GC after every n compilations where n is supplied
// by the gcstep parameter; this is not ideal as it kills performance
// but appears to work for the test cases
// A better solution is needed
int gcstep = this->jitState_->get_gcstep();
if (gcstep > 0 && (id_ % gcstep) == 0) {
lua_unlock(L);
lua_gc(L, LUA_GCCOLLECT, 0);
lua_lock(L);
}
auto f = create_function(p, module, builder, def);
if (!f) {
p->ravi_jit.jit_status = RAVI_JIT_CANT_COMPILE; // can't compile
return false;
}
// Set flag so we can avoid recursive calls
module->owner()->set_compiling_flag(true);
// The functions constants
TValue *k = p->k;
@ -1634,8 +1630,11 @@ bool RaviCodeGenerator::compile(lua_State *L, Proto *p,
int C = GETARG_C(i);
emit_SETTABLE_SK(def, A, B, C, pc);
} break;
case OP_RAVI_SETTABLE_I:
case OP_RAVI_SETTABLE_I: {
int B = GETARG_B(i);
int C = GETARG_C(i);
emit_SETTABLE_I(def, A, B, C, pc);
} break;
case OP_SETTABLE: {
int B = GETARG_B(i);
int C = GETARG_C(i);
@ -1710,6 +1709,19 @@ bool RaviCodeGenerator::compile(lua_State *L, Proto *p,
case OP_RAVI_TOARRAYF: {
emit_TOARRAY(def, A, RAVI_TARRAYFLT, "number[] expected", pc);
} break;
case OP_RAVI_TOSTRING: {
emit_TOSTRING(def, A, pc);
break;
}
case OP_RAVI_TOCLOSURE: {
emit_TOCLOSURE(def, A, pc);
break;
}
case OP_RAVI_TOTYPE: {
int Bx = GETARG_Bx(i);
emit_TOTYPE(def, A, Bx, pc);
break;
}
case OP_RAVI_MOVEAI: {
int B = GETARG_B(i);
emit_MOVEAI(def, A, B, pc);
@ -1801,7 +1813,7 @@ bool RaviCodeGenerator::compile(lua_State *L, Proto *p,
case OP_ADD: {
int B = GETARG_B(i);
int C = GETARG_C(i);
emit_ARITH_new(def, A, B, C, OP_ADD, TM_ADD, pc);
emit_ARITH(def, A, B, C, OP_ADD, TM_ADD, pc);
} break;
case OP_RAVI_ADDFF: {
int B = GETARG_B(i);
@ -1822,7 +1834,7 @@ bool RaviCodeGenerator::compile(lua_State *L, Proto *p,
case OP_SUB: {
int B = GETARG_B(i);
int C = GETARG_C(i);
emit_ARITH_new(def, A, B, C, OP_SUB, TM_SUB, pc);
emit_ARITH(def, A, B, C, OP_SUB, TM_SUB, pc);
} break;
case OP_RAVI_SUBFF: {
int B = GETARG_B(i);
@ -1848,7 +1860,7 @@ bool RaviCodeGenerator::compile(lua_State *L, Proto *p,
case OP_MUL: {
int B = GETARG_B(i);
int C = GETARG_C(i);
emit_ARITH_new(def, A, B, C, OP_MUL, TM_MUL, pc);
emit_ARITH(def, A, B, C, OP_MUL, TM_MUL, pc);
} break;
case OP_RAVI_MULFF: {
int B = GETARG_B(i);
@ -1869,7 +1881,7 @@ bool RaviCodeGenerator::compile(lua_State *L, Proto *p,
case OP_DIV: {
int B = GETARG_B(i);
int C = GETARG_C(i);
emit_ARITH_new(def, A, B, C, OP_DIV, TM_DIV, pc);
emit_ARITH(def, A, B, C, OP_DIV, TM_DIV, pc);
} break;
case OP_RAVI_DIVFF: {
int B = GETARG_B(i);
@ -1921,12 +1933,16 @@ bool RaviCodeGenerator::compile(lua_State *L, Proto *p,
if (doVerify && llvm::verifyFunction(*f->function(), &llvm::errs())) {
f->dump();
fprintf(stderr, "LLVM Code Verification failed\n");
exit(1);
exit(1);
}
ravi::RaviJITFunction *llvm_func = f.release();
p->ravi_jit.jit_data = reinterpret_cast<void *>(llvm_func);
p->ravi_jit.jit_function = nullptr;
p->ravi_jit.jit_status = RAVI_JIT_COMPILED;
module->owner()->set_compiling_flag(false);
return llvm_func != nullptr;
}
@ -2004,4 +2020,4 @@ void RaviCodeGenerator::scan_jump_targets(RaviFunctionDef *def, Proto *p) {
}
}
}
}
} // namespace ravi

@ -1,27 +1,30 @@
/******************************************************************************
* 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.
******************************************************************************/
* 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_llvmcodegen.h>
#include <ravijit.h>
#include "ravi_llvmcodegen.h"
// Important to include the C++ header files (ravi_llvmcodegen.h) before following
// (ravi_jitshared.h) as the Lua headers define macros that mess with C++ headers
#include <ravi_jitshared.h>
/*
* Implementation Notes:
@ -36,6 +39,79 @@ namespace ravi {
// see below
static std::atomic_int init;
static struct {
const char *name;
void *address;
} global_syms[] = {
{"lua_absindex", reinterpret_cast<void *>(lua_absindex)},
{"lua_gettop", reinterpret_cast<void *>(lua_gettop)},
{"lua_settop", reinterpret_cast<void *>(lua_settop)},
{"lua_pushvalue", reinterpret_cast<void *>(lua_pushvalue)},
{"lua_rotate", reinterpret_cast<void *>(lua_rotate)},
{"lua_copy", reinterpret_cast<void *>(lua_copy)},
{"lua_checkstack", reinterpret_cast<void *>(lua_checkstack)},
{"lua_xmove", reinterpret_cast<void *>(lua_xmove)},
{"lua_isnumber", reinterpret_cast<void *>(lua_isnumber)},
{"lua_isstring", reinterpret_cast<void *>(lua_isstring)},
{"lua_iscfunction", reinterpret_cast<void *>(lua_iscfunction)},
{"lua_isinteger", reinterpret_cast<void *>(lua_isinteger)},
{"lua_isuserdata", reinterpret_cast<void *>(lua_isuserdata)},
{"lua_type", reinterpret_cast<void *>(lua_type)},
{"lua_typename", reinterpret_cast<void *>(lua_typename)},
{"lua_tonumberx", reinterpret_cast<void *>(lua_tonumberx)},
{"lua_tointegerx", reinterpret_cast<void *>(lua_tointegerx)},
{"lua_toboolean", reinterpret_cast<void *>(lua_toboolean)},
{"lua_tolstring", reinterpret_cast<void *>(lua_tolstring)},
{"lua_rawlen", reinterpret_cast<void *>(lua_rawlen)},
{"lua_tocfunction", reinterpret_cast<void *>(lua_tocfunction)},
{"lua_touserdata", reinterpret_cast<void *>(lua_touserdata)},
{"lua_tothread", reinterpret_cast<void *>(lua_tothread)},
{"lua_topointer", reinterpret_cast<void *>(lua_topointer)},
{"lua_arith", reinterpret_cast<void *>(lua_arith)},
{"lua_rawequal", reinterpret_cast<void *>(lua_rawequal)},
{"lua_compare", reinterpret_cast<void *>(lua_compare)},
{"lua_pushnil", reinterpret_cast<void *>(lua_pushnil)},
{"lua_pushnumber", reinterpret_cast<void *>(lua_pushnumber)},
{"lua_pushinteger", reinterpret_cast<void *>(lua_pushinteger)},
{"lua_pushlstring", reinterpret_cast<void *>(lua_pushlstring)},
{"lua_pushstring", reinterpret_cast<void *>(lua_pushstring)},
{"lua_pushvfstring", reinterpret_cast<void *>(lua_pushvfstring)},
{"lua_pushfstring", reinterpret_cast<void *>(lua_pushfstring)},
{"lua_pushcclosure", reinterpret_cast<void *>(lua_pushcclosure)},
{"lua_pushboolean", reinterpret_cast<void *>(lua_pushboolean)},
{"lua_pushlightuserdata", reinterpret_cast<void *>(lua_pushlightuserdata)},
{"lua_pushthread", reinterpret_cast<void *>(lua_pushthread)},
{"lua_getglobal", reinterpret_cast<void *>(lua_getglobal)},
{"lua_gettable", reinterpret_cast<void *>(lua_gettable)},
{"lua_getfield", reinterpret_cast<void *>(lua_getfield)},
{"lua_geti", reinterpret_cast<void *>(lua_geti)},
{"lua_rawget", reinterpret_cast<void *>(lua_rawget)},
{"lua_rawgeti", reinterpret_cast<void *>(lua_rawgeti)},
{"lua_rawgetp", reinterpret_cast<void *>(lua_rawgetp)},
{"lua_createtable", reinterpret_cast<void *>(lua_createtable)},
{"lua_newuserdata", reinterpret_cast<void *>(lua_newuserdata)},
{"lua_getmetatable", reinterpret_cast<void *>(lua_getmetatable)},
{"lua_getuservalue", reinterpret_cast<void *>(lua_getuservalue)},
{"lua_setglobal", reinterpret_cast<void *>(lua_setglobal)},
{"lua_settable", reinterpret_cast<void *>(lua_settable)},
{"lua_setfield", reinterpret_cast<void *>(lua_setfield)},
{"lua_seti", reinterpret_cast<void *>(lua_seti)},
{"lua_rawset", reinterpret_cast<void *>(lua_rawset)},
{"lua_rawseti", reinterpret_cast<void *>(lua_rawseti)},
{"lua_rawsetp", reinterpret_cast<void *>(lua_rawsetp)},
{"lua_setmetatable", reinterpret_cast<void *>(lua_setmetatable)},
{"lua_setuservalue", reinterpret_cast<void *>(lua_setuservalue)},
{"lua_gc", reinterpret_cast<void *>(lua_gc)},
{"lua_error", reinterpret_cast<void *>(lua_error)},
{"lua_next", reinterpret_cast<void *>(lua_next)},
{"lua_concat", reinterpret_cast<void *>(lua_concat)},
{"lua_len", reinterpret_cast<void *>(lua_len)},
{"lua_stringtonumber", reinterpret_cast<void *>(lua_stringtonumber)},
{"printf", reinterpret_cast<void *>(printf)},
{"puts", reinterpret_cast<void *>(puts)},
{nullptr, nullptr}};
// Construct the JIT compiler state
// The JIT compiler state will be attached to the
// lua_State - all compilation activity happens
@ -45,11 +121,14 @@ RaviJITState::RaviJITState()
enabled_(true),
opt_level_(2),
size_level_(0),
verbosity_(0),
tracehook_enabled_(false),
validation_(false),
gcstep_(300),
min_code_size_(150),
min_exec_count_(50),
gc_step_(300),
tracehook_enabled_(false),
allocated_modules_(0) {
allocated_modules_(0),
compiling_(false) {
// LLVM needs to be initialized else
// ExecutionEngine cannot be created
// This needs to be an atomic check although LLVM docs
@ -58,10 +137,13 @@ RaviJITState::RaviJITState()
llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter();
llvm::InitializeNativeTargetAsmParser();
// TODO see email trail on resolving symbols in process
llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr);
init++;
}
triple_ = llvm::sys::getProcessTriple();
#if defined(_WIN32) && (!defined(_WIN64) || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7)
#if defined(_WIN32) && \
(!defined(_WIN64) || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7)
// On Windows we get compilation error saying incompatible object format
// Reading posts on mailing lists I found that the issue is that COEFF
// format is not supported and therefore we need to set -elf as the object
@ -69,7 +151,31 @@ RaviJITState::RaviJITState()
triple_ += "-elf";
#endif
context_ = new llvm::LLVMContext();
#if USE_ORC_JIT
llvm::EngineBuilder eengineBuilder;
auto target = eengineBuilder.selectTarget();
TM = std::unique_ptr<llvm::TargetMachine>(target);
TM->setO0WantsFastISel(true); // enable FastISel when -O0 is used
DL = std::unique_ptr<llvm::DataLayout>(new llvm::DataLayout(TM->createDataLayout()));
ObjectLayer = std::unique_ptr<ObjectLayerT>(new ObjectLayerT(
[]() { return std::make_shared<llvm::SectionMemoryManager>(); }));
CompileLayer = std::unique_ptr<CompileLayerT>(new CompileLayerT(
*ObjectLayer, llvm::orc::SimpleCompiler(*TM)));
OptimizeLayer = std::unique_ptr<OptimizerLayerT>(new OptimizerLayerT(
*CompileLayer,
[this](std::shared_ptr<llvm::Module> M) {
return optimizeModule(std::move(M));
})),
#endif
types_ = new LuaLLVMTypes(*context_);
for (int i = 0; global_syms[i].name != nullptr; i++) {
llvm::sys::DynamicLibrary::AddSymbol(global_syms[i].name,
global_syms[i].address);
}
}
// Destroy the JIT state freeing up any
@ -80,24 +186,181 @@ RaviJITState::~RaviJITState() {
delete context_;
}
#if USE_ORC_JIT
std::shared_ptr<llvm::Module> RaviJITState::optimizeModule(
std::shared_ptr<llvm::Module> M) {
#if LLVM_VERSION_MAJOR > 3 || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
using llvm::legacy::FunctionPassManager;
using llvm::legacy::PassManager;
#else
using llvm::FunctionPassManager;
using llvm::PassManager;
#endif
if (get_verbosity() >= 1)
M->print(llvm::errs(), NULL, false, true);
if (get_verbosity() >= 3)
TM->Options.PrintMachineCode = 1;
else
TM->Options.PrintMachineCode = 0;
if (get_optlevel() == 0)
TM->Options.EnableFastISel = 1;
else
TM->Options.EnableFastISel = 0;
// We use the PassManagerBuilder to setup optimization
// passes - the PassManagerBuilder allows easy configuration of
// typical C/C++ passes corresponding to O0, O1, O2, and O3 compiler options
// If dumpAsm is true then the generated assembly code will be
// dumped to stderr
llvm::PassManagerBuilder pmb;
pmb.OptLevel = get_optlevel();
pmb.SizeLevel = get_sizelevel();
{
// Create a function pass manager for this engine
std::unique_ptr<FunctionPassManager> FPM(new FunctionPassManager(M.get()));
// Set up the optimizer pipeline. Start with registering info about how the
// target lays out data structures.
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR == 6
// LLVM 3.6.0 change
module_->setDataLayout(engine_->getDataLayout());
FPM->add(new llvm::DataLayoutPass());
#elif LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR == 5
// LLVM 3.5.0
auto target_layout = engine_->getTargetMachine()->getDataLayout();
module_->setDataLayout(target_layout);
FPM->add(new llvm::DataLayoutPass(*engine_->getDataLayout()));
#elif LLVM_VERSION_MAJOR > 3 || \
LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
// Apparently no need to set DataLayout
#else
#error Unsupported LLVM version
#endif
pmb.populateFunctionPassManager(*FPM);
FPM->doInitialization();
// Run the optimizations over all functions in the module being added to
// the JIT.
for (auto &F : *M) FPM->run(F);
}
std::string codestr;
{
// In LLVM 3.7 for some reason the string is not saved
// until the stream is destroyed - even though there is a
// flush; so we introduce a scope here to ensure destruction
// of the stream
llvm::raw_string_ostream ostream(codestr);
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7
llvm::formatted_raw_ostream formatted_stream(ostream);
#else
llvm::buffer_ostream formatted_stream(ostream);
#endif
// Also in 3.7 the pass manager seems to hold on to the stream
// so we need to ensure that the stream outlives the pass manager
std::unique_ptr<PassManager> MPM(new PassManager());
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR == 6
MPM->add(new llvm::DataLayoutPass());
#elif LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR == 5
MPM->add(new llvm::DataLayoutPass(*engine_->getDataLayout()));
#endif
pmb.populateModulePassManager(*MPM);
for (int i = 0; get_verbosity() == 2 && i < 1; i++) {
if (!TM) {
llvm::errs() << "unable to dump assembly\n";
break;
}
if (TM->addPassesToEmitFile(*MPM, formatted_stream,
llvm::TargetMachine::CGFT_AssemblyFile)) {
llvm::errs() << "unable to add passes for generating assemblyfile\n";
break;
}
}
MPM->run(*M);
// Note that in 3.7 this flus appears to have no effect
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR <= 7
formatted_stream.flush();
#endif
}
if (get_verbosity() == 2 && codestr.length() > 0) llvm::errs() << codestr << "\n";
return M;
}
#endif
void RaviJITState::addGlobalSymbol(const std::string &name, void *address) {
llvm::sys::DynamicLibrary::AddSymbol(name, address);
}
#if USE_ORC_JIT
RaviJITState::ModuleHandle RaviJITState::addModule(
std::unique_ptr<llvm::Module> M) {
// Build our symbol resolver:
// Lambda 1: Look back into the JIT itself to find symbols that are part of
// the same "logical dylib".
// Lambda 2: Search for external symbols in the host process.
auto Resolver = llvm::orc::createLambdaResolver(
[&](const std::string &Name) {
if (auto Sym = OptimizeLayer->findSymbol(Name, false)) return Sym;
return llvm::JITSymbol(nullptr);
},
[](const std::string &Name) {
if (auto SymAddr =
llvm::RTDyldMemoryManager::getSymbolAddressInProcess(Name))
return llvm::JITSymbol(SymAddr, llvm::JITSymbolFlags::Exported);
return llvm::JITSymbol(nullptr);
});
// Add the set to the JIT with the resolver we created above and a newly
// created SectionMemoryManager.
return llvm::cantFail(
OptimizeLayer->addModule(std::move(M), std::move(Resolver)));
}
llvm::JITSymbol RaviJITState::findSymbol(const std::string Name) {
std::string MangledName;
llvm::raw_string_ostream MangledNameStream(MangledName);
llvm::Mangler::getNameWithPrefix(MangledNameStream, Name, *DL);
// Note that the LLVM tutorial uses true below but that appears to
// cause a failure in lookup
return OptimizeLayer->findSymbol(MangledNameStream.str(), false);
}
void RaviJITState::removeModule(ModuleHandle H) {
llvm::cantFail(OptimizeLayer->removeModule(H));
}
#endif
void RaviJITState::dump() { types_->dump(); }
static std::atomic_int module_id;
RaviJITModule::RaviJITModule(RaviJITState *owner)
: owner_(owner), engine_(nullptr), module_(nullptr) {
: owner_(owner)
#if !USE_ORC_JIT
,module_(nullptr)
,engine_(nullptr)
#endif
{
int myid = module_id++;
char buf[40];
snprintf(buf, sizeof buf, "ravi_module_%d", myid);
std::string moduleName(buf);
#if USE_ORC_JIT
module_ = std::unique_ptr<llvm::Module>(new llvm::Module(moduleName, owner->context()));
module_->setDataLayout(owner_->getTargetMachine().createDataLayout());
#else
module_ = new llvm::Module(moduleName, owner->context());
#endif
if (myid == 0) {
// Extra validation to check that the LLVM sizes match Lua sizes
llvm::DataLayout *layout = new llvm::DataLayout(module_);
llvm::DataLayout *layout = new llvm::DataLayout(module());
// auto valueSize = layout->getTypeAllocSize(owner->types()->ValueT);
// auto valueSizeOf = sizeof(Value);
// auto TvalueSize = layout->getTypeAllocSize(owner->types()->TValueT);
@ -115,14 +378,16 @@ RaviJITModule::RaviJITModule(RaviJITState *owner)
layout->getTypeAllocSize(owner->types()->lua_StateT));
delete layout;
}
#if defined(_WIN32) && (!defined(_WIN64) || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7)
#if !USE_ORC_JIT
#if defined(_WIN32) && \
(!defined(_WIN64) || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7)
// On Windows we get error saying incompatible object format
// Reading posts on mailing lists I found that the issue is that COEFF
// format is not supported and therefore we need to set
// -elf as the object format; LLVM 3.7 onwards COEFF is supported
module_->setTargetTriple(owner->triple());
#endif
#if LLVM_VERSION_MAJOR > 3 || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 5
#if LLVM_VERSION_MAJOR > 3 || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 5
// LLVM 3.6.0 change
std::unique_ptr<llvm::Module> module(module_);
llvm::EngineBuilder builder(std::move(module));
@ -134,25 +399,30 @@ RaviJITModule::RaviJITModule(RaviJITState *owner)
std::string errStr;
builder.setErrorStr(&errStr);
engine_ = builder.create();
owner->incr_allocated_modules();
if (!engine_) {
fprintf(stderr, "FATAL ERROR: could not create ExecutionEngine: %s\n",
errStr.c_str());
abort();
return;
}
#endif
owner->incr_allocated_modules();
}
RaviJITModule::~RaviJITModule() {
#if !USE_ORC_JIT
if (engine_)
delete engine_;
else if (module_)
// if engine was created then we don't need to delete the
// module as it would have been deleted by the engine
delete module_;
#else
owner()->removeModule(module_handle_);
#endif
owner_->decr_allocated_modules();
#if 0
//fprintf(stderr, "module destroyed\n");
#if 1
// fprintf(stderr, "module destroyed\n");
#endif
}
@ -168,7 +438,7 @@ void RaviJITModule::removeFunction(RaviJITFunction *f) {
}
RaviJITFunction::RaviJITFunction(lua_CFunction *p,
std::shared_ptr<RaviJITModule> module,
const std::shared_ptr<RaviJITModule> &module,
llvm::FunctionType *type,
llvm::GlobalValue::LinkageTypes linkage,
const std::string &name)
@ -177,7 +447,19 @@ RaviJITFunction::RaviJITFunction(lua_CFunction *p,
function_(nullptr),
ptr_(nullptr),
func_ptrptr_(p) {
function_ = llvm::Function::Create(type, linkage, name, module_->module());
auto M = module_->module();
lua_assert(M);
function_ = llvm::Function::Create(type, linkage, name, M);
id_ = module_->addFunction(this);
}
RaviJITFunction::RaviJITFunction(lua_CFunction *p,
const std::shared_ptr<RaviJITModule> &module,
const std::string &name)
: module_(module), name_(name), ptr_(nullptr), func_ptrptr_(p) {
auto M = module_->module();
lua_assert(M);
function_ = M->getFunction(name);
id_ = module_->addFunction(this);
}
@ -188,6 +470,8 @@ RaviJITFunction::~RaviJITFunction() {
}
void RaviJITModule::runpasses(bool dumpAsm) {
if (!module_) return;
#if !USE_ORC_JIT
#if LLVM_VERSION_MAJOR > 3 || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
using llvm::legacy::FunctionPassManager;
using llvm::legacy::PassManager;
@ -221,7 +505,8 @@ void RaviJITModule::runpasses(bool dumpAsm) {
auto target_layout = engine_->getTargetMachine()->getDataLayout();
module_->setDataLayout(target_layout);
FPM->add(new llvm::DataLayoutPass(*engine_->getDataLayout()));
#elif LLVM_VERSION_MAJOR > 3 || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
#elif LLVM_VERSION_MAJOR > 3 || \
LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
// Apparently no need to set DataLayout
#else
#error Unsupported LLVM version
@ -277,9 +562,13 @@ void RaviJITModule::runpasses(bool dumpAsm) {
#endif
}
if (dumpAsm && codestr.length() > 0) llvm::errs() << codestr << "\n";
#endif
}
void RaviJITModule::finalize(bool doDump) {
lua_assert(module_);
if (!module_) return;
#if !USE_ORC_JIT
// Following will generate very verbose dump when machine code is
// produced below
llvm::TargetMachine *TM = engine_->getTargetMachine();
@ -293,6 +582,11 @@ void RaviJITModule::finalize(bool doDump) {
// explicitly or a function such as MCJIT::getPointerToFunction
// is called which requires the code to have been generated.
engine_->finalizeObject();
#else
// With ORC api, the module gets compiled when it is added
// The optimzation passes are run via the callback
module_handle_ = owner()->addModule(std::move(module_));
#endif
for (int i = 0; i < functions_.size(); i++) {
if (functions_[i] == nullptr) continue;
functions_[i]->setFunctionPtr();
@ -305,8 +599,22 @@ void RaviJITModule::finalize(bool doDump) {
// Lua Proto structure
void RaviJITFunction::setFunctionPtr() {
lua_assert(ptr_ == nullptr);
ptr_ = engine()->getPointerToFunction(function_);
*func_ptrptr_ = (lua_CFunction)ptr_;
// function_ may be nullptr if it was obtained by name from the module, so
// we need to check that
#if !USE_ORC_JIT
if (function_) {
ptr_ = engine()->getPointerToFunction(function_);
*func_ptrptr_ = (lua_CFunction)ptr_;
}
#else
if (function_) {
auto symbol = owner()->findSymbol(name());
if (symbol) {
ptr_ = (void *)(intptr_t)llvm::cantFail(symbol.getAddress());
*func_ptrptr_ = (lua_CFunction)ptr_;
}
}
#endif
}
llvm::Function *RaviJITModule::addExternFunction(llvm::FunctionType *type,
@ -315,7 +623,7 @@ llvm::Function *RaviJITModule::addExternFunction(llvm::FunctionType *type,
auto fn = external_symbols_.find(name);
if (fn != external_symbols_.end()) return fn->second;
llvm::Function *f = llvm::Function::Create(
type, llvm::Function::ExternalLinkage, name, module_);
type, llvm::Function::ExternalLinkage, name, module());
f->setDoesNotThrow();
// We should have been able to call
// engine_->addGlobalMapping() but this doesn't work
@ -327,11 +635,15 @@ llvm::Function *RaviJITModule::addExternFunction(llvm::FunctionType *type,
return f;
}
void RaviJITModule::dump() { module_->dump(); }
void RaviJITModule::dump() {
#if LLVM_VERSION_MAJOR < 5
if (module_) module_->dump();
#endif
}
// Dumps the machine code
// Will execute the passes as required by currently set
// optimzation level; this may or may not match the actual
// optimization level; this may or may not match the actual
// JITed code which would have used the optimzation level set at the
// time of compilation
void RaviJITModule::dumpAssembly() { runpasses(true); }
@ -339,7 +651,7 @@ void RaviJITModule::dumpAssembly() { runpasses(true); }
std::unique_ptr<RaviJITState> RaviJITStateFactory::newJITState() {
return std::unique_ptr<RaviJITState>(new RaviJITState());
}
}
} // namespace ravi
// Initialize the JIT State and attach it to the
// Global Lua State
@ -373,10 +685,11 @@ void raviV_close(struct lua_State *L) {
// Returns true if compilation was successful
int raviV_compile(struct lua_State *L, struct Proto *p,
ravi_compile_options_t *options) {
if (p->ravi_jit.jit_function) return true;
if (p->ravi_jit.jit_function) return 1;
global_State *G = G(L);
if (G->ravi_state == NULL) return 0;
if (!G->ravi_state->jit->is_enabled()) { return 0; }
if (G->ravi_state->jit->get_compiling_flag()) { return 0; }
bool doCompile = (bool)(options && options->manual_request != 0);
if (!doCompile && G->ravi_state->jit->is_auto()) {
if (p->ravi_jit.jit_flags ==
@ -400,7 +713,7 @@ int raviV_compile(struct lua_State *L, struct Proto *p,
auto module = std::make_shared<ravi::RaviJITModule>(G->ravi_state->jit);
if (G->ravi_state->code_generator->compile(L, p, module, options)) {
module->runpasses();
module->finalize(options ? options->dump_level != 0 : 0);
module->finalize(G->ravi_state->jit->get_verbosity() == 3);
}
}
return p->ravi_jit.jit_function != nullptr;
@ -413,6 +726,8 @@ int raviV_compile_n(struct lua_State *L, struct Proto *p[], int n,
ravi_compile_options_t *options) {
global_State *G = G(L);
int count = 0;
if (G->ravi_state->jit->get_compiling_flag())
return 0;
auto module = std::make_shared<ravi::RaviJITModule>(G->ravi_state->jit);
for (int i = 0; i < n; i++) {
if (G->ravi_state->code_generator->compile(L, p[i], module, options))
@ -420,7 +735,7 @@ int raviV_compile_n(struct lua_State *L, struct Proto *p[], int n,
}
if (count) {
module->runpasses();
module->finalize(options ? options->dump_level != 0 : 0);
module->finalize(G->ravi_state->jit->get_verbosity() == 3);
}
return count > 0;
}
@ -522,6 +837,28 @@ int raviV_getsizelevel(lua_State *L) {
return G->ravi_state->jit->get_sizelevel();
}
void raviV_setverbosity(lua_State *L, int value) {
global_State *G = G(L);
if (!G->ravi_state) return;
G->ravi_state->jit->set_verbosity(value);
}
int raviV_getverbosity(lua_State *L) {
global_State *G = G(L);
if (!G->ravi_state) return 0;
return G->ravi_state->jit->get_verbosity();
}
void raviV_setvalidation(lua_State *L, int value) {
global_State *G = G(L);
if (!G->ravi_state) return;
G->ravi_state->jit->set_validation(value != 0);
}
int raviV_getvalidation(lua_State *L) {
global_State *G = G(L);
if (!G->ravi_state) return 0;
return G->ravi_state->jit->get_validation();
}
void raviV_setgcstep(lua_State *L, int value) {
global_State *G = G(L);
if (!G->ravi_state) return;

@ -238,6 +238,69 @@ void RaviCodeGenerator::emit_MOVEF(RaviFunctionDef *def, int A, int B, int pc) {
emit_store_reg_n_withtype(def, load_var, dest);
}
void RaviCodeGenerator::emit_TOSTRING(RaviFunctionDef *def, int A, int pc) {
emit_debug_trace(def, OP_RAVI_TOSTRING, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
llvm::Instruction *type = emit_load_type(def, ra);
llvm::Value *isnotnil = emit_is_not_value_of_type(def, type, LUA__TNIL);
// check if string type
llvm::Value *cmp1 = emit_is_not_value_of_type_class(def, type, LUA_TSTRING);
cmp1 = def->builder->CreateAnd(isnotnil, cmp1, "OP_RAVI_TOSTRING_is.not.expected.type");
llvm::BasicBlock *raise_error = llvm::BasicBlock::Create(
def->jitState->context(), "OP_RAVI_TOSTRING_if.not.expected_type", def->f);
llvm::BasicBlock *done =
llvm::BasicBlock::Create(def->jitState->context(), "OP_RAVI_TOSTRING_done");
auto brinst1 = def->builder->CreateCondBr(cmp1, raise_error, done);
attach_branch_weights(def, brinst1, 0, 100);
def->builder->SetInsertPoint(raise_error);
// Conversion failed, so raise error
emit_raise_lua_error(def, "string expected");
def->builder->CreateBr(done);
def->f->getBasicBlockList().push_back(done);
def->builder->SetInsertPoint(done);
}
void RaviCodeGenerator::emit_TOCLOSURE(RaviFunctionDef *def, int A, int pc) {
emit_debug_trace(def, OP_RAVI_TOCLOSURE, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
llvm::Instruction *type = emit_load_type(def, ra);
llvm::Value *isnotnil = emit_is_not_value_of_type(def, type, LUA__TNIL);
// check if function type
llvm::Value *cmp1 = emit_is_not_value_of_type_class(
def, type, LUA_TFUNCTION);
cmp1 = def->builder->CreateAnd(isnotnil, cmp1, "OP_RAVI_TOCLOSURE_is.not.expected.type");
llvm::BasicBlock *raise_error = llvm::BasicBlock::Create(
def->jitState->context(), "OP_RAVI_TOCLOSURE_if.not.expected_type",
def->f);
llvm::BasicBlock *done = llvm::BasicBlock::Create(def->jitState->context(),
"OP_RAVI_TOCLOSURE_done");
auto brinst1 = def->builder->CreateCondBr(cmp1, raise_error, done);
attach_branch_weights(def, brinst1, 0, 100);
def->builder->SetInsertPoint(raise_error);
// Conversion failed, so raise error
emit_raise_lua_error(def, "closure expected");
def->builder->CreateBr(done);
def->f->getBasicBlockList().push_back(done);
def->builder->SetInsertPoint(done);
}
void RaviCodeGenerator::emit_TOTYPE(RaviFunctionDef *def, int A, int Bx,
int pc) {
emit_debug_trace(def, OP_RAVI_TOTYPE, pc);
// Load pointer to base
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
llvm::Value *rb = emit_gep_constant(def, Bx);
CreateCall3(def->builder, def->raviV_op_totypeF, def->L, ra, rb);
}
void RaviCodeGenerator::emit_TOINT(RaviFunctionDef *def, int A, int pc) {
// case OP_RAVI_TOINT: {
// lua_Integer j;

@ -25,6 +25,9 @@
This will hopefully eventually contain a Lua binding for LLVM.
*/
#if USE_DMR_C
#include <dmr_c.h>
#endif
#include <ravijit.h>
#include "ravi_llvmcodegen.h"
@ -175,6 +178,7 @@ struct MainFunctionHolder {
ravi::RaviJITFunction *func;
lua_CFunction compiled_func;
llvm::Value *arg1;
bool is_valid;
};
struct FunctionHolder {
@ -198,9 +202,11 @@ struct ModuleHolder {
ModuleHolder(const std::shared_ptr<ravi::RaviJITModule> &module) {
M = module;
//printf("ModuleHolder created\n");
// printf("ModuleHolder created\n");
}
~ModuleHolder() {
//printf("ModuleHolder destroyed\n");
}
~ModuleHolder() { /* printf("ModuleHolder destroyed\n");*/ }
};
struct PhiNodeHolder {
@ -238,7 +244,7 @@ static void alloc_LLVM_module(lua_State *L,
/* __gc for ModuleHolder */
static int collect_LLVM_module(lua_State *L) {
ModuleHolder *mh = check_LLVM_module(L, 1);
//printf("Module released: usecount %d\n", (int)mh->M.use_count());
// printf("Module released: usecount %d\n", (int)mh->M.use_count());
mh->~ModuleHolder();
return 0;
}
@ -319,6 +325,7 @@ static void alloc_LLVM_phinode(lua_State *L, llvm::PHINode *phi) {
h->phi = phi;
}
// Creates a new module to hold a Lua C Function
static MainFunctionHolder *alloc_LLVM_mainfunction(lua_State *L,
ravi::RaviJITState *jit,
llvm::FunctionType *type,
@ -333,6 +340,77 @@ static MainFunctionHolder *alloc_LLVM_mainfunction(lua_State *L,
auto module = std::make_shared<ravi::RaviJITModule>(G(L)->ravi_state->jit);
h->func = new ravi::RaviJITFunction(&h->compiled_func, module, type,
llvm::Function::ExternalLinkage, name);
h->is_valid = true;
return h;
}
static bool validate_has_luaCFunction_signature(MainFunctionHolder *h,
char *errormessage, int len) {
auto f = h->func->function();
if (!f) {
snprintf(errormessage, len, "Function was not found");
return false;
}
auto ftype = f->getFunctionType();
auto returnType = ftype->getReturnType();
if (!returnType->isIntegerTy()) {
snprintf(errormessage, len,
"Invalid return type in function: expected integer");
return false;
}
if (ftype->isVarArg()) {
// invalid
snprintf(errormessage, len,
"Invalid function: cannot be variable argument type");
return false;
}
if (ftype->getFunctionNumParams() != 1) {
// invalid
snprintf(errormessage, len,
"Invalid function: function must accept one argument (struct lua_State *) only");
return false;
}
auto paramType = ftype->getFunctionParamType(0);
if (!paramType->isPointerTy()) {
// invalid
snprintf(errormessage, len,
"Invalid function: argument is not a pointer to struct lua_State");
return false;
}
auto underLying = paramType->getPointerElementType();
if (!underLying->isStructTy()) {
// invalid
snprintf(errormessage, len,
"Invalid function: argument is not a pointer to struct lua_State");
return false;
}
if (!underLying->getStructName().startswith("struct.lua_State")) {
// invalid
snprintf(
errormessage, len,
"Invalid function: argument is not a pointer to struct lua_State");
return false;
}
return true;
}
// References an existing function in a Module
static MainFunctionHolder *alloc_LLVM_luaCfunction(
lua_State *L, const std::shared_ptr<ravi::RaviJITModule> &module,
const char *name) {
char error_message[128];
MainFunctionHolder *h =
(MainFunctionHolder *)lua_newuserdata(L, sizeof(MainFunctionHolder));
h->func = nullptr;
h->compiled_func = nullptr;
h->arg1 = nullptr;
raviL_getmetatable(L, LLVM_mainfunction);
lua_setmetatable(L, -2);
h->func = new ravi::RaviJITFunction(&h->compiled_func, module, name);
h->is_valid = validate_has_luaCFunction_signature(h, error_message, sizeof error_message);
if (!h->is_valid) {
luaL_argerror(L, 2, error_message);
}
return h;
}
@ -342,7 +420,7 @@ static int collect_LLVM_mainfunction(lua_State *L) {
if (builder->func) {
delete builder->func;
builder->func = nullptr;
//printf("collected function\n");
//printf("Collected MainFunctionHolder\n");
}
return 0;
}
@ -474,6 +552,7 @@ static llvm::Value *get_value(lua_State *L, int idx) {
Dump an LLVM object
*/
static int dump_content(lua_State *L) {
#if LLVM_VERSION_MAJOR < 5
TypeHolder *th = nullptr;
StructTypeHolder *sth = nullptr;
PointerTypeHolder *ph = nullptr;
@ -523,6 +602,7 @@ static int dump_content(lua_State *L) {
phi->phi->dump();
return 0;
}
#endif
return 0;
}
@ -624,6 +704,13 @@ static int context_new_lua_CFunction(lua_State *L) {
return 1;
}
static int context_new_module(lua_State *L) {
ContextHolder *context = check_LLVM_context(L, 1);
alloc_LLVM_module(L,
std::make_shared<ravi::RaviJITModule>(context->jitState));
return 1;
}
static int func_getmodule(lua_State *L) {
MainFunctionHolder *f = check_LLVM_mainfunction(L, 1);
alloc_LLVM_module(L, f->func->raviModule());
@ -646,6 +733,93 @@ static int module_newfunction(lua_State *L) {
return 1;
}
static int module_getfunction(lua_State *L) {
ModuleHolder *mh = check_LLVM_module(L, 1);
const char *name = luaL_checkstring(L, 2);
alloc_LLVM_luaCfunction(L, mh->M, name);
// TODO we should check that the function signature is correct
return 1;
}
enum {
MAX_ARGS = 50,
MAX_BUFFER = 4096
};
static int collect_args(lua_State *L, int tabindex, char *argv[], int maxargs,
char *buf, int buflen) {
char errormessage[128];
int len = lua_rawlen(L, tabindex);
if (len > maxargs) {
snprintf(errormessage, sizeof errormessage,
"Arguments exceed total count %d elements", maxargs);
luaL_argerror(L, 2, errormessage);
len = maxargs;
}
char *p = buf;
char *endp = buf + buflen;
int n = 0;
for (int i = 0; i < len; i++) {
lua_rawgeti(L, tabindex, i + 1);
size_t size = 0;
const char *argument = luaL_checklstring(L, -1, &size);
if (argument && size > 0) {
if (p + size + 1 >= endp) {
snprintf(errormessage, sizeof errormessage,
"Arguments exceed combined size of %d bytes", buflen);
luaL_argerror(L, 2, errormessage);
break;
}
strncpy(p, argument, size + 1);
argv[n] = p;
p += (size + 1);
n++;
}
}
assert(p <= endp);
return n;
}
static int module_compile_C(lua_State *L) {
ModuleHolder *mh = check_LLVM_module(L, 1);
const char *codebuffer = NULL; // luaL_checkstring(L, 2);
char *argv[MAX_ARGS + 1] = {NULL};
int argc = 0;
char buf[MAX_BUFFER + 1] = {0};
int guard = 0xfefefefe;
if (lua_istable(L, 2)) {
argc = collect_args(L, 2, argv, MAX_ARGS, buf, sizeof buf);
assert(argc >= 0 && argc <= MAX_ARGS);
assert(argv[MAX_ARGS] == NULL);
assert(guard == 0xfefefefe);
if (lua_isstring(L, 3)) { codebuffer = lua_tostring(L, 3); }
}
else if (lua_isstring(L, 2)) {
codebuffer = lua_tostring(L, 2);
}
#if USE_DMR_C
if (dmrC_llvmcompile(argc, argv, llvm::wrap(mh->M->module()), codebuffer)) {
lua_pushboolean(L, true);
}
else {
lua_pushboolean(L, false);
}
#else
(void)mh;
lua_pushboolean(L, false);
#endif
return 1;
}
static int module_generate_code(lua_State *L) {
ModuleHolder *mh = check_LLVM_module(L, 1);
mh->M->runpasses();
mh->M->finalize();
return 0;
}
static int context_new_basicblock(lua_State *L) {
ContextHolder *context = check_LLVM_context(L, 1);
const char *name = luaL_checkstring(L, 2);
@ -709,6 +883,8 @@ static int irbuilder_condbranch(lua_State *L) {
static int func_compile(lua_State *L) {
MainFunctionHolder *f = check_LLVM_mainfunction(L, 1);
if (!f->is_valid) return 0;
if (!f->func->function()) return 0;
if (!f->compiled_func) {
f->func->raviModule()->runpasses();
f->func->raviModule()->finalize();
@ -1221,7 +1397,9 @@ static const luaL_Reg structtype_methods[] = {{"setbody", struct_add_members},
{NULL, NULL}};
static const luaL_Reg module_methods[] = {
{"newfunction", module_newfunction}, {"dump", dump_content}, {NULL, NULL}};
{"newfunction", module_newfunction}, {"getfunction", module_getfunction},
{"compileC", module_compile_C}, {"dump", dump_content},
{"generatecode", module_generate_code}, {NULL, NULL}};
static const luaL_Reg main_function_methods[] = {
{"appendblock", func_append_basicblock},
@ -1248,6 +1426,7 @@ static const luaL_Reg context_methods[] = {
{"basicblock", context_new_basicblock},
{"intconstant", context_intconstant},
{"nullconstant", context_nullconstant},
{"newmodule", context_new_module},
{NULL, NULL}};
static const luaL_Reg phi_methods[] = {{"addincoming", phi_addincoming},

@ -97,18 +97,13 @@ void RaviCodeGenerator::emit_LEN(RaviFunctionDef *def, int A, int B, int pc) {
// b) we know the key is an integer
void RaviCodeGenerator::emit_SETTABLE_I(RaviFunctionDef *def, int A, int B,
int C, int pc) {
// This is broken as we need to handle meta methods etc.
lua_assert(false);
#if 0
emit_debug_trace(def, OP_RAVI_SETTABLE_I, pc);
bool traced = emit_debug_trace(def, OP_RAVI_SETTABLE_I, pc);
if (!traced) emit_update_savedpc(def, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
llvm::Value *rb = emit_gep_register_or_constant(def, B);
llvm::Value *rc = emit_gep_register_or_constant(def, C);
llvm::Instruction *t = emit_load_reg_h(def, ra);
llvm::Instruction *key = emit_load_reg_i(def, rb);
CreateCall4(def->builder, def->luaH_setintF, def->L, t, key, rc);
#endif
CreateCall4(def->builder, def->raviV_settable_iF, def->L, ra, rb, rc);
}
// R(A)[RK(B)] := RK(C)
@ -208,6 +203,17 @@ void RaviCodeGenerator::emit_GETTABLE_SK(RaviFunctionDef *def, int A, int B,
// b) we know the key is an integer
void RaviCodeGenerator::emit_GETTABLE_I(RaviFunctionDef *def, int A, int B,
int C, int pc) {
// changed to that target may not be a table
bool traced = emit_debug_trace(def, OP_RAVI_GETTABLE_I, pc);
if (!traced) emit_update_savedpc(def, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
llvm::Value *rb = emit_gep_register(def, B);
llvm::Value *rc = emit_gep_register_or_constant(def, C);
CreateCall4(def->builder, def->raviV_gettable_iF, def->L, rb, rc, ra);
// FIXME following is no longer valid as RB may not be a table
// TValue *rb = RB(i);
// TValue *rc = RKC(i);
// lua_Integer idx = ivalue(rc);
@ -224,49 +230,49 @@ void RaviCodeGenerator::emit_GETTABLE_I(RaviFunctionDef *def, int A, int B,
// Protect(luaV_finishget(L, rb, rc, ra, v));
//}
emit_debug_trace(def, OP_RAVI_GETTABLE_I, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
llvm::Value *rb = emit_gep_register(def, B);
llvm::Value *rc = emit_gep_register_or_constant(def, C);
llvm::Instruction *key = emit_load_reg_i(def, rc);
llvm::Instruction *t = emit_load_reg_h(def, rb);
llvm::Value *data = emit_table_get_array(def, t);
llvm::Value *len = emit_table_get_arraysize(def, t);
// As Lua arrays are 1 based we need to subtract by 1
llvm::Value *key_minus_1 =
def->builder->CreateSub(key, def->types->kluaInteger[1]);
// As len is unsigned int we need to truncate
llvm::Value *ukey =
def->builder->CreateTrunc(key_minus_1, def->types->C_intT);
// Do an unsigned comparison with length
llvm::Value *cmp = def->builder->CreateICmpULT(ukey, len);
llvm::BasicBlock *then_block =
llvm::BasicBlock::Create(def->jitState->context(), "if.in.range", def->f);
llvm::BasicBlock *else_block =
llvm::BasicBlock::Create(def->jitState->context(), "if.not.in.range");
llvm::BasicBlock *end_block =
llvm::BasicBlock::Create(def->jitState->context(), "if.end");
def->builder->CreateCondBr(cmp, then_block, else_block);
def->builder->SetInsertPoint(then_block);
// Key is in range so array access possible
llvm::Value *value1 = def->builder->CreateGEP(data, ukey);
def->builder->CreateBr(end_block);
// Out of range so fall back to luaH_getint()
def->f->getBasicBlockList().push_back(else_block);
def->builder->SetInsertPoint(else_block);
llvm::Value *value2 = CreateCall2(def->builder, def->luaH_getintF, t, key);
def->builder->CreateBr(end_block);
// Merge results from the two branches above
def->f->getBasicBlockList().push_back(end_block);
def->builder->SetInsertPoint(end_block);
llvm::PHINode *phi = def->builder->CreatePHI(def->types->pTValueT, 2);
phi->addIncoming(value1, then_block);
phi->addIncoming(value2, else_block);
emit_finish_GETTABLE(def, phi, t, ra, rb, rc);
//emit_debug_trace(def, OP_RAVI_GETTABLE_I, pc);
//emit_load_base(def);
//llvm::Value *ra = emit_gep_register(def, A);
//llvm::Value *rb = emit_gep_register(def, B);
//llvm::Value *rc = emit_gep_register_or_constant(def, C);
//llvm::Instruction *key = emit_load_reg_i(def, rc);
//llvm::Instruction *t = emit_load_reg_h(def, rb);
//llvm::Value *data = emit_table_get_array(def, t);
//llvm::Value *len = emit_table_get_arraysize(def, t);
//// As Lua arrays are 1 based we need to subtract by 1
//llvm::Value *key_minus_1 =
// def->builder->CreateSub(key, def->types->kluaInteger[1]);
//// As len is unsigned int we need to truncate
//llvm::Value *ukey =
// def->builder->CreateTrunc(key_minus_1, def->types->C_intT);
//// Do an unsigned comparison with length
//llvm::Value *cmp = def->builder->CreateICmpULT(ukey, len);
//llvm::BasicBlock *then_block =
// llvm::BasicBlock::Create(def->jitState->context(), "if.in.range", def->f);
//llvm::BasicBlock *else_block =
// llvm::BasicBlock::Create(def->jitState->context(), "if.not.in.range");
//llvm::BasicBlock *end_block =
// llvm::BasicBlock::Create(def->jitState->context(), "if.end");
//def->builder->CreateCondBr(cmp, then_block, else_block);
//def->builder->SetInsertPoint(then_block);
//// Key is in range so array access possible
//llvm::Value *value1 = def->builder->CreateGEP(data, ukey);
//def->builder->CreateBr(end_block);
//// Out of range so fall back to luaH_getint()
//def->f->getBasicBlockList().push_back(else_block);
//def->builder->SetInsertPoint(else_block);
//llvm::Value *value2 = CreateCall2(def->builder, def->luaH_getintF, t, key);
//def->builder->CreateBr(end_block);
//// Merge results from the two branches above
//def->f->getBasicBlockList().push_back(end_block);
//def->builder->SetInsertPoint(end_block);
//llvm::PHINode *phi = def->builder->CreatePHI(def->types->pTValueT, 2);
//phi->addIncoming(value1, then_block);
//phi->addIncoming(value2, else_block);
//emit_finish_GETTABLE(def, phi, t, ra, rb, rc);
}
void RaviCodeGenerator::emit_finish_GETTABLE(RaviFunctionDef *def,
@ -760,12 +766,12 @@ void RaviCodeGenerator::emit_SETUPVAL(RaviFunctionDef *def, int A, int B,
llvm::Value *type = emit_load_type(def, v);
llvm::Value *is_collectible =
def->builder->CreateAnd(type, def->types->kInt[BIT_ISCOLLECTABLE]);
def->builder->CreateAnd(type, def->types->kByte[BIT_ISCOLLECTABLE]);
llvm::Value *value = emit_gep_upval_value(def, upval);
llvm::Value *cmp = def->builder->CreateICmpNE(v, value, "v.ne.value");
llvm::Value *tobool = def->builder->CreateICmpEQ(
is_collectible, def->types->kInt[0], "not.collectible");
is_collectible, def->types->kByte[0], "not.collectible");
llvm::Value *orcond =
def->builder->CreateOr(cmp, tobool, "v.ne.value.or.not.collectible");

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save