merge changes from master

ravi-distro
Dibyendu Majumdar 4 years ago
commit 3c7828439f

@ -21,3 +21,7 @@ script:
- cd $TRAVIS_BUILD_DIR/build && $TRAVIS_BUILD_DIR/cmake-3.4.0-Linux-x86_64/bin/cmake -DCMAKE_BUILD_TYPE=Debug -DLLVM_DIR=$TRAVIS_BUILD_DIR/clang+llvm-6.0.1-x86_64-linux-gnu-ubuntu-16.04/lib/cmake/llvm -G "Unix Makefiles" -DLLVM_JIT=ON ..
- cd $TRAVIS_BUILD_DIR/build && make
- cd $TRAVIS_BUILD_DIR/lua-tests && sh ./run_travis_tests.sh $TRAVIS_BUILD_DIR/build/ravi
- mkdir $TRAVIS_BUILD_DIR/buildmir
- cd $TRAVIS_BUILD_DIR/buildmir && $TRAVIS_BUILD_DIR/cmake-3.4.0-Linux-x86_64/bin/cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" -DMIR_JIT=ON ..
- cd $TRAVIS_BUILD_DIR/buildmir && make
- cd $TRAVIS_BUILD_DIR/lua-tests && sh ./run_travis_tests.sh $TRAVIS_BUILD_DIR/buildmir/ravi

@ -12,64 +12,86 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
# By default JIT is OFF
option(LLVM_JIT "Controls whether LLVM JIT compilation will be enabled, default is OFF" OFF)
option(OMR_JIT "Controls whether NanoJIT compilation will be enabled, default is OFF" OFF)
option(MIR_JIT "Controls whether MIR JIT compilation will be enabled, default is OFF" OFF)
option(STATIC_BUILD "Build static version of Ravi, default is OFF" OFF)
option(COMPUTED_GOTO "Controls whether the interpreter switch will use computed gotos on gcc/clang, default is ON" ON)
option(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" ON)
option(LTESTS "Controls whether ltests are enabled in Debug mode; note requires Debug build" ON)
if (LLVM_JIT AND OMR_JIT)
if (LLVM_JIT AND OMR_JIT AND MIR_JIT)
message(FATAL_ERROR
"Both LLVM_JIT and OMR_JIT cannot be set to ON at the same time")
endif()
"LLVM_JIT, OMR_JIT and MIR_IT cannot all be set to ON at the same time")
endif ()
if (LLVM_JIT OR OMR_JIT)
if (LLVM_JIT OR OMR_JIT OR MIR_JIT)
# ASM VM is in development and not compatible with anything yet
set(ASM_VM OFF)
endif ()
if (MIR_JIT)
if (MSVC OR WIN32)
message(FATAL_ERROR "MIR_JIT is not supported when using MSVC and/or WIN32")
endif()
if (NOT (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)"))
message(FATAL_ERROR "MIR_JIT is only supported on X86-64 platforms")
endif()
set(LLVM_JIT OFF)
set(OMR_JIT OFF)
set(STATIC_BUILD ON)
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
set(STATIC_BUILD ON)
# LTESTS messes with global state and breaks the ASMVM dispatch table
# LTESTS messes with global state and breaks the ASMVM dispatch table
set(LTESTS OFF)
# Not compatible with JIT modes
set(LLVM_JIT OFF)
set(OMR_JIT OFF)
endif()
set(MIR_JIT OFF)
endif ()
if (STATIC_BUILD)
message(STATUS "STATIC library build enabled")
else()
else ()
message(STATUS "DYNAMIC library build enabled")
endif()
endif ()
if (LLVM_JIT)
find_package(LLVM REQUIRED CONFIG)
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
include_directories(${LLVM_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})
message(STATUS "LLVM enabled")
# We also need to define USE_LLVM when compiling code
# but rather than setting globally we set this when building the
# library
endif()
endif ()
if (OMR_JIT)
find_package(OMRJIT REQUIRED)
include_directories(${OMRJIT_INCLUDE_DIRS})
add_definitions(-DUSE_OMRJIT)
endif()
message(STATUS "OMRJIT enabled")
endif ()
if (MIR_JIT)
add_subdirectory(mir)
include_directories(mir)
include_directories(mir/c2mir)
set(MIRJIT_LIBRARIES c2mir)
add_definitions(-DUSE_MIRJIT)
message(STATUS "MIRJIT enabled")
endif ()
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 OMR_JIT)
message(WARNING "LLVM will not be enabled; specify -DLLVM_JIT=ON to enable")
endif()
endif ()
if (MSVC)
set(CMAKE_C_FLAGS_DEBUG "/Od /D_DEBUG /MDd /Zi /RTC1 /EHsc")
@ -106,11 +128,11 @@ elseif ((CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang
# set(SANITIZER_FLAGS "-fsanitize=address")
set(LUA_COMPAT_FLAGS "-DLUA_COMPAT_5_2 -DLUA_COMPAT_5_1")
set(CMAKE_C_FLAGS "-std=c99 -DNDEBUG -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_DEBUG "${SANITIZER_FLAGS} -UNDEBUG -fno-omit-frame-pointer -std=c99 -O0 -g3 -Wall -Wextra ${LUA_COMPAT_FLAGS} ${OS_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE "-std=c99 -DNDEBUG -O2 -fomit-frame-pointer -Wall -Wextra -Winline ${LUA_COMPAT_FLAGS} ${OS_FLAGS}")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${SANITIZER_FLAGS} -DNDEBUG -std=c99 -O2 -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_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_DEBUG "${SANITIZER_FLAGS} -UNDEBUG -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_RELEASE "-fno-rtti -DNDEBUG -O2 -fomit-frame-pointer -Wall -Wno-sign-compare -Winline -std=c++11 -fno-exceptions ${LUA_COMPAT_FLAGS} ${OS_FLAGS}")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${SANITIZER_FLAGS} -DNDEBUG -fno-rtti -O2 -g3 -Wall -Wno-sign-compare -std=c++11 -fno-exceptions ${LUA_COMPAT_FLAGS} ${OS_FLAGS}")
elseif (APPLE)
@ -123,7 +145,7 @@ elseif (APPLE)
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_RELEASE "-fno-rtti -DNDEBUG -O2 -Wall -Wno-sign-compare -std=c++11 -fno-exceptions ${LUA_COMPAT_FLAGS} -DLUA_USE_MACOSX")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-fno-rtti -DNDEBUG -O2 -g3 -Wall -Wno-sign-compare -std=c++11 -fno-exceptions ${LUA_COMPAT_FLAGS} -DLUA_USE_MACOSX")
else()
else ()
message(FATAL_ERROR "Unsupported platform")
endif ()
@ -137,71 +159,74 @@ if (NOT LTESTS)
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
# 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 )
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()
else ()
set(VMMODE elfasm)
endif()
# This macro runs the buildvm command to generate the VM code
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}
)
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)
# 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)
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} )
# Generate the ravi_bcdef.h header file
add_buildvm_target(${ASMVM_DEFS} bcdef ${LJLIB_C})
SET (ASMVM_DEPS
${ASMVM_SRC}
${ASMVM_DEFS}
)
endif()
SET(ASMVM_DEPS
${ASMVM_SRC}
${ASMVM_DEFS}
)
endif ()
# define LLVM JIT compiler sources
# define JIT compiler sources
if (LLVM_JIT)
set(LLVM_JIT_SRCS src/ravi_llvmjit.cpp src/ravi_llvmtypes.cpp
src/ravi_llvmcodegen.cpp src/ravi_llvmforprep.cpp src/ravi_llvmcomp.cpp
src/ravi_llvmreturn.cpp src/ravi_llvmload.cpp src/ravi_llvmforloop.cpp
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)
src/ravi_llvmarith2.cpp src/ravi_llvmtforcall.cpp src/ravi_llvmrest.cpp)
elseif (OMR_JIT)
set(OMR_JIT_SRCS src/ravi_omrjit.c src/ravi_omrjitapi.c)
else()
elseif (MIR_JIT)
set(MIR_JIT_SRCS src/ravi_mirjit.c)
else ()
set(NO_JIT_SRCS src/ravi_nojit.c)
endif()
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/ravi_membuf.c
src/lvm.c src/lzio.c src/ravijit.cpp src/ltests.c src/ravi_profile.c
src/ravi_ast_parse.c src/ravi_ast_print.c src/ravi_ast_typecheck.c src/ravi_membuf.c
src/ravi_jitshared.c src/bit.c src/ravi_alloc.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")
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()
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)
@ -209,6 +234,7 @@ set(LUA_LIB_SRCS src/lauxlib.c src/lbaselib.c src/lbitlib.c src/lcorolib.c src/l
file(GLOB RAVI_HEADERS "${PROJECT_SOURCE_DIR}/include/*.h")
set(LUA_HEADERS include/lua.h include/luaconf.h include/lualib.h include/lauxlib.h)
# Misc setup
if (MSVC OR APPLE)
source_group("Ravi Headers" FILES ${RAVI_HEADERS})
source_group("Ravi Source Files" FILES ${LUA_CORE_SRCS} ${LUA_LIB_SRCS}
@ -223,118 +249,135 @@ elseif (NOT WIN32)
set(EXTRA_LIBRARIES m dl readline)
endif ()
# Additional stuff for dmrC
if (CMAKE_COMPILER_IS_GNUCC)
execute_process(COMMAND ${CMAKE_C_COMPILER} --print-file-name=
OUTPUT_VARIABLE GCC_BASE OUTPUT_STRIP_TRAILING_WHITESPACE)
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)
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} )
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/expression.c
dmr_c/src/evaluate.c
dmr_c/src/expand.c
dmr_c/src/inline.c
dmr_c/src/lib.c
dmr_c/src/linearize.c
dmr_c/src/liveness.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/symbol.c
dmr_c/src/walksymbol.c
src/ravi_dmrc_parsesymbols.c
)
message(STATUS "GCC_BASE_DIR : " ${GCC_BASE})
message(STATUS "MULTIARCH_TRIPLET : " ${MULTIARCH_TRIPLET})
endif ()
# Common stuff we need even if we don't use dmrC.
set(DMR_C_HEADERS_COMMON
dmr_c/src/allocate.h
dmr_c/src/port.h
dmr_c/src/ptrlist.h
)
set(DMR_C_SRCS_COMMON
dmr_c/src/allocate.c
dmr_c/src/ptrlist.c
)
# dmrC Optional sources
set(DMR_C_SRCS_OPT
dmr_c/src/builtin.c
dmr_c/src/char.c
dmr_c/src/expression.c
dmr_c/src/evaluate.c
dmr_c/src/expand.c
dmr_c/src/inline.c
dmr_c/src/lib.c
dmr_c/src/linearize.c
dmr_c/src/liveness.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/scope.c
dmr_c/src/show-parse.c
dmr_c/src/symbol.c
dmr_c/src/walksymbol.c
src/ravi_dmrc_parsesymbols.c
)
set(DMR_C_HEADERS_OPT
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/scope.h
dmr_c/src/symbol.h
dmr_c/src/target.h
dmr_c/src/token.h
dmr_c/src/walksymbol.h
)
set(EMBEDDED_DMRC ON)
if (LLVM_JIT)
set(DMR_C_JIT_SRCS
dmr_c/llvm-backend/sparse-llvm.c
)
dmr_c/llvm-backend/sparse-llvm.c
)
set(DMR_C_JIT_HEADERS
dmr_c/llvm-backend/dmr_c.h
)
dmr_c/llvm-backend/dmr_c.h
)
include_directories("${PROJECT_SOURCE_DIR}/dmr_c/llvm-backend")
set(DMR_C_HEADERS ${DMR_C_HEADERS_OPT} ${DMR_C_HEADERS_COMMON})
set(DMR_C_SRCS ${DMR_C_SRCS_OPT} ${DMR_C_SRCS_COMMON})
elseif (OMR_JIT)
set(DMR_C_JIT_SRCS
dmr_c/omrjit-backend/sparse-omrjit.c
)
dmr_c/omrjit-backend/sparse-omrjit.c
)
set(DMR_C_JIT_HEADERS
dmr_c/omrjit-backend/dmr_c.h
)
dmr_c/omrjit-backend/dmr_c.h
)
include_directories("${PROJECT_SOURCE_DIR}/dmr_c/omrjit-backend")
set(DMR_C_HEADERS ${DMR_C_HEADERS_OPT} ${DMR_C_HEADERS_COMMON})
set(DMR_C_SRCS ${DMR_C_SRCS_OPT} ${DMR_C_SRCS_COMMON})
else()
set(DMR_C_JIT_HEADERS
dmr_c/null-backend/dmr_c.h
)
include_directories("${PROJECT_SOURCE_DIR}/dmr_c/null-backend")
endif()
# Omit all dmrC stuff except for what we need for the parser
set(DMR_C_HEADERS ${DMR_C_HEADERS_COMMON})
set(DMR_C_SRCS ${DMR_C_SRCS_COMMON})
set(EMBEDDED_DMRC OFF)
endif ()
# IDE stuff
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()
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
X86CodeGen
X86AsmParser
X86Disassembler
X86AsmPrinter
X86Desc
X86Info
X86Utils
)
set(LLVM_LIBS_PROCESSOR
X86CodeGen
X86AsmParser
X86Disassembler
X86Desc
X86Info
X86Utils
)
if (${LLVM_PACKAGE_VERSION} VERSION_LESS "9.0.0")
list(APPEND LLVM_LIBS_PROCESSOR X86AsmPrinter)
endif ()
elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "arm")
set(LLVM_LIBS_PROCESSOR
ARMCodeGen
ARMAsmParser
ARMDisassembler
ARMAsmPrinter
ARMDesc
ARMInfo
)
endif()
set(LLVM_LIBS_PROCESSOR
ARMCodeGen
ARMAsmParser
ARMDisassembler
ARMAsmPrinter
ARMDesc
ARMInfo
)
endif ()
llvm_map_components_to_libnames(LLVM_LIBS
Analysis
AsmParser
@ -362,113 +405,131 @@ endif ()
if (NOT STATIC_BUILD)
set(LIBRAVI_BUILD_TYPE SHARED)
endif()
else()
set(LIBRAVI_BUILD_TYPE STATIC)
endif ()
# Name library differently based on JIT backend
if (LLVM_JIT)
set (LIBRAVI_NAME libravi)
set(LIBRAVI_NAME libravillvm)
elseif (OMR_JIT)
set (LIBRAVI_NAME libravi)
else()
set (LIBRAVI_NAME libravi)
endif()
set(LIBRAVI_NAME libravilomr)
elseif (MIR_JIT)
set(LIBRAVI_NAME libravimir)
else ()
set(LIBRAVI_NAME libravinojit)
endif ()
#Main library
add_library(${LIBRAVI_NAME} ${LIBRAVI_BUILD_TYPE}
add_library(${LIBRAVI_NAME} ${LIBRAVI_BUILD_TYPE}
${RAVI_HEADERS}
${LUA_LIB_SRCS}
${LUA_LIB_SRCS}
${LUA_CORE_SRCS}
${LLVM_JIT_SRCS}
${LLVM_JIT_SRCS}
${OMR_JIT_SRCS}
${MIR_JIT_SRCS}
${NO_JIT_SRCS}
${DMR_C_HEADERS}
${DMR_C_SRCS}
${DMR_C_JIT_SRCS}
${ASMVM_DEPS}
)
if (EMBEDDED_DMRC)
set(DMRC_DEF "USE_DMR_C=1")
endif ()
if (NOT STATIC_BUILD)
if (WIN32)
# enable DLL export
set_target_properties(${LIBRAVI_NAME} PROPERTIES DEFINE_SYMBOL "LUA_BUILD_AS_DLL")
else()
set_target_properties(${LIBRAVI_NAME} PROPERTIES PREFIX "")
# enable DLL export
set_target_properties(${LIBRAVI_NAME} PROPERTIES DEFINE_SYMBOL "LUA_BUILD_AS_DLL")
else ()
set_target_properties(${LIBRAVI_NAME} PROPERTIES PREFIX "")
endif ()
endif()
else()
set_target_properties(${LIBRAVI_NAME} PROPERTIES PREFIX "")
endif ()
if (LLVM_JIT)
set_target_properties(${LIBRAVI_NAME} PROPERTIES COMPILE_DEFINITIONS "USE_LLVM=1")
endif()
message(STATUS "Setting USE_LLVM=1")
set_target_properties(${LIBRAVI_NAME} PROPERTIES COMPILE_DEFINITIONS "USE_LLVM=1 ${DMRC_DEF}")
endif ()
if (OMR_JIT)
set_target_properties(${LIBRAVI_NAME} PROPERTIES COMPILE_DEFINITIONS "USE_OMRJIT=1")
endif()
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} ${OMRJIT_LIBRARIES})
set_target_properties(${LIBRAVI_NAME} PROPERTIES COMPILE_DEFINITIONS "USE_OMRJIT=1 ${DMRC_DEF}")
endif ()
if (MIR_JIT)
set_target_properties(${LIBRAVI_NAME} PROPERTIES COMPILE_DEFINITIONS "USE_MIRJIT=1")
endif ()
target_link_libraries(${LIBRAVI_NAME} ${EXTRA_LIBRARIES} ${LLVM_LIBS} ${OMRJIT_LIBRARIES} ${MIRJIT_LIBRARIES})
# Main Ravi executable
add_executable(ravi src/lua.c)
if (LLVM_JIT)
set_target_properties(ravi PROPERTIES COMPILE_DEFINITIONS "USE_LLVM=1")
endif()
endif ()
if (OMR_JIT)
set_target_properties(ravi PROPERTIES COMPILE_DEFINITIONS "USE_OMRJIT=1")
endif ()
if (MIR_JIT)
set_target_properties(ravi PROPERTIES COMPILE_DEFINITIONS "USE_MIRJIT=1")
endif ()
if (EMBEDDED_DMRC)
set_target_properties(ravi PROPERTIES COMPILE_DEFINITIONS "USE_DMR_C=1")
endif()
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}
${DMR_C_HEADERS}
${DMR_C_SRCS}
${DMR_C_JIT_SRCS}
src/ravi_nojit.c)
set(NOJIT_RAVI_SRCS
${RAVI_HEADERS}
${LUA_LIB_SRCS}
${LUA_CORE_SRCS}
${DMR_C_HEADERS}
${DMR_C_SRCS}
${DMR_C_JIT_SRCS}
src/ravi_nojit.c)
if (NOT ASM_VM)
set(RAVI_STATICEXEC_TARGET ravi_s)
# We always build a static library without JIT so that
# we can create some default executables
add_library(libravinojit_static
${NOJIT_RAVI_SRCS})
set_target_properties(libravinojit_static PROPERTIES PREFIX "") # As we already prefix with lib
target_link_libraries(libravinojit_static ${EXTRA_LIBRARIES})
# Create a simple NoJIT version of statically linked ravi
# This is sometimes useful in other projects that just need a Lua commandline
# but do not care about the shared library
add_executable(ravi_s
src/lua.c)
target_link_libraries(ravi_s libravinojit_static)
# Ravi VSCode Debug adapter
set(RAVI_DEBUGGER_TARGET ravidebug)
add_executable(${RAVI_DEBUGGER_TARGET}
vscode-debugger/src/ravidebug.c
vscode-debugger/src/json.c
vscode-debugger/src/protocol.c)
target_link_libraries(${RAVI_DEBUGGER_TARGET} libravinojit_static)
# Tests for VSCode Debug Adapter
add_executable(testravidebug
vscode-debugger/src/testravidebug.c
vscode-debugger/src/json.c
vscode-debugger/src/protocol.c)
target_link_libraries(testravidebug libravinojit_static)
add_test(TestRaviDebug testravidebug)
add_executable(test_vm tests/test_vm.c)
target_link_libraries(test_vm ${LIBRAVI_NAME})
add_test(TestVM test_vm)
else()
# Simple VM tests
add_executable(test_asmvm tests/test_asmvm.c)
target_link_libraries(test_asmvm ${LIBRAVI_NAME})
add_test(TestVM test_asmvm)
endif()
set(RAVI_STATICEXEC_TARGET ravi_s)
# We always build a static library without JIT so that
# we can create some default executables
add_library(libravinojit_static
${NOJIT_RAVI_SRCS})
set_target_properties(libravinojit_static PROPERTIES PREFIX "") # As we already prefix with lib
target_link_libraries(libravinojit_static ${EXTRA_LIBRARIES})
# Create a simple NoJIT version of statically linked ravi
# This is sometimes useful in other projects that just need a Lua commandline
# but do not care about the shared library
add_executable(ravi_s
src/lua.c)
target_link_libraries(ravi_s libravinojit_static)
# Ravi VSCode Debug adapter
set(RAVI_DEBUGGER_TARGET ravidebug)
add_executable(${RAVI_DEBUGGER_TARGET}
vscode-debugger/src/ravidebug.c
vscode-debugger/src/json.c
vscode-debugger/src/protocol.c)
target_link_libraries(${RAVI_DEBUGGER_TARGET} libravinojit_static)
# Tests for VSCode Debug Adapter
add_executable(testravidebug
vscode-debugger/src/testravidebug.c
vscode-debugger/src/json.c
vscode-debugger/src/protocol.c)
target_link_libraries(testravidebug libravinojit_static)
add_test(TestRaviDebug testravidebug)
add_executable(test_vm tests/test_vm.c)
target_link_libraries(test_vm ${LIBRAVI_NAME})
add_test(TestVM test_vm)
else ()
# Simple VM tests
add_executable(test_asmvm tests/test_asmvm.c)
target_link_libraries(test_asmvm ${LIBRAVI_NAME})
add_test(TestVM test_asmvm)
endif ()
install(FILES ${LUA_HEADERS}
DESTINATION include/ravi)

@ -1,5 +1,23 @@
Most of Ravi is under MIT License
There are components that are under GPL - please see relevant
source files. These are optional components that are part of the
libgccjit implementation of the JIT compiler. You can remove these
components if you do not want GPL license.
/******************************************************************************
* Copyright (C) 1994-2019 Lua.org, PUC-Rio.
* Portions Copyright (C) 2015-2020 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.
******************************************************************************/

@ -48,7 +48,7 @@ TO_LIB= libravinojit.a
# Lua version and release.
V= 5.3
R= $V.4
R= $V.5
# Targets start here.
all: $(PLAT)

@ -33,12 +33,14 @@ Features
* Compatibility with Lua 5.3 (see Compatibility section below)
* `LLVM <http://www.llvm.org/>`_ powered JIT compiler
* `Eclipse OMR <https://github.com/dibyendumajumdar/nj>`_ powered JIT compiler
* New (wip) small JIT backend based on `MIR <https://github.com/vnmakarov/mir>`_; only Linux and x86-64 supported.
* Built-in C pre-processor, parser and JIT compiler
* A `distribution with batteries <https://github.com/dibyendumajumdar/Suravi>`_.
Documentation
=============
* For the Lua extensions in Ravi see the `Reference Manual <https://the-ravi-programming-language.readthedocs.io/en/latest/ravi-reference.html>`_.
* `MIR JIT Build instructions <https://the-ravi-programming-language.readthedocs.io/en/latest/ravi-mir-instructions.html>`_.
* `OMR JIT Build instructions <https://the-ravi-programming-language.readthedocs.io/en/latest/ravi-omr-instructions.html>`_.
* `LLVM JIT Build instructions <https://the-ravi-programming-language.readthedocs.io/en/latest/ravi-llvm-instructions.html>`_.
* Also see `Ravi Documentation <http://the-ravi-programming-language.readthedocs.org/en/latest/index.html>`_.
@ -48,6 +50,7 @@ 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>`_.
* A `patch for Lua 5.3 <http://lua-users.org/lists/lua-l/2020-01/msg00004.html>`_ implements the 'defer' statement.
Compatibility with Lua
======================
@ -91,10 +94,15 @@ History
* 2018
- Implemented Eclipse OMR JIT backend
- Created `Ravi with batteries <https://github.com/dibyendumajumdar/Suravi>`_.
* 2019 (Plan)
- New parser, type checker and code generator
- Release Ravi 1.0
* 2019
- `New parser, type checker for Ravi <https://the-ravi-programming-language.readthedocs.io/en/latest/ravi-new-parser-codegenerator.html>`_ - work in progress
- New language feature - `defer` statement
- New JIT backend `MIR <https://github.com/vnmakarov/mir>`_.
* 2020 (Plan)
- New optimizing byte code generator based on new parser / type checker
- Ravi 1.0 release
License
=======
MIT License for LLVM version.
MIT License

@ -0,0 +1,5 @@
rmdir /s llvm8
mkdir llvm8
cd llvm8
cmake -DCMAKE_INSTALL_PREFIX=c:\Software\ravi -G "Visual Studio 15 2017 Win64" -DCMAKE_BUILD_TYPE=Release -DLLVM_JIT=ON -DLLVM_DIR=c:\Software\llvm801\lib\cmake\llvm ..
cd ..

@ -0,0 +1,5 @@
rmdir /s llvm9d
mkdir llvm9d
cd llvm9d
cmake -DCMAKE_INSTALL_PREFIX=c:\Software\ravi -G "Visual Studio 15 2017 Win64" -DLLVM_JIT=ON -DLLVM_DIR=c:\Software\llvm900\lib\cmake\llvm ..
cd ..

@ -0,0 +1,6 @@
rmdir /s llvm9r
mkdir llvm9r
cd llvm9r
rem cmake -DCMAKE_INSTALL_PREFIX=c:\Software\ravi -G "Visual Studio 15 2017 Win64" -DLLVM_JIT=ON -DLLVM_DIR=c:\Software\llvm900r\lib\cmake\llvm ..
cmake -DCMAKE_INSTALL_PREFIX=c:\Software\ravi -G "Visual Studio 16 2019" -DLLVM_JIT=ON -DLLVM_DIR=c:\Software\llvm900r\lib\cmake\llvm ..
cd ..

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

@ -0,0 +1,16 @@
find_path(MIRJIT_INCLUDE_DIR c2mir.h
PATHS
c:/Software/mir/include/mir
~/Software/mir/include/mir
NO_DEFAULT_PATH
)
find_library(MIRJIT_LIBRARY
NAMES libc2mir.a
PATHS
c:/Software/mir/lib
~/Software/mir/lib
)
set( MIRJIT_INCLUDE_DIRS "${MIRJIT_INCLUDE_DIR}" )
set( MIRJIT_LIBRARIES "${MIRJIT_LIBRARY}" )

@ -929,11 +929,11 @@ static JIT_NodeRef is_neq_zero(struct dmr_C *C, struct function *fn, JIT_NodeRef
break;
case JIT_Double:
cond = JIT_CreateNode2C(OP_dcmpne, value, JIT_ZeroValue(fn->injector, JIT_Double));
cond = JIT_CreateNode2C(OP_dcmpneu, value, JIT_ZeroValue(fn->injector, JIT_Double));
break;
case JIT_Float:
cond = JIT_CreateNode2C(OP_fcmpne, value, JIT_ZeroValue(fn->injector, JIT_Float));
cond = JIT_CreateNode2C(OP_fcmpneu, value, JIT_ZeroValue(fn->injector, JIT_Float));
break;
default:
fprintf(stderr, "Cannot construct a zero object of JIT type %d\n", value_type);
@ -1121,9 +1121,9 @@ static JIT_NodeRef output_op_compare(struct dmr_C *C, struct function *fn, struc
break;
case OP_SET_NE:
if (op_type == JIT_Double)
target = JIT_CreateNode2C(OP_dcmpne, lhs, rhs);
target = JIT_CreateNode2C(OP_dcmpneu, lhs, rhs);
else if (op_type == JIT_Float)
target = JIT_CreateNode2C(OP_fcmpne, lhs, rhs);
target = JIT_CreateNode2C(OP_fcmpneu, lhs, rhs);
else if (op_type == JIT_Int64)
target = JIT_CreateNode2C(OP_lcmpne, lhs, rhs);
else if (op_type == JIT_Int32)
@ -2111,6 +2111,10 @@ static bool JIT_ILBuilderImpl(JIT_ILInjectorRef injector, void *userdata)
}
}
END_FOR_EACH_PTR(bb);
// The following flag triggers loop optimizations at O2
JIT_SetMayHaveLoops(fn->injector);
return true;
Efailed:

@ -0,0 +1,35 @@
FROM ubuntu:18.04
RUN set -x \
&& apt-get update \
&& apt-get install -y libreadline-dev \
&& apt-get install -y build-essential \
&& apt-get install -y git wget \
&& apt-get install -y zlib1g-dev \
&& apt-get clean \
&& mkdir -p /Software \
&& wget -O "/Software/cmake-3.14.5-Linux-x86_64.tar.gz" "https://github.com/Kitware/CMake/releases/download/v3.14.5/cmake-3.14.5-Linux-x86_64.tar.gz" \
&& cd /Software \
&& tar xvf "cmake-3.14.5-Linux-x86_64.tar.gz" \
&& rm -rf "/Software/cmake-3.14.5-Linux-x86_64.tar.gz" \
&& wget -O "/Software/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz" "http://releases.llvm.org/8.0.0/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz" \
&& cd /Software \
&& tar xvf "clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz" \
&& rm -rf "/Software/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz" \
&& mkdir -p /sources \
&& cd /sources \
&& git clone https://github.com/dibyendumajumdar/ravi.git \
&& cd /sources/ravi \
&& mkdir build \
&& cd build \
&& /Software/cmake-3.14.5-Linux-x86_64/bin/cmake -DSTATIC_BUILD=ON -DCMAKE_INSTALL_PREFIX=/Software/ravi -DLLVM_JIT=ON -DCMAKE_BUILD_TYPE=Release -DLLVM_DIR=/Software/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-18.04/lib/cmake/llvm .. \
&& make install \
&& rm -rf /Software/cmake-3.14.5-Linux-x86_64 \
&& rm -rf /Software/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-18.04 \
&& rm -rf /sources \
&& apt-get autoremove \
&& apt-get remove -y --purge git wget build-essential \
&& apt-get clean
ENV PATH /Software/ravi/bin:${PATH}

@ -54,6 +54,7 @@ LUAI_FUNC void luaD_inctop (lua_State *L);
LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode);
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop);
#endif

@ -35,7 +35,8 @@
*/
struct UpVal {
TValue *v; /* points to stack or to its own value */
lu_mem refcount; /* reference counter */
unsigned int refcount; /* reference counter */
unsigned int flags; /* Used to mark deferred values */
union {
struct { /* (when open) */
UpVal *next; /* linked list */
@ -53,7 +54,7 @@ LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems);
LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems);
LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_close (lua_State *L, StkId level);
LUAI_FUNC int luaF_close (lua_State *L, StkId level, int status);
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
/* The additional type argument is a Ravi extension */
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,

@ -27,7 +27,7 @@ enum RESERVED {
/* terminal symbols denoted by reserved words */
TK_AND = FIRST_RESERVED, TK_BREAK,
TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,
TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_DEFER, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
/* other terminal symbols */
TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE,

@ -281,10 +281,12 @@ OP_RAVI_SELF_SK, /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)], string key *
OP_RAVI_SETFIELD, /* 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 */
OP_RAVI_DEFER, /* A mark variable A "deferred" */
} OpCode;
#define NUM_OPCODES (cast(int, OP_RAVI_GETTABUP_SK) + 1)
#define NUM_OPCODES (cast(int, OP_RAVI_DEFER) + 1)
/*===========================================================================
Notes:

@ -83,7 +83,7 @@ required to get to a node in the hash table
#if !RAVI_USE_INLINE_SHORTSTR_TGET
LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
#else
LUAI_FUNC const TValue *luaH_getshortstr_continue(Table *t, TString *key, Node *n);
LUAI_FUNC const TValue *luaH_getshortstr_continue(TString *key, Node *n);
static RAVI_ALWAYS_INLINE const TValue *luaH_getshortstr(Table *t, TString *key) {
/* We inline the lookup in first two slots */
Node *n = hashstr(t, key);
@ -94,6 +94,7 @@ static RAVI_ALWAYS_INLINE const TValue *luaH_getshortstr(Table *t, TString *key)
int nx = gnext(n);
if (nx == 0)
return luaO_nilobject; /* not found */
#if RAVI_USE_INLINE_SHORTSTR_TGET == 2
n += nx;
k = gkey(n);
if (ttisshrstring(k) && eqshrstr(tsvalue(k), key))
@ -101,8 +102,9 @@ static RAVI_ALWAYS_INLINE const TValue *luaH_getshortstr(Table *t, TString *key)
nx = gnext(n);
if (nx == 0)
return luaO_nilobject; /* not found */
#endif
/* Okay continue search slowly */
return luaH_getshortstr_continue(t, key, n);
return luaH_getshortstr_continue(key, n);
}
#endif
LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);

@ -23,7 +23,7 @@
#define LUA_VERSION "Ravi " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#define LUA_COPYRIGHT LUA_RELEASE "\nCopyright (C) 1994-2019 Lua.org, PUC-Rio\nPortions Copyright (C) 2015-2019 Dibyendu Majumdar"
#define LUA_COPYRIGHT LUA_RELEASE "\nCopyright (C) 1994-2019 Lua.org, PUC-Rio\nPortions Copyright (C) 2015-2020 Dibyendu Majumdar"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes, Dibyendu Majumdar"
@ -661,7 +661,8 @@ LUA_API void ravi_set_debuglevel(int level);
/******************************************************************************
* Copyright (C) 1994-2017 Lua.org, PUC-Rio.
* Copyright (C) 1994-2019 Lua.org, PUC-Rio.
* Portions Copyright (C) 2015-2020 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the

@ -823,7 +823,10 @@
#endif
/* Use LuaJIT style hashing */
#define RAVI_USE_NEWHASH 1
/* Following cause the first hash lookup to be inlined,
and if value is 2 then the second hash lookup is also inlined. */
#define RAVI_USE_INLINE_SHORTSTR_TGET 1
#define RAVI_USE_LLVM_BRANCH_WEIGHTS 1
/* If following is defined as true then LLVM instructions emitted for arithmetic ops

@ -57,10 +57,10 @@ LUAMOD_API int (raviopen_llvmjit)(lua_State *L);
#define LUA_ASTLIBNAME "ast"
LUAMOD_API int (raviopen_ast_library)(lua_State *L);
#ifdef USE_LLVM
#define LUA_LLVMLIBNAME "llvm"
LUAMOD_API int (raviopen_llvmluaapi)(lua_State *L);
#endif
//#ifdef USE_LLVM
//#define LUA_LLVMLIBNAME "llvm"
//LUAMOD_API int (raviopen_llvmluaapi)(lua_State *L);
//#endif
/** RAVI change end */
/* open all previous libraries */
LUALIB_API void (luaL_openlibs) (lua_State *L);

@ -161,5 +161,6 @@ LUAI_FUNC void raviV_gettable_i(lua_State *L, const TValue *t, TValue *key, StkI
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);
LUAI_FUNC int raviV_check_usertype(lua_State *L, TString *name, const TValue *o);
LUAI_FUNC void raviV_op_defer(lua_State *L, TValue *ra);
#endif

@ -1,15 +1,289 @@
#ifndef ravi_ast_h
#define ravi_ast_h
/*
** $Id: lparser.h,v 1.74 2014/10/25 11:50:46 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
A parser and syntax tree builder for Ravi. This is work in progress.
Once ready it will be used to create a new byte code generator for Ravi.
The parser will perform following actions:
a) Generate syntax tree
b) Perform type checking (Ravi enhancement)
*/
#ifndef ravi_ast_h
#define ravi_ast_h
#define LUA_CORE
#include "lprefix.h"
#include "lua.h"
#include "lcode.h"
#include "ldo.h"
#include "lstring.h"
#include "ltable.h"
#include "lauxlib.h"
#include "ravi_ast.h"
#include "ravi_membuf.h"
#include "allocate.h"
#include "ptrlist.h"
#include <assert.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#define MAXVARS 125
//////////////////////////
struct lua_symbol_list;
/*
* Userdata object to hold the abstract syntax tree;
* All memory is held by this object. Memory is freed when
* the object is GC collected; or when
* ast_container:release() method is called
* by user.
*/
struct ast_container {
struct allocator ast_node_allocator;
struct allocator ptrlist_allocator;
struct allocator block_scope_allocator;
struct allocator symbol_allocator;
struct ast_node *main_function;
bool killed; /* flag to check if this is already destroyed */
};
struct ast_node;
DECLARE_PTR_LIST(ast_node_list, struct ast_node);
struct var_type;
DECLARE_PTR_LIST(var_type_list, struct var_type);
/* Lua type info. We need to support user defined types too which are known by name */
struct var_type {
ravitype_t type_code;
const TString *type_name; /* type name for user defined types; used to lookup metatable in registry, only set when
type_code is RAVI_TUSERDATA */
};
struct lua_symbol;
DECLARE_PTR_LIST(lua_symbol_list, struct lua_symbol);
struct block_scope;
/* Types of symbols */
enum symbol_type {
SYM_LOCAL,
SYM_UPVALUE,
SYM_GLOBAL, /* Global symbols are never added to a scope so they are always looked up */
SYM_LABEL
};
/* A symbol is a name recognised in Ravi/Lua code*/
struct lua_symbol {
enum symbol_type symbol_type;
struct var_type value_type;
union {
struct {
const TString *var_name; /* name of the variable */
struct block_scope *block; /* NULL if global symbol, as globals are never added to a scope */
} var;
struct {
const TString *label_name;
struct block_scope *block;
} label;
struct {
struct lua_symbol *var; /* variable reference */
struct ast_node *function; /* Where the upvalue lives */
} upvalue;
};
};
struct block_scope {
struct ast_node *function; /* function owning this block - of type FUNCTION_EXPR */
struct block_scope *parent; /* parent block, may belong to parent function */
struct lua_symbol_list *symbol_list; /* symbols defined in this block */
};
enum ast_node_type {
AST_NONE, /* Used when the node doesn't represent an AST such as test_then_block. */
AST_RETURN_STMT,
AST_GOTO_STMT,
AST_LABEL_STMT,
AST_DO_STMT,
AST_LOCAL_STMT,
AST_FUNCTION_STMT,
AST_IF_STMT,
AST_WHILE_STMT,
AST_FORIN_STMT,
AST_FORNUM_STMT,
AST_REPEAT_STMT,
AST_EXPR_STMT, /* Also used for assignment statements */
AST_LITERAL_EXPR,
AST_SYMBOL_EXPR,
AST_Y_INDEX_EXPR, /* [] operator */
AST_FIELD_SELECTOR_EXPR, /* table field access - '.' or ':' operator */
AST_INDEXED_ASSIGN_EXPR, /* table value assign in table constructor */
AST_SUFFIXED_EXPR,
AST_UNARY_EXPR,
AST_BINARY_EXPR,
AST_FUNCTION_EXPR, /* function literal */
AST_TABLE_EXPR, /* table constructor */
AST_FUNCTION_CALL_EXPR
};
/* The parse tree is made up of ast_node objects. Some of the ast_nodes reference the appropriate block
scopes but not all scopes may be referenced. The tree captures Lua syntax tree - i.e. statements such as
while, repeat, and for are captured in the way user uses them and not the way Lua generates code. Potentially
we can have a transformation step to convert to a tree that is more like the code generation */
struct ast_node {
enum ast_node_type type;
union {
struct {
struct ast_node_list *expr_list;
} return_stmt;
struct {
struct lua_symbol *symbol;
} label_stmt;
struct {
const TString *name; /* target label, used to resolve the goto destination */
struct ast_node *label_stmt; /* Initially this will be NULL; set by a separate pass */
} goto_stmt;
struct {
struct lua_symbol_list *var_list;
struct ast_node_list *expr_list;
} local_stmt; /* local declarations */
struct {
struct ast_node_list *var_expr_list; /* Optional var expressions, comma separated */
struct ast_node_list *expr_list; /* Comma separated expressions */
} expression_stmt; /* Also covers assignments */
struct {
struct ast_node *name; /* base symbol to be looked up */
struct ast_node_list *selectors; /* Optional */
struct ast_node *method_name; /* Optional */
struct ast_node *function_expr; /* Function's AST */
} function_stmt;
struct {
struct block_scope *scope; /* The do statement only creates a new scope */
struct ast_node_list *do_statement_list; /* statements in this block */
} do_stmt;
struct {
struct ast_node *condition;
struct block_scope *test_then_scope;
struct ast_node_list *test_then_statement_list; /* statements in this block */
} test_then_block; /* Used internally in if_stmt, not an independent AST node */
struct {
struct ast_node_list *if_condition_list; /* Actually a list of test_then_blocks */
struct block_scope *else_block;
struct ast_node_list *else_statement_list; /* statements in this block */
} if_stmt;
struct {
struct ast_node *condition;
struct block_scope *loop_scope;
struct ast_node_list *loop_statement_list; /* statements in this block */
} while_or_repeat_stmt;
struct {
struct lua_symbol_list *symbols;
struct ast_node_list *expr_list;
struct block_scope *for_body;
struct ast_node_list *for_statement_list; /* statements in this block */
} for_stmt; /* Used for both generic and numeric for loops */
struct {
struct var_type type;
} common_expr; /* To access the type field common to all expr objects */
/* all expr types must be compatible with common_expr */
struct {
struct var_type type;
union {
lua_Integer i;
lua_Number n;
const TString *s;
} u;
} literal_expr;
struct {
struct var_type type;
struct lua_symbol *var;
} symbol_expr;
struct {
struct var_type type;
struct ast_node *expr; /* '[' expr ']' */
} index_expr;
struct {
struct var_type type;
UnOpr unary_op;
struct ast_node *expr;
} unary_expr;
struct {
struct var_type type;
BinOpr binary_op;
struct ast_node *expr_left;
struct ast_node *expr_right;
} binary_expr;
struct {
struct var_type type;
unsigned int is_vararg : 1;
unsigned int is_method : 1;
struct ast_node *parent_function; /* parent function or NULL if main chunk */
struct block_scope *main_block; /* the function's main block */
struct ast_node_list *function_statement_list; /* statements in this block */
struct lua_symbol_list *args; /* arguments, also must be part of the function block's symbol list */
struct ast_node_list *child_functions; /* child functions declared in this function */
struct lua_symbol_list *upvalues; /* List of upvalues */
struct lua_symbol_list *locals; /* List of locals */
} function_expr; /* a literal expression whose result is a value of type function */
struct {
struct var_type type;
struct ast_node *
index_expr; /* If NULL means this is a list field with next available index, else specfies index expression */
struct ast_node *value_expr;
} indexed_assign_expr; /* Assign values in table constructor */
struct {
struct var_type type;
struct ast_node_list *expr_list;
} table_expr; /* table constructor expression */
struct {
struct var_type type;
struct ast_node *primary_expr;
struct ast_node_list *suffix_list;
} suffixed_expr;
struct {
/* Note that in Ravi the results from a function call must be type asserted during assignment to variables.
* This is not explicit in the AST but is required to ensure that function return values do not
* overwrite the type of the variables in an inconsistent way.
*/
struct var_type type;
TString *method_name; /* Optional method_name */
struct ast_node_list *arg_list; /* Call arguments */
} function_call_expr;
};
};
#include "lparser.h"
#define set_typecode(vt, t) \
(vt).type_code = t
#define set_type(vt, t) \
(vt).type_code = t, \
(vt).type_name = NULL
#define set_typename(vt, t, name) \
(vt).type_code = t, \
(vt).type_name = (name)
#define is_type_same(a, b) ((a).type_code == (b).type_code && (a).type_name == (b).type_name)
#define copy_type(a, b) \
(a).type_code = (b).type_code, \
(a).type_name = (b).type_name
struct parser_state {
LexState *ls;
struct ast_container *container;
struct ast_node *current_function;
struct block_scope *current_scope;
};
LUAMOD_API int raviopen_ast_library(lua_State *L);
#endif
void raviA_print_ast_node(membuff_t *buf, struct ast_node *node, int level); /* output the AST structure recusrively */
void raviA_ast_typecheck(struct ast_container *container); /* Perform type checks and assign types to AST */
#endif

@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (C) 2015-2017 Dibyendu Majumdar
* Copyright (C) 2015-2020 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the

@ -38,11 +38,15 @@
#endif
#if LLVM_VERSION_MAJOR >= 8 && !defined(_WIN32)
#define USE_ORCv2_JIT 1
#define USE_ORCv2_JIT 0
#else
#define USE_ORCv2_JIT 0
#endif
#if LLVM_VERSION_MAJOR >= 9
#define USE_ORCv2_JIT 0
#endif
// In lua.c we include this just to get version numbers
// We cannot have C++ headers in that case
#ifdef __cplusplus

@ -288,6 +288,7 @@ struct LuaLLVMTypes {
llvm::FunctionType *raviV_gettable_iT;
llvm::FunctionType *raviV_settable_iT;
llvm::FunctionType *raviV_op_totypeT;
llvm::FunctionType *raviV_op_deferT;
llvm::FunctionType *raviH_set_intT;
llvm::FunctionType *raviH_set_floatT;
@ -832,6 +833,7 @@ struct RaviFunctionDef {
llvm::Function *raviV_gettable_iF;
llvm::Function *raviV_settable_iF;
llvm::Function *raviV_op_totypeF;
llvm::Function *raviV_op_deferF;
// array setters
llvm::Function *raviH_set_intF;
@ -843,10 +845,17 @@ struct RaviFunctionDef {
llvm::Function *ravi_debug_traceF;
// standard C functions
#if LLVM_VERSION_MAJOR >= 9
llvm::FunctionCallee printfFunc;
llvm::FunctionCallee fmodFunc;
llvm::FunctionCallee floorFunc;
llvm::FunctionCallee powFunc;
#else
llvm::Constant *printfFunc;
llvm::Constant *fmodFunc;
llvm::Constant *floorFunc;
llvm::Constant *powFunc;
#endif
// Jump targets in the function
std::vector<RaviBranchDef> jmp_targets;
@ -1362,6 +1371,8 @@ class RaviCodeGenerator {
void emit_BNOT(RaviFunctionDef *def, int A, int B, int pc);
void emit_DEFER(RaviFunctionDef *def, int A, int pc);
void emit_bitwise_shiftl(RaviFunctionDef *def, llvm::Value *ra, int B, lua_Integer y);
private:

@ -0,0 +1,53 @@
/******************************************************************************
* Copyright (C) 2019-2020 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_MIRJIT_H
#define RAVI_MIRJIT_H
#include <ravi_jitshared.h>
#ifdef USE_MIRJIT
#include "c2mir.h"
#include "mir-gen.h"
struct ravi_State {
MIR_context_t jit;
unsigned long long id; // counter to generate function names
unsigned int verbosity_ : 3;
unsigned int auto_ : 1; /* Should we auto compile what we can? */
unsigned int enabled_ : 1; /* is JIT enabled */
unsigned int opt_level_ : 3; /* optimization level */
unsigned int tracehook_enabled_ : 1; /* enable calls to luaG_traceexec() at every bytecode, this is expensive ! */
unsigned int validation_ : 1; /* Enable extra validation such as IL verification */
unsigned int compiling_; /* flag to help avoid recursion */
int min_code_size_; /* min code size for compilation */
int min_exec_count_; /* min execution count for compilation */
struct c2mir_options options; /* MIR options */
};
#ifdef __cplusplus
};
#endif
#endif /* USE_MIRJIT */
#endif /* RAVI_MIRJIT_H */

@ -1,27 +1,5 @@
/******************************************************************************
* 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.
******************************************************************************/
/******************************************************************************
* Copyright (C) 2015-2018 Dibyendu Majumdar
* Copyright (C) 2015-2020 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the

@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
* Copyright (C) 2015-2020 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the

@ -507,7 +507,10 @@ do
end
-- conversion
a = 0; for i="10","1","-2" do a=a+1 end; assert(a==5)
if not ravi.jit() then
-- Because we do not do some of the conversions in MIR jit
a = 0; for i="10","1","-2" do a=a+1 end; assert(a==5)
end
do -- checking types
local c
@ -531,32 +534,33 @@ do -- checking types
c = 0; for i = m, m - 10, -1 do checkint(i) end
assert(c == 11)
c = 0; for i = 1, 10.9 do checkint(i) end
assert(c == 10)
if not ravi.jit() then
c = 0; for i = 1, 10.9 do checkint(i) end
assert(c == 10)
c = 0; for i = 10, 0.001, -1 do checkint(i) end
assert(c == 10)
c = 0; for i = 10, 0.001, -1 do checkint(i) end
assert(c == 10)
c = 0; for i = 1, "10.8" do checkint(i) end
assert(c == 10)
c = 0; for i = 1, "10.8" do checkint(i) end
assert(c == 10)
c = 0; for i = 9, "3.4", -1 do checkint(i) end
assert(c == 6)
c = 0; for i = 9, "3.4", -1 do checkint(i) end
assert(c == 6)
c = 0; for i = 0, " -3.4 ", -1 do checkint(i) end
assert(c == 4)
c = 0; for i = 0, " -3.4 ", -1 do checkint(i) end
assert(c == 4)
c = 0; for i = 100, "96.3", -2 do checkint(i) end
assert(c == 2)
c = 0; for i = 100, "96.3", -2 do checkint(i) end
assert(c == 2)
c = 0; for i = 1, math.huge do if i > 10 then break end; checkint(i) end
assert(c == 10)
c = 0; for i = 1, math.huge do if i > 10 then break end; checkint(i) end
assert(c == 10)
c = 0; for i = -1, -math.huge, -1 do
if i < -10 then break end; checkint(i)
c = 0; for i = -1, -math.huge, -1 do
if i < -10 then break end; checkint(i)
end
assert(c == 10)
assert(c == 10)
end
for i = math.mininteger, -10e100 do assert(false) end
for i = math.maxinteger, 10e100, -1 do assert(false) end

@ -0,0 +1,44 @@
project(mir)
enable_language(C)
message(STATUS "OS type is ${CMAKE_SYSTEM_NAME}")
message(STATUS "System processor is ${CMAKE_HOST_SYSTEM_PROCESSOR}")
message(STATUS "Build type is ${CMAKE_BUILD_TYPE}")
set(TARGET x86_64)
set(MIR_HEADERS
mir.h
mir-gen.h
mir-varr.h
mir-dlist.h
mir-htab.h
mir-hash.h
mir-bitmap.h
)
set(MIR_SRCS
mir.c
mir-gen.c
)
set(C2MIR_SRCS
c2mir/c2mir.c
)
set(LIBS dl)
add_definitions(-D${TARGET})
add_definitions(-DMIR_IO)
add_definitions(-DMIR_SCAN)
include_directories(".")
include_directories("./c2mir")
add_library(c2mir
${MIR_HEADERS}
${MIR_SRCS}
${C2MIR_SRCS})
target_link_libraries(c2mir ${LIBS})

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Vladimir Makarov
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.

@ -0,0 +1,5 @@
This is a private copy of the [MIR](https://github.com/vnmakarov/mir) project for use by Ravi. The code will be occasionally refreshed from the upstream
project. Following changes have been made:
* A CMake build script added to create a library
* Unused files / tests have been removed to avoid clutter

File diff suppressed because it is too large Load Diff

@ -0,0 +1,25 @@
#include "mir.h"
#define COMMAND_LINE_SOURCE_NAME "<command-line>"
#define STDIN_SOURCE_NAME "<stdin>"
struct c2mir_macro_command {
int def_p; /* #define or #undef */
const char *name, *def; /* def is used only when def_p is true */
};
struct c2mir_options {
FILE *message_file;
int debug_p, verbose_p, no_prepro_p, prepro_only_p, syntax_only_p, pedantic_p, asm_p, object_p;
size_t module_num;
FILE *prepro_output_file; /* non-null for prepro_only_p */
const char *output_file_name;
size_t macro_commands_num, include_dirs_num;
struct c2mir_macro_command *macro_commands;
const char **include_dirs;
};
void c2mir_init (MIR_context_t ctx);
void c2mir_finish (MIR_context_t ctx);
int c2mir_compile (MIR_context_t ctx, struct c2mir_options *ops, int (*getc_func) (void *),
void *getc_data, const char *source_name, FILE *output_file);

@ -0,0 +1,23 @@
static const char mirc[]
= "#define __mirc__ 1\n"
"#define __MIRC__ 1\n"
"#define __STDC_HOSTED__ 1\n"
"//#define __STDC_ISO_10646__ 201103L\n"
"#define __STDC_NO_ATOMICS__ 1\n"
"#define __STDC_NO_COMPLEX__ 1\n"
"#define __STDC_NO_THREADS__ 1\n"
"#define __STDC_NO_VLA__ 1\n"
"#define __STDC_UTF_16__ 1\n"
"#define __STDC_UTF_32__ 1\n"
"#define __STDC_VERSION__ 201112L\n"
"#define __STDC__ 1\n"
"\n"
"/* Some GCC alternative keywords used but not defined in standard headers: */\n"
"#define __const const\n"
"#define __const__ const\n"
"#define __inline__ inline\n"
"#define __restrict__ restrict\n"
"#define __signed signed\n"
"#define __signed__ signed\n"
"#define __volatile volatile\n"
"#define __volatile__ volatile\n";

@ -0,0 +1,24 @@
/* This file is a part of MIR project.
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
#include "../mirc.h"
#include "mirc-x86_64-linux.h"
static const char *standard_includes[] = {mirc, x86_64_mirc};
static const char *standard_include_dirs[] = {"include/mirc/", "include/mirc/x86-64/"};
#define MAX_ALIGNMENT 16
#define ADJUST_VAR_ALIGNMENT(c2m_ctx, align, type) x86_adjust_var_alignment (c2m_ctx, align, type)
static int x86_adjust_var_alignment (c2m_ctx_t c2m_ctx, int align, struct type *type) {
/* see https://www.uclibc.org/docs/psABI-x86_64.pdf */
if (type->mode == TM_ARR && raw_type_size (c2m_ctx, type) >= 16) return 16;
return align;
}
static int invalid_alignment (mir_llong align) {
return align != 0 && align != 1 && align != 2 && align != 4 && align != 8 && align != 16;
}

@ -0,0 +1,50 @@
/* This file is a part of MIR project.
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
#include <stdint.h>
#define MIR_CHAR_BIT 8
typedef int8_t mir_schar;
typedef int16_t mir_short;
typedef int32_t mir_int;
typedef int64_t mir_long;
typedef int64_t mir_llong;
#define MIR_SCHAR_MIN INT8_MIN
#define MIR_SCHAR_MAX INT8_MAX
#define MIR_SHORT_MIN INT16_MIN
#define MIR_SHORT_MAX INT16_MAX
#define MIR_INT_MIN INT32_MIN
#define MIR_INT_MAX INT32_MAX
#define MIR_LONG_MIN INT64_MIN
#define MIR_LONG_MAX INT64_MAX
#define MIR_LLONG_MIN INT64_MIN
#define MIR_LLONG_MAX INT64_MAX
typedef uint8_t mir_uchar;
typedef uint16_t mir_ushort;
typedef uint32_t mir_uint;
typedef uint64_t mir_ulong;
typedef uint64_t mir_ullong;
#define MIR_UCHAR_MAX UINT8_MAX
#define MIR_USHORT_MAX UINT16_MAX
#define MIR_UINT_MAX UINT32_MAX
#define MIR_ULONG_MAX UINT64_MAX
#define MIR_ULLONG_MAX UINT64_MAX
typedef mir_schar mir_char;
#define MIR_CHAR_MIN MIR_SCHAR_MIN
#define MIR_CHAR_MAX MIR_SCHAR_MAX
typedef float mir_float;
typedef double mir_double;
typedef long double mir_ldouble;
typedef uint8_t mir_bool;
typedef int64_t mir_ptrdiff_t;
typedef uint64_t mir_size_t;
#define MIR_SIZE_MAX UINT64_MAX

@ -0,0 +1,89 @@
static char x86_64_mirc[]
= "#define __amd64 1\n"
"#define __amd64__ 1\n"
"#define _LP64 1\n"
"#define __LP64__ 1\n"
"#define __x86_64 1\n"
"#define __x86_64__ 1\n"
"\n"
"#define __SIZEOF_DOUBLE__ 8\n"
"#define __SIZEOF_FLOAT__ 4\n"
"#define __SIZEOF_INT__ 4\n"
"#define __SIZEOF_LONG_DOUBLE__ 8\n"
"#define __SIZEOF_LONG_LONG__ 8\n"
"#define __SIZEOF_LONG__ 8\n"
"#define __SIZEOF_POINTER__ 8\n"
"#define __SIZEOF_PTRDIFF_T__ 8\n"
"#define __SIZEOF_SHORT__ 2\n"
"#define __SIZEOF_SIZE_T__ 8\n"
"\n"
"#define __BYTE_ORDER__ 1234\n"
"#define __ORDER_LITTLE_ENDIAN__ 1234\n"
"#define __ORDER_BIG_ENDIAN__ 4321\n"
"\n"
"/* Some GCC predefined macros: */\n"
"#define __SIZE_TYPE__ unsigned long\n"
"#define __PTRDIFF_TYPE__ long\n"
"#define __INTMAX_TYPE__ long\n"
"#define __UINTMAX_TYPE__ unsigned long\n"
"#define __INT8_TYPE__ signed char\n"
"#define __INT16_TYPE__ short\n"
"#define __INT32_TYPE__ int\n"
"#define __INT64_TYPE__ long\n"
"#define __UINT8_TYPE__ unsigned char\n"
"#define __UINT16_TYPE__ unsigned short\n"
"#define __UINT32_TYPE__ unsigned int\n"
"#define __UINT64_TYPE__ unsigned long\n"
"#define __INTPTR_TYPE__ long\n"
"#define __UINTPTR_TYPE__ unsigned long\n"
"\n"
"#define __CHAR_BIT__ 8\n"
"#define __INT8_MAX__ 127\n"
"#define __INT16_MAX__ 32767\n"
"#define __INT32_MAX__ 2147483647\n"
"#define __INT64_MAX__ 9223372036854775807l\n"
"#define __UINT8_MAX__ (__INT8_MAX__ * 2u + 1u)\n"
"#define __UINT16_MAX__ (__INT16_MAX__ * 2u + 1u)\n"
"#define __UINT32_MAX__ (__INT32_MAX__ * 2u + 1u)\n"
"#define __UINT64_MAX__ (__INT64_MAX__ * 2u + 1u)\n"
"#define __SCHAR_MAX__ __INT8_MAX__\n"
"#define __SHRT_MAX__ __INT16_MAX__\n"
"#define __INT_MAX__ __INT32_MAX__\n"
"#define __LONG_MAX__ __INT64_MAX__\n"
"#define __LONG_LONG_MAX__ __INT64_MAX__\n"
"#define __SIZE_MAX__ __UINT64_MAX__\n"
"#define __PTRDIFF_MAX__ __INT64_MAX__\n"
"#define __INTMAX_MAX__ __INT64_MAX__\n"
"#define __UINTMAX_MAX__ __UINT64_MAX__\n"
"#define __INTPTR_MAX__ __INT64_MAX__\n"
"#define __UINTPTR_MAX__ __UINT64_MAX__\n"
"\n"
"#define __FLT_MIN_EXP__ (-125)\n"
"#define __FLT_MAX_EXP__ 128\n"
"#define __FLT_DIG__ 6\n"
"#define __FLT_DECIMAL_DIG__ 9\n"
"#define __FLT_MANT_DIG__ 24\n"
"#define __FLT_MIN__ 1.17549435082228750796873653722224568e-38F\n"
"#define __FLT_MAX__ 3.40282346638528859811704183484516925e+38F\n"
"#define __FLT_EPSILON__ 1.19209289550781250000000000000000000e-7F\n"
"\n"
"#define __DBL_MIN_EXP__ (-1021)\n"
"#define __DBL_MAX_EXP__ 1024\n"
"#define __DBL_DIG__ 15\n"
"#define __DBL_DECIMAL_DIG__ 17\n"
"#define __DBL_MANT_DIG__ 53\n"
"#define __DBL_MAX__ ((double) 1.79769313486231570814527423731704357e+308L)\n"
"#define __DBL_MIN__ ((double) 2.22507385850720138309023271733240406e-308L)\n"
"#define __DBL_EPSILON__ ((double) 2.22044604925031308084726333618164062e-16L)\n"
"\n"
"typedef unsigned short char16_t;\n"
"typedef unsigned int char32_t;\n"
"\n"
"#define __gnu_linux__ 1\n"
"#define __linux 1\n"
"#define __linux__ 1\n"
"#define __unix 1\n"
"#define __unix__ 1\n"
"#define linux 1\n"
"\n"
"void *alloca (unsigned long);\n";

@ -0,0 +1,286 @@
/* This file is a part of MIR project.
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
#ifndef MIR_BITMAP_H
#define MIR_BITMAP_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include "mir-varr.h"
#define FALSE 0
#define TRUE 1
#if !defined(BITMAP_ENABLE_CHECKING) && !defined(NDEBUG)
#define BITMAP_ENABLE_CHECKING
#endif
#ifndef BITMAP_ENABLE_CHECKING
#define BITMAP_ASSERT(EXPR, OP) ((void) (EXPR))
#else
static inline void mir_bitmap_assert_fail (const char *op) {
fprintf (stderr, "wrong %s for a bitmap", op);
assert (0);
}
#define BITMAP_ASSERT(EXPR, OP) (void) ((EXPR) ? 0 : (mir_bitmap_assert_fail (#OP), 0))
#endif
#define BITMAP_WORD_BITS 64
typedef uint64_t bitmap_el_t;
DEF_VARR (bitmap_el_t);
typedef VARR (bitmap_el_t) * bitmap_t;
typedef const VARR (bitmap_el_t) * const_bitmap_t;
static inline bitmap_t bitmap_create2 (size_t init_bits_num) {
bitmap_t bm;
VARR_CREATE (bitmap_el_t, bm, (init_bits_num + BITMAP_WORD_BITS - 1) / BITMAP_WORD_BITS);
return bm;
}
static inline bitmap_t bitmap_create (void) { return bitmap_create2 (0); }
static inline void bitmap_destroy (bitmap_t bm) { VARR_DESTROY (bitmap_el_t, bm); }
static inline void bitmap_clear (bitmap_t bm) { VARR_TRUNC (bitmap_el_t, bm, 0); }
static inline void bitmap_expand (bitmap_t bm, size_t nb) {
size_t i, len = VARR_LENGTH (bitmap_el_t, bm);
size_t new_len = (nb + BITMAP_WORD_BITS - 1) / BITMAP_WORD_BITS;
for (i = len; i < new_len; i++) VARR_PUSH (bitmap_el_t, bm, (bitmap_el_t) 0);
}
static inline int bitmap_bit_p (const_bitmap_t bm, size_t nb) {
size_t nw, sh, len = VARR_LENGTH (bitmap_el_t, bm);
bitmap_el_t *addr = VARR_ADDR (bitmap_el_t, bm);
if (nb >= BITMAP_WORD_BITS * len) return 0;
nw = nb / BITMAP_WORD_BITS;
sh = nb % BITMAP_WORD_BITS;
return (addr[nw] >> sh) & 1;
}
static inline int bitmap_set_bit_p (bitmap_t bm, size_t nb) {
size_t nw, sh;
bitmap_el_t *addr;
int res;
bitmap_expand (bm, nb + 1);
addr = VARR_ADDR (bitmap_el_t, bm);
nw = nb / BITMAP_WORD_BITS;
sh = nb % BITMAP_WORD_BITS;
res = ((addr[nw] >> sh) & 1) == 0;
addr[nw] |= (bitmap_el_t) 1 << sh;
return res;
}
static inline int bitmap_clear_bit_p (bitmap_t bm, size_t nb) {
size_t nw, sh, len = VARR_LENGTH (bitmap_el_t, bm);
bitmap_el_t *addr = VARR_ADDR (bitmap_el_t, bm);
int res;
if (nb >= BITMAP_WORD_BITS * len) return 0;
nw = nb / BITMAP_WORD_BITS;
sh = nb % BITMAP_WORD_BITS;
res = (addr[nw] >> sh) & 1;
addr[nw] &= ~((bitmap_el_t) 1 << sh);
return res;
}
static inline void bitmap_copy (bitmap_t dst, const_bitmap_t src) {
size_t dst_len = VARR_LENGTH (bitmap_el_t, dst);
size_t src_len = VARR_LENGTH (bitmap_el_t, src);
if (dst_len >= src_len)
VARR_TRUNC (bitmap_el_t, dst, src_len);
else
bitmap_expand (dst, src_len * BITMAP_WORD_BITS);
memcpy (VARR_ADDR (bitmap_el_t, dst), VARR_ADDR (bitmap_el_t, src),
src_len * sizeof (bitmap_el_t));
}
static inline int bitmap_equal_p (const_bitmap_t bm1, const_bitmap_t bm2) {
const_bitmap_t temp_bm;
size_t i, temp_len, bm1_len = VARR_LENGTH (bitmap_el_t, bm1);
size_t bm2_len = VARR_LENGTH (bitmap_el_t, bm2);
bitmap_el_t *addr1, *addr2;
if (bm1_len > bm2_len) {
temp_bm = bm1;
bm1 = bm2;
bm2 = temp_bm;
temp_len = bm1_len;
bm1_len = bm2_len;
bm2_len = temp_len;
}
addr1 = VARR_ADDR (bitmap_el_t, bm1);
addr2 = VARR_ADDR (bitmap_el_t, bm2);
if (memcmp (addr1, addr2, bm1_len * sizeof (bitmap_el_t)) != 0) return FALSE;
for (i = bm1_len; i < bm2_len; i++)
if (addr2[i] != 0) return FALSE;
return TRUE;
}
static inline int bitmap_intersect_p (const_bitmap_t bm1, const_bitmap_t bm2) {
size_t i, min_len, bm1_len = VARR_LENGTH (bitmap_el_t, bm1);
size_t bm2_len = VARR_LENGTH (bitmap_el_t, bm2);
bitmap_el_t *addr1 = VARR_ADDR (bitmap_el_t, bm1);
bitmap_el_t *addr2 = VARR_ADDR (bitmap_el_t, bm2);
min_len = bm1_len <= bm2_len ? bm1_len : bm2_len;
for (i = 0; i < min_len; i++)
if ((addr1[i] & addr2[i]) != 0) return TRUE;
return FALSE;
}
static inline int bitmap_empty_p (const_bitmap_t bm) {
size_t i, len = VARR_LENGTH (bitmap_el_t, bm);
bitmap_el_t *addr = VARR_ADDR (bitmap_el_t, bm);
for (i = 0; i < len; i++)
if (addr[i] != 0) return FALSE;
return TRUE;
}
static inline bitmap_el_t bitmap_el_max3 (bitmap_el_t el1, bitmap_el_t el2, bitmap_el_t el3) {
if (el1 <= el2) return el2 < el3 ? el3 : el2;
return el1 < el3 ? el3 : el1;
}
static inline bitmap_el_t bitmap_el_max4 (bitmap_el_t el1, bitmap_el_t el2, bitmap_el_t el3,
bitmap_el_t el4) {
if (el1 <= el2) return bitmap_el_max3 (el2, el3, el4);
return bitmap_el_max3 (el1, el3, el4);
}
/* Return the number of bits set in BM. */
static inline size_t bitmap_bit_count (const_bitmap_t bm) {
size_t i, len = VARR_LENGTH (bitmap_el_t, bm);
bitmap_el_t el, *addr = VARR_ADDR (bitmap_el_t, bm);
size_t count = 0;
for (i = 0; i < len; i++) {
if ((el = addr[i]) != 0) {
for (; el != 0; el >>= 1)
if (el & 1) count++;
}
}
return count;
}
static inline int bitmap_op2 (bitmap_t dst, const_bitmap_t src1, const_bitmap_t src2,
bitmap_el_t (*op) (bitmap_el_t, bitmap_el_t)) {
size_t i, len, bound, src1_len, src2_len;
bitmap_el_t old, *dst_addr, *src1_addr, *src2_addr;
int change_p = FALSE;
src1_len = VARR_LENGTH (bitmap_el_t, src1);
src2_len = VARR_LENGTH (bitmap_el_t, src2);
len = bitmap_el_max3 (VARR_LENGTH (bitmap_el_t, dst), src1_len, src2_len);
bitmap_expand (dst, len * BITMAP_WORD_BITS);
dst_addr = VARR_ADDR (bitmap_el_t, dst);
src1_addr = VARR_ADDR (bitmap_el_t, src1);
src2_addr = VARR_ADDR (bitmap_el_t, src2);
for (bound = i = 0; i < len; i++) {
old = dst_addr[i];
if ((dst_addr[i] = op (i >= src1_len ? 0 : src1_addr[i], i >= src2_len ? 0 : src2_addr[i]))
!= 0)
bound = i + 1;
if (old != dst_addr[i]) change_p = TRUE;
}
VARR_TRUNC (bitmap_el_t, dst, bound);
return change_p;
}
static inline bitmap_el_t bitmap_el_and (bitmap_el_t el1, bitmap_el_t el2) { return el1 & el2; }
static inline int bitmap_and (bitmap_t dst, bitmap_t src1, bitmap_t src2) {
return bitmap_op2 (dst, src1, src2, bitmap_el_and);
}
static inline bitmap_el_t bitmap_el_and_compl (bitmap_el_t el1, bitmap_el_t el2) {
return el1 & ~el2;
}
static inline int bitmap_and_compl (bitmap_t dst, bitmap_t src1, bitmap_t src2) {
return bitmap_op2 (dst, src1, src2, bitmap_el_and_compl);
}
static inline bitmap_el_t bitmap_el_ior (bitmap_el_t el1, bitmap_el_t el2) { return el1 | el2; }
static inline int bitmap_ior (bitmap_t dst, bitmap_t src1, bitmap_t src2) {
return bitmap_op2 (dst, src1, src2, bitmap_el_ior);
}
static inline int bitmap_op3 (bitmap_t dst, const_bitmap_t src1, const_bitmap_t src2,
const_bitmap_t src3,
bitmap_el_t (*op) (bitmap_el_t, bitmap_el_t, bitmap_el_t)) {
size_t i, len, bound, src1_len, src2_len, src3_len;
bitmap_el_t old, *dst_addr, *src1_addr, *src2_addr, *src3_addr;
int change_p = FALSE;
src1_len = VARR_LENGTH (bitmap_el_t, src1);
src2_len = VARR_LENGTH (bitmap_el_t, src2);
src3_len = VARR_LENGTH (bitmap_el_t, src3);
len = bitmap_el_max4 (VARR_LENGTH (bitmap_el_t, dst), src1_len, src2_len, src3_len);
bitmap_expand (dst, len * BITMAP_WORD_BITS);
dst_addr = VARR_ADDR (bitmap_el_t, dst);
src1_addr = VARR_ADDR (bitmap_el_t, src1);
src2_addr = VARR_ADDR (bitmap_el_t, src2);
src3_addr = VARR_ADDR (bitmap_el_t, src3);
for (bound = i = 0; i < len; i++) {
old = dst_addr[i];
if ((dst_addr[i] = op (i >= src1_len ? 0 : src1_addr[i], i >= src2_len ? 0 : src2_addr[i],
i >= src3_len ? 0 : src3_addr[i]))
!= 0)
bound = i + 1;
if (old != dst_addr[i]) change_p = TRUE;
}
VARR_TRUNC (bitmap_el_t, dst, bound);
return change_p;
}
static inline bitmap_el_t bitmap_el_ior_and (bitmap_el_t el1, bitmap_el_t el2, bitmap_el_t el3) {
return el1 | (el2 & el3);
}
/* DST = SRC1 | (SRC2 & SRC3). Return true if DST changed. */
static inline int bitmap_ior_and (bitmap_t dst, bitmap_t src1, bitmap_t src2, bitmap_t src3) {
return bitmap_op3 (dst, src1, src2, src3, bitmap_el_ior_and);
}
static inline bitmap_el_t bitmap_el_ior_and_compl (bitmap_el_t el1, bitmap_el_t el2,
bitmap_el_t el3) {
return el1 | (el2 & ~el3);
}
/* DST = SRC1 | (SRC2 & ~SRC3). Return true if DST changed. */
static inline int bitmap_ior_and_compl (bitmap_t dst, bitmap_t src1, bitmap_t src2, bitmap_t src3) {
return bitmap_op3 (dst, src1, src2, src3, bitmap_el_ior_and_compl);
}
static inline void bitmap_for_each (bitmap_t bm, void (*func) (size_t, void *), void *data) {
size_t i, nb, len = VARR_LENGTH (bitmap_el_t, bm);
bitmap_el_t el, *addr = VARR_ADDR (bitmap_el_t, bm);
for (i = 0; i < len; i++) {
if ((el = addr[i]) != 0) {
for (nb = 0; el != 0; el >>= 1, nb++)
if (el & 1) func (i * BITMAP_WORD_BITS + nb, data);
}
}
}
#endif /* #ifndef MIR_BITMAP_H */

@ -0,0 +1,175 @@
/* This file is part of MIR project.
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* Typed doubly linked lists. */
#ifndef MIR_DLIST_H
#define MIR_DLIST_H
#include <stdio.h>
#include <assert.h>
#if !defined(DLIST_ENABLE_CHECKING) && !defined(NDEBUG)
#define DLIST_ENABLE_CHECKING
#endif
#ifndef DLIST_ENABLE_CHECKING
#define DLIST_ASSERT(EXPR, OP, T) ((void) (EXPR))
#else
static inline void dlist_assert_fail (const char* op, const char* var) {
fprintf (stderr, "wrong %s for %s", op, var);
assert (0);
}
#define DLIST_ASSERT(EXPR, OP, T) (void) ((EXPR) ? 0 : (dlist_assert_fail (OP, #T), 0))
#endif
#define DLIST(T) DLIST_##T
#define DLIST_OP(T, OP) DLIST_##T##_##OP
#define DLIST_LINK(T) DLIST_LINK_##T
#define DLIST_LINK_T(T) \
typedef struct DLIST_LINK (T) { \
T prev, next; \
} DLIST_LINK (T)
#define DEF_DLIST_LINK(T) DLIST_LINK_T (T);
#define DEF_DLIST_TYPE(T) \
typedef struct DLIST (T) { \
T head, tail; \
} DLIST (T)
#define DEF_DLIST_CODE(T, LINK) \
\
static inline void DLIST_OP (T, init) (DLIST (T) * list) { list->head = list->tail = NULL; } \
\
static inline T DLIST_OP (T, head) (DLIST (T) * list) { return list->head; } \
\
static inline T DLIST_OP (T, tail) (DLIST (T) * list) { return list->tail; } \
\
static inline T DLIST_OP (T, prev) (T elem) { return elem->LINK.prev; } \
static inline T DLIST_OP (T, next) (T elem) { return elem->LINK.next; } \
\
static inline T DLIST_OP (T, el) (DLIST (T) * list, int n) { \
T e; \
\
if (n >= 0) { \
for (e = list->head; e != NULL && n != 0; e = e->LINK.next, n--) \
; \
} else { \
for (e = list->tail; e != NULL && n != -1; e = e->LINK.prev, n++) \
; \
} \
return e; \
} \
\
static inline void DLIST_OP (T, prepend) (DLIST (T) * list, T elem) { \
DLIST_ASSERT (list&& elem, "prepend", T); \
if (list->head == NULL) { \
DLIST_ASSERT (list->tail == NULL, "prepend", T); \
list->tail = elem; \
} else { \
DLIST_ASSERT (list->head->LINK.prev == NULL, "prepend", T); \
list->head->LINK.prev = elem; \
} \
elem->LINK.prev = NULL; \
elem->LINK.next = list->head; \
list->head = elem; \
} \
\
static inline void DLIST_OP (T, append) (DLIST (T) * list, T elem) { \
DLIST_ASSERT (list&& elem, "append", T); \
if (list->tail == NULL) { \
DLIST_ASSERT (list->head == NULL, "append", T); \
list->head = elem; \
} else { \
DLIST_ASSERT (list->tail->LINK.next == NULL, "append", T); \
list->tail->LINK.next = elem; \
} \
elem->LINK.next = NULL; \
elem->LINK.prev = list->tail; \
list->tail = elem; \
} \
\
static inline void DLIST_OP (T, insert_before) (DLIST (T) * list, T before, T elem) { \
DLIST_ASSERT (list&& before&& elem && list->tail, "insert_before", T); \
if (before->LINK.prev == NULL) { \
DLIST_ASSERT (list->head == before, "insert_before", T); \
before->LINK.prev = elem; \
elem->LINK.next = before; \
elem->LINK.prev = NULL; \
list->head = elem; \
} else { \
DLIST_ASSERT (list->head, "insert_before", T); \
before->LINK.prev->LINK.next = elem; \
elem->LINK.prev = before->LINK.prev; \
before->LINK.prev = elem; \
elem->LINK.next = before; \
} \
} \
\
static inline void DLIST_OP (T, insert_after) (DLIST (T) * list, T after, T elem) { \
DLIST_ASSERT (list&& after&& elem && list->head, "insert_after", T); \
if (after->LINK.next == NULL) { \
DLIST_ASSERT (list->tail == after, "insert_after", T); \
after->LINK.next = elem; \
elem->LINK.prev = after; \
elem->LINK.next = NULL; \
list->tail = elem; \
} else { \
DLIST_ASSERT (list->tail, "insert_after", T); \
after->LINK.next->LINK.prev = elem; \
elem->LINK.next = after->LINK.next; \
after->LINK.next = elem; \
elem->LINK.prev = after; \
} \
} \
\
static inline void DLIST_OP (T, remove) (DLIST (T) * list, T elem) { \
DLIST_ASSERT (list&& elem, "remove", T); \
if (elem->LINK.prev != NULL) { \
elem->LINK.prev->LINK.next = elem->LINK.next; \
} else { \
DLIST_ASSERT (list->head == elem, "remove", T); \
list->head = elem->LINK.next; \
} \
if (elem->LINK.next != NULL) { \
elem->LINK.next->LINK.prev = elem->LINK.prev; \
} else { \
DLIST_ASSERT (list->tail == elem, "remove", T); \
list->tail = elem->LINK.prev; \
} \
elem->LINK.prev = elem->LINK.next = NULL; \
} \
\
static inline size_t DLIST_OP (T, length) (DLIST (T) * list) { \
size_t len = 0; \
T curr; \
\
for (curr = list->head; curr != NULL; curr = curr->LINK.next) len++; \
return len; \
}
#define DEF_DLIST(T, LINK) \
DEF_DLIST_TYPE (T); \
DEF_DLIST_CODE (T, LINK)
#define DLIST_INIT(T, L) (DLIST_OP (T, init) (&(L)))
#define DLIST_HEAD(T, L) (DLIST_OP (T, head) (&(L)))
#define DLIST_TAIL(T, L) (DLIST_OP (T, tail) (&(L)))
#define DLIST_PREV(T, E) (DLIST_OP (T, prev) (E))
#define DLIST_NEXT(T, E) (DLIST_OP (T, next) (E))
#define DLIST_EL(T, L, N) (DLIST_OP (T, el) (&(L), N))
#define DLIST_PREPEND(T, L, E) (DLIST_OP (T, prepend) (&(L), (E)))
#define DLIST_APPEND(T, L, E) (DLIST_OP (T, append) (&(L), (E)))
#define DLIST_INSERT_BEFORE(T, L, B, E) (DLIST_OP (T, insert_before) (&(L), (B), (E)))
#define DLIST_INSERT_AFTER(T, L, A, E) (DLIST_OP (T, insert_after) (&(L), (A), (E)))
#define DLIST_REMOVE(T, L, E) (DLIST_OP (T, remove) (&(L), (E)))
#define DLIST_LENGTH(T, L) (DLIST_OP (T, length) (&(L)))
#endif /* #ifndef MIR_DLIST_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,22 @@
/* This file is a part of MIR project.
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
#ifndef MIR_GEN_H
#define MIR_GEN_H
#include "mir.h"
#ifndef MIR_GEN_DEBUG
#define MIR_GEN_DEBUG 0
#endif
extern void MIR_gen_init (MIR_context_t context);
extern void MIR_gen_set_debug_file (MIR_context_t context, FILE *f);
extern void *MIR_gen (MIR_context_t context, MIR_item_t func_item);
extern void MIR_set_gen_interface (MIR_context_t context, MIR_item_t func_item);
extern void MIR_set_lazy_gen_interface (MIR_context_t context, MIR_item_t func_item);
extern void MIR_gen_finish (MIR_context_t context);
#endif /* #ifndef MIR_GEN_H */

@ -0,0 +1,92 @@
/* This file is a part of MIR project.
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* Simple high-quality multiplicative hash passing demerphq-smhsher,
faster than spooky, city, or xxhash for strings less 100 bytes.
Hash for the same key can be different on different architectures.
To get machine-independent hash, use mir_hash_strict which is about
1.5 times slower than mir_hash. */
#ifndef __MIR_HASH__
#define __MIR_HASH__
#include <stddef.h>
#include <stdint.h>
#if defined(__x86_64__) || defined(__i386__) || defined(__PPC64__) || defined(__s390__) \
|| defined(__m32c__) || defined(cris) || defined(__CR16__) || defined(__vax__) \
|| defined(__m68k__) || defined(__aarch64__) || defined(_M_AMD64) || defined(_M_IX86)
#define MIR_HASH_UNALIGNED_ACCESS 1
#else
#define MIR_HASH_UNALIGNED_ACCESS 0
#endif
static inline uint64_t mir_get_key_part (const uint8_t *v, size_t len, int relax_p) {
size_t i, start = 0;
uint64_t tail = 0;
if (relax_p || __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) {
#if MIR_HASH_UNALIGNED_ACCESS
if (len == sizeof (uint64_t)) return *(uint64_t *) v;
if (len >= sizeof (uint32_t)) {
tail = (uint64_t) * (uint32_t *) v << 32;
start = 4;
}
#endif
}
for (i = start; i < len; i++) tail = (tail >> 8) | ((uint64_t) v[i] << 56);
return tail;
}
static const uint64_t p1 = 0X65862b62bdf5ef4d, p2 = 0X288eea216831e6a7;
static inline uint64_t mir_mum (uint64_t v, uint64_t c, int relax_p) {
if (relax_p) {
#if defined(__SIZEOF_INT128__)
__uint128_t r = (__uint128_t) v * (__uint128_t) c;
return (uint64_t) (r >> 64) + (uint64_t) r;
#endif
}
uint64_t v1 = v >> 32, v2 = (uint32_t) v, c1 = c >> 32, c2 = (uint32_t) c, rm = v2 * c1 + v1 * c2;
return v1 * c1 + (rm >> 32) + v2 * c2 + (rm << 32);
}
static inline uint64_t mir_round (uint64_t state, uint64_t v, int relax_p) {
state ^= mir_mum (v, p1, relax_p);
return state ^ mir_mum (state, p2, relax_p);
}
static inline uint64_t mir_hash_1 (const void *key, size_t len, uint64_t seed, int relax_p) {
const uint8_t *v = (const uint8_t *) key;
uint64_t r = seed + len;
for (; len >= 16; len -= 16, v += 16) {
r ^= mir_mum (mir_get_key_part (v, 8, relax_p), p1, relax_p);
r ^= mir_mum (mir_get_key_part (v + 8, 8, relax_p), p2, relax_p);
r ^= mir_mum (r, p1, relax_p);
}
if (len >= 8) {
r ^= mir_mum (mir_get_key_part (v, 8, relax_p), p1, relax_p);
len -= 8, v += 8;
}
if (len != 0) r ^= mir_mum (mir_get_key_part (v, len, relax_p), p2, relax_p);
return mir_round (r, r, relax_p);
}
static inline uint64_t mir_hash (const void *key, size_t len, uint64_t seed) {
return mir_hash_1 (key, len, seed, 1);
}
static inline uint64_t mir_hash_strict (const void *key, size_t len, uint64_t seed) {
return mir_hash_1 (key, len, seed, 0);
}
static inline uint64_t mir_hash_init (uint64_t seed) { return seed; }
static inline uint64_t mir_hash_step (uint64_t h, uint64_t key) { return mir_round (h, key, 1); }
static inline uint64_t mir_hash_finish (uint64_t h) { return mir_round (h, h, 1); }
static inline uint64_t mir_hash64 (uint64_t key, uint64_t seed) {
return mir_hash_finish (mir_hash_step (mir_hash_init (seed), key));
}
#endif

@ -0,0 +1,221 @@
/* This file is a part of MIR project.
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
#ifndef MIR_HTAB_H
#define MIR_HTAB_H
#include "mir-varr.h"
#define FALSE 0
#define TRUE 1
#if !defined(VARR_ENABLE_CHECKING) && !defined(NDEBUG)
#define VARR_ENABLE_CHECKING
#endif
#ifndef HTAB_ENABLE_CHECKING
#define HTAB_ASSERT(EXPR, OP, T) ((void) (EXPR))
#else
static inline void mir_htab_assert_fail (const char *op, const char *var) {
fprintf (stderr, "wrong %s for %s\n", op, var);
assert (0);
}
#define HTAB_ASSERT(EXPR, OP, T) (void) ((EXPR) ? 0 : (mir_htab_assert_fail (OP, #T), 0))
#endif
#ifdef __GNUC__
#define MIR_HTAB_NO_RETURN __attribute__ ((noreturn))
#else
#define MIR_HTAB_NO_RETURN
#endif
static inline void MIR_HTAB_NO_RETURN mir_htab_error (const char *message) {
#ifdef MIR_HTAB_ERROR
MIR_HTAB_ERROR (message);
assert (FALSE);
#else
fprintf (stderr, "%s\n", message);
#endif
exit (1);
}
/*---------------- Typed hash table -----------------------------*/
typedef unsigned htab_ind_t;
typedef unsigned htab_size_t;
typedef unsigned htab_hash_t;
#define HTAB_EMPTY_IND (~(htab_ind_t) 0)
#define HTAB_DELETED_IND (HTAB_EMPTY_IND - 1)
#define HTAB_DELETED_HASH 0
enum htab_action { HTAB_FIND, HTAB_INSERT, HTAB_REPLACE, HTAB_DELETE };
#define HTAB(T) HTAB_##T
#define HTAB_OP(T, OP) HTAB_##T##_##OP
DEF_VARR (htab_ind_t)
#define HTAB_EL(T) HTAB_EL_##T
#define HTAB_T(T) \
typedef struct HTAB_EL (T) { \
htab_hash_t hash; \
T el; \
} HTAB_EL (T); \
DEF_VARR (HTAB_EL (T)) \
typedef struct { \
htab_size_t els_num, els_start, els_bound, collisions; \
htab_hash_t (*hash_func) (T el); \
int (*eq_func) (T el1, T el2); \
void (*free_func) (T el); \
VARR (HTAB_EL (T)) * els; \
VARR (htab_ind_t) * entries; \
} HTAB (T);
#define DEF_HTAB(T) \
HTAB_T (T) \
\
static inline void HTAB_OP (T, create) (HTAB (T) * *htab, htab_size_t min_size, \
htab_hash_t (*hash_func) (T el), \
int (*eq_func) (T el1, T el2), \
void (*free_func) (T el)) { \
HTAB (T) * ht; \
htab_size_t i, size; \
\
for (size = 2; min_size > size; size *= 2) \
; \
ht = malloc (sizeof (*ht)); \
if (ht == NULL) mir_htab_error ("htab: no memory"); \
VARR_CREATE (HTAB_EL (T), ht->els, size); \
VARR_TAILOR (HTAB_EL (T), ht->els, size); \
VARR_CREATE (htab_ind_t, ht->entries, 2 * size); \
ht->hash_func = hash_func; \
ht->eq_func = eq_func; \
ht->free_func = free_func; \
ht->els_num = ht->els_start = ht->els_bound = ht->collisions = 0; \
for (i = 0; i < 2 * size; i++) VARR_PUSH (htab_ind_t, ht->entries, HTAB_EMPTY_IND); \
*htab = ht; \
} \
\
static inline void HTAB_OP (T, clear) (HTAB (T) * htab) { \
htab_ind_t *addr; \
htab_size_t i, size; \
HTAB_EL (T) * els_addr; \
\
HTAB_ASSERT (htab != NULL, "clear", T); \
if (htab->free_func != NULL) { \
els_addr = VARR_ADDR (HTAB_EL (T), htab->els); \
size = VARR_LENGTH (HTAB_EL (T), htab->els); \
for (i = 0; i < htab->els_bound; i++) \
if (els_addr[i].hash != HTAB_DELETED_HASH) htab->free_func (els_addr[i].el); \
} \
htab->els_num = htab->els_start = htab->els_bound = 0; \
addr = VARR_ADDR (htab_ind_t, htab->entries); \
size = VARR_LENGTH (htab_ind_t, htab->entries); \
for (i = 0; i < size; i++) addr[i] = HTAB_EMPTY_IND; \
} \
\
static inline void HTAB_OP (T, destroy) (HTAB (T) * *htab) { \
HTAB_ASSERT (*htab != NULL, "destroy", T); \
if ((*htab)->free_func != NULL) HTAB_OP (T, clear) (*htab); \
VARR_DESTROY (HTAB_EL (T), (*htab)->els); \
VARR_DESTROY (htab_ind_t, (*htab)->entries); \
free (*htab); \
*htab = NULL; \
} \
\
static inline int HTAB_OP (T, do) (HTAB (T) * htab, T el, enum htab_action action, T * res) { \
htab_ind_t ind, el_ind, *entry, *first_deleted_entry = NULL; \
htab_hash_t hash, peterb; \
htab_size_t els_size, size, mask, start, bound, i; \
htab_ind_t *addr; \
HTAB_EL (T) * els_addr; \
\
HTAB_ASSERT (htab != NULL, "do htab", T); \
size = VARR_LENGTH (htab_ind_t, htab->entries); \
els_size = VARR_LENGTH (HTAB_EL (T), htab->els); \
HTAB_ASSERT (els_size * 2 == size, "do size", T); \
if ((action == HTAB_INSERT || action == HTAB_REPLACE) && htab->els_bound == els_size) { \
size *= 2; \
VARR_TAILOR (htab_ind_t, htab->entries, size); \
addr = VARR_ADDR (htab_ind_t, htab->entries); \
for (i = 0; i < size; i++) addr[i] = HTAB_EMPTY_IND; \
VARR_TAILOR (HTAB_EL (T), htab->els, els_size * 2); \
els_addr = VARR_ADDR (HTAB_EL (T), htab->els); \
start = htab->els_start; \
bound = htab->els_bound; \
htab->els_start = htab->els_bound = htab->els_num = 0; \
for (i = start; i < bound; i++) \
if (els_addr[i].hash != HTAB_DELETED_HASH) { \
HTAB_OP (T, do) (htab, els_addr[i].el, HTAB_INSERT, res); \
HTAB_ASSERT ((*htab->eq_func) (*res, els_addr[i].el), "do expand", T); \
} \
HTAB_ASSERT (bound - start >= htab->els_bound, "do bound", T); \
} \
mask = size - 1; \
hash = (*htab->hash_func) (el); \
if (hash == HTAB_DELETED_HASH) hash += 1; \
peterb = hash; \
ind = hash & mask; \
addr = VARR_ADDR (htab_ind_t, htab->entries); \
els_addr = VARR_ADDR (HTAB_EL (T), htab->els); \
for (;; htab->collisions++) { \
entry = addr + ind; \
el_ind = *entry; \
if (el_ind != HTAB_EMPTY_IND) { \
if (el_ind == HTAB_DELETED_IND) { \
first_deleted_entry = entry; \
} else if (els_addr[el_ind].hash == hash && (*htab->eq_func) (els_addr[el_ind].el, el)) { \
if (action == HTAB_REPLACE) { \
if (htab->free_func != NULL) htab->free_func (els_addr[el_ind].el); \
els_addr[el_ind].el = el; \
} \
if (action != HTAB_DELETE) { \
*res = els_addr[el_ind].el; \
} else { \
htab->els_num--; \
*entry = HTAB_DELETED_IND; \
if (htab->free_func != NULL) htab->free_func (els_addr[el_ind].el); \
els_addr[el_ind].hash = HTAB_DELETED_HASH; \
} \
return TRUE; \
} \
} else { \
if (action == HTAB_INSERT || action == HTAB_REPLACE) { \
htab->els_num++; \
if (first_deleted_entry != NULL) entry = first_deleted_entry; \
els_addr[htab->els_bound].hash = hash; \
els_addr[htab->els_bound].el = el; \
*entry = htab->els_bound++; \
*res = el; \
} \
return FALSE; \
} \
peterb >>= 11; \
ind = (5 * ind + peterb + 1) & mask; \
} \
} \
\
static inline htab_size_t HTAB_OP (T, els_num) (HTAB (T) * htab) { \
HTAB_ASSERT (htab != NULL, "els_num", T); \
return htab->els_num; \
} \
static inline htab_size_t HTAB_OP (T, collisions) (HTAB (T) * htab) { \
HTAB_ASSERT (htab != NULL, "collisions", T); \
return htab->collisions; \
}
#define HTAB_CREATE(T, V, S, H, EQ) (HTAB_OP (T, create) (&(V), S, H, EQ, NULL))
#define HTAB_CREATE_WITH_FREE_FUNC(T, V, S, H, EQ, F) (HTAB_OP (T, create) (&(V), S, H, EQ, F))
#define HTAB_CLEAR(T, V) (HTAB_OP (T, clear) (V))
#define HTAB_DESTROY(T, V) (HTAB_OP (T, destroy) (&(V)))
/* It returns TRUE if the element existed in the table. */
#define HTAB_DO(T, V, EL, A, TAB_EL) (HTAB_OP (T, do) (V, EL, A, &(TAB_EL)))
#define HTAB_ELS_NUM(T, V) (HTAB_OP (T, els_num) (V))
#define HTAB_COLLISIONS(T, V) (HTAB_OP (T, collisions) (V))
#endif /* #ifndef MIR_HTAB_H */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,463 @@
/* This file is a part of MIR project.
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
#ifndef MIR_REDUCE_H
#define MIR_REDUCE_H
/* Data compression. Major goals are simplicity, fast decompression
speed, moderate compression speed. The algorithm is tuned for
binary MIR compression and close to LZ4. Only we use a bit
different format and offsets in symbol numbers instead of just
offsets.
A better compression (on par with LZ4) could be achieved by adding
elements for all positions (now positions inside referenced symbols
are excluded) or/and increasing the buffer or/and increasing the
table. But it would slow down the compression or/and increase the
used memory.
Functions reduce_encode, reduce_decode, reduce_encode_start,
reduce_encode_put, reduce_encode_finish, reduce_decode_start,
reduce_decode_get, reduce_decode_finish are the only interface
functions.
Format of compressed data: "MIR", elements*, zero byte, 8-byte check hash in little endian form
Format of element:
o 8 bits tag
(N bits for symbol length; 0 means no sym, 2^N -1 means symbol length as uint present;
(8-N) bits for reference length; 0 means no ref, 2^(8-N) - 1 means length as uint present)
o [uint for symbol lenght]*, symbol string,
o [uint for ref len]*, symbol number as uint */
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "mir-hash.h"
#define FALSE 0
#define TRUE 1
#define _REDUCE_DATA_PREFIX "MIR" /* first chars of compressed data */
#define _REDUCE_SYMB_TAG_LEN 3 /* for some application could be 4 */
#define _REDUCE_SYMB_TAG_LONG ((1 << _REDUCE_SYMB_TAG_LEN) - 1) /* should be not changed */
#define _REDUCE_REF_TAG_LEN (8 - _REDUCE_SYMB_TAG_LEN)
#define _REDUCE_REF_TAG_LONG ((1 << _REDUCE_REF_TAG_LEN) - 1) /* should be not changed */
#define _REDUCE_START_LEN 4 /* Should be at least 4 */
#define _REDUCE_BUF_LEN (1 << 18)
/* The following should be power of two. There will be no space saving if it is less than 1/4 of buf
length. */
#define _REDUCE_TABLE_SIZE (_REDUCE_BUF_LEN / 4)
#define _REDUCE_MAX_SYMB_LEN (2047)
typedef size_t (*reduce_reader_t) (void *start, size_t len, void *aux_data);
typedef size_t (*reduce_writer_t) (const void *start, size_t len, void *aux_data);
struct _reduce_el {
uint32_t pos, num, next, head;
};
struct _reduce_encode_data {
reduce_writer_t writer;
uint32_t el_free;
uint32_t curr_symb_len;
uint8_t curr_symb[_REDUCE_MAX_SYMB_LEN];
struct _reduce_el table[_REDUCE_TABLE_SIZE]; /* hash -> el */
};
struct _reduce_decode_data {
uint8_t eof_p;
uint32_t buf_get_pos;
reduce_reader_t reader;
uint32_t ind2pos[_REDUCE_BUF_LEN];
};
struct reduce_data {
union {
struct _reduce_encode_data encode;
struct _reduce_decode_data decode;
} u;
void *aux_data;
uint8_t ok_p;
uint64_t check_hash;
uint32_t curr_num, buf_bound;
uint8_t buf[_REDUCE_BUF_LEN];
};
static inline uint32_t _reduce_min (uint32_t a, uint32_t b) { return a < b ? a : b; }
static inline uint32_t _reduce_get_new_el (struct reduce_data *data) {
struct _reduce_encode_data *encode_data = &data->u.encode;
uint32_t res = encode_data->el_free;
if (res != UINT32_MAX) encode_data->el_free = encode_data->table[res].next;
return res;
}
static inline void _reduce_put (struct reduce_data *data, int byte) {
uint8_t u = byte;
if (data->u.encode.writer (&u, 1, data->aux_data) != 1) data->ok_p = FALSE;
}
static inline int _reduce_get (reduce_reader_t reader, void *aux_data) {
uint8_t u;
if (reader (&u, 1, aux_data) != 1) return -1;
return u;
}
static inline uint32_t _reduce_ref_offset_size (uint32_t offset) {
return offset < (1 << 7) ? 1 : offset < (1 << 14) ? 2 : offset < (1 << 21) ? 3 : 4;
}
static inline uint32_t _reduce_ref_size (uint32_t len, uint32_t offset) {
assert (len >= _REDUCE_START_LEN);
len -= _REDUCE_START_LEN - 1;
return ((len < _REDUCE_REF_TAG_LONG ? 0 : _reduce_ref_offset_size (len))
+ _reduce_ref_offset_size (offset));
}
static inline void _reduce_uint_write (struct reduce_data *data, uint32_t u) {
int n;
assert (u < (1 << 7 * 4));
for (n = 1; n <= 4 && u >= (1 << 7 * n); n++)
;
_reduce_put (data, (1 << (8 - n)) | (u >> (n - 1) * 8) & 0xff); /* tag */
for (int i = 2; i <= n; i++) _reduce_put (data, (u >> (n - i) * 8) & 0xff);
}
static inline int64_t _reduce_uint_read (reduce_reader_t reader, void *aux_data) {
int i, n, r = _reduce_get (reader, aux_data);
uint32_t u, v;
if (r < 0) return -1;
for (u = (uint32_t) r, n = 1; n <= 4 && (u >> (8 - n)) != 1; n++)
;
assert ((u >> (8 - n)) == 1);
v = u & (0xff >> n);
for (i = 1; i < n; i++) {
if ((r = _reduce_get (reader, aux_data)) < 0) return -1;
v = v * 256 + (uint32_t) r;
}
return v;
}
static inline void _reduce_hash_write (struct reduce_data *data, uint64_t h) {
_reduce_put (data, 0); /* 0 tag */
for (int i = 0; i < sizeof (uint64_t); i++) _reduce_put (data, (h >> i * 8) & 0xff);
}
static inline uint64_t _reduce_str2hash (const uint8_t *s) {
uint64_t h = 0;
for (int i = 0; i < sizeof (uint64_t); i++) h |= (uint64_t) s[i] << i * 8;
return h;
}
static inline int _reduce_symb_flush (struct reduce_data *data, int ref_tag) {
uint8_t u;
struct _reduce_encode_data *encode_data = &data->u.encode;
uint32_t len = encode_data->curr_symb_len;
if (len == 0 && ref_tag == 0) return FALSE;
u = ((len < _REDUCE_SYMB_TAG_LONG ? len : _REDUCE_SYMB_TAG_LONG) << _REDUCE_REF_TAG_LEN)
| ref_tag;
encode_data->writer (&u, 1, data->aux_data);
if (len >= _REDUCE_SYMB_TAG_LONG) _reduce_uint_write (data, len);
encode_data->writer (encode_data->curr_symb, len, data->aux_data);
encode_data->curr_symb_len = 0;
return TRUE;
}
static inline void _reduce_output_byte (struct reduce_data *data, uint32_t pos) {
struct _reduce_encode_data *encode_data = &data->u.encode;
if (encode_data->curr_symb_len + 1 > _REDUCE_MAX_SYMB_LEN) {
_reduce_symb_flush (data, 0);
encode_data->curr_symb_len = 0;
}
encode_data->curr_symb[encode_data->curr_symb_len++] = data->buf[pos];
}
static inline void _reduce_output_ref (struct reduce_data *data, uint32_t offset, uint32_t len) {
uint32_t ref_tag;
assert (len >= _REDUCE_START_LEN);
len -= _REDUCE_START_LEN - 1;
ref_tag = len < _REDUCE_REF_TAG_LONG ? len : _REDUCE_REF_TAG_LONG;
_reduce_symb_flush (data, ref_tag);
if (len >= _REDUCE_REF_TAG_LONG) _reduce_uint_write (data, len);
_reduce_uint_write (data, offset);
}
#define _REDUCE_HASH_SEED 24
static inline uint32_t _reduce_dict_find_longest (struct reduce_data *data, uint32_t pos,
uint32_t *dict_pos) {
uint32_t len, best_len, len_bound;
uint64_t hash;
uint32_t off, best_off, ref_size, best_ref_size;
uint32_t curr, prev, next;
const uint8_t *s1, *s2;
struct _reduce_el *el, *best_el = NULL;
struct _reduce_encode_data *encode_data = &data->u.encode;
if (pos + _REDUCE_START_LEN > data->buf_bound) return 0;
/* To have the same compressed output independently of the target
and the used compiler, use strict hash even if it decreases
compression speed by 10%. */
hash
= mir_hash_strict (&data->buf[pos], _REDUCE_START_LEN, _REDUCE_HASH_SEED) % _REDUCE_TABLE_SIZE;
for (curr = encode_data->table[hash].head, prev = UINT32_MAX; curr != UINT32_MAX;
prev = curr, curr = next) {
next = encode_data->table[curr].next;
el = &encode_data->table[curr];
len_bound = _reduce_min (data->buf_bound - pos, pos - el->pos);
if (len_bound < _REDUCE_START_LEN) continue;
s1 = &data->buf[el->pos];
s2 = &data->buf[pos];
#if MIR_HASH_UNALIGNED_ACCESS
assert (_REDUCE_START_LEN >= 4);
if (*(uint32_t *) &s1[0] != *(uint32_t *) &s2[0]) continue;
len = 4;
#else
len = 0;
#endif
for (; len < len_bound; len++)
if (s1[len] != s2[len]) break;
#if !MIR_HASH_UNALIGNED_ACCESS
if (len < _REDUCE_START_LEN) continue;
#endif
off = data->curr_num - el->num;
if (best_el == NULL) {
best_len = len;
best_el = el;
best_ref_size = _reduce_ref_size (len, off);
continue;
}
best_off = data->curr_num - best_el->num;
ref_size = _reduce_ref_size (len, off);
if (best_len + ref_size < len + best_ref_size) {
best_len = len;
best_el = el;
best_ref_size = ref_size;
}
}
if (best_el == NULL) return 0;
*dict_pos = best_el->num;
return best_len;
}
static inline void _reduce_dict_add (struct reduce_data *data, uint32_t pos) {
uint64_t hash;
struct _reduce_el *el;
uint32_t prev, curr, num = data->curr_num++;
struct _reduce_encode_data *encode_data = &data->u.encode;
if (pos + _REDUCE_START_LEN > data->buf_bound) return;
hash
= mir_hash_strict (&data->buf[pos], _REDUCE_START_LEN, _REDUCE_HASH_SEED) % _REDUCE_TABLE_SIZE;
if ((curr = _reduce_get_new_el (data)) == UINT32_MAX) { /* rare case: use last if any */
for (prev = UINT32_MAX, curr = encode_data->table[hash].head;
curr != UINT32_MAX && encode_data->table[curr].next != UINT32_MAX;
prev = curr, curr = encode_data->table[curr].next)
;
if (curr == UINT32_MAX) return; /* no more free els */
if (prev != UINT32_MAX)
encode_data->table[prev].next = encode_data->table[curr].next;
else
encode_data->table[hash].head = encode_data->table[curr].next;
}
encode_data->table[curr].pos = pos;
encode_data->table[curr].num = num;
encode_data->table[curr].next = encode_data->table[hash].head;
encode_data->table[hash].head = curr;
}
static void _reduce_reset_next (struct reduce_data *data) {
struct _reduce_encode_data *encode_data = &data->u.encode;
for (uint32_t i = 0; i < _REDUCE_TABLE_SIZE; i++) {
encode_data->table[i].next = i + 1;
encode_data->table[i].head = UINT32_MAX;
}
encode_data->table[_REDUCE_TABLE_SIZE - 1].next = UINT32_MAX;
encode_data->el_free = 0;
}
#define _REDUCE_CHECK_HASH_SEED 42
static inline struct reduce_data *reduce_encode_start (reduce_writer_t writer, void *aux_data) {
struct reduce_data *data = malloc (sizeof (struct reduce_data));
char prefix[] = _REDUCE_DATA_PREFIX;
size_t prefix_size = strlen (prefix);
if (data == NULL) return data;
data->u.encode.writer = writer;
data->aux_data = aux_data;
data->check_hash = _REDUCE_CHECK_HASH_SEED;
data->buf_bound = 0;
data->ok_p = writer (prefix, prefix_size, aux_data) == prefix_size;
return data;
}
static inline void _reduce_encode_buf (struct reduce_data *data) {
uint32_t dict_len, dict_pos, base;
if (data->buf_bound == 0) return;
data->check_hash = mir_hash_strict (data->buf, data->buf_bound, data->check_hash);
data->curr_num = data->u.encode.curr_symb_len = 0;
_reduce_reset_next (data);
for (uint32_t pos = 0; pos < data->buf_bound;) {
dict_len = _reduce_dict_find_longest (data, pos, &dict_pos);
base = data->curr_num;
if (dict_len == 0) {
_reduce_output_byte (data, pos);
_reduce_dict_add (data, pos);
pos++;
continue;
}
_reduce_output_ref (data, base - dict_pos, dict_len);
_reduce_dict_add (data, pos); /* replace */
pos += dict_len;
}
_reduce_symb_flush (data, 0);
}
static inline void reduce_encode_put (struct reduce_data *data, int c) {
if (data->buf_bound < _REDUCE_BUF_LEN) {
data->buf[data->buf_bound++] = c;
return;
}
_reduce_encode_buf (data);
data->buf_bound = 0;
data->buf[data->buf_bound++] = c;
}
static inline int reduce_encode_finish (struct reduce_data *data) {
int ok_p;
_reduce_encode_buf (data);
_reduce_hash_write (data, data->check_hash);
ok_p = data->ok_p;
free (data);
return ok_p;
}
static inline struct reduce_data *reduce_decode_start (reduce_reader_t reader, void *aux_data) {
struct reduce_data *data = malloc (sizeof (struct reduce_data));
struct _reduce_decode_data *decode_data = &data->u.decode;
char prefix[] = _REDUCE_DATA_PREFIX, str[sizeof (prefix)];
size_t prefix_size = strlen (prefix);
if (data == NULL) return data;
decode_data->reader = reader;
data->aux_data = aux_data;
data->check_hash = _REDUCE_CHECK_HASH_SEED;
decode_data->buf_get_pos = data->buf_bound = 0;
data->ok_p
= reader (str, prefix_size, aux_data) == prefix_size && memcmp (prefix, str, prefix_size) == 0;
decode_data->eof_p = FALSE;
return data;
}
static inline int reduce_decode_get (struct reduce_data *data) {
uint8_t tag, hash_str[sizeof (uint64_t)];
uint32_t sym_len, ref_len, ref_ind, sym_pos, pos = 0, curr_ind = 0;
uint64_t r;
struct _reduce_decode_data *decode_data = &data->u.decode;
reduce_reader_t reader = decode_data->reader;
if (decode_data->buf_get_pos < data->buf_bound) return data->buf[decode_data->buf_get_pos++];
if (decode_data->eof_p) return -1;
for (;;) {
if (reader (&tag, 1, data->aux_data) == 0) break;
if (tag == 0) { /* check hash */
if (reader (hash_str, sizeof (hash_str), data->aux_data) != sizeof (hash_str)
|| reader (&tag, 1, data->aux_data) != 0)
break;
if (pos != 0) data->check_hash = mir_hash_strict (data->buf, pos, data->check_hash);
if (_reduce_str2hash (hash_str) != data->check_hash) break;
decode_data->eof_p = TRUE;
decode_data->buf_get_pos = 0;
data->buf_bound = pos;
return pos == 0 ? -1 : data->buf[decode_data->buf_get_pos++];
}
sym_len = tag >> _REDUCE_REF_TAG_LEN;
if (sym_len != 0) {
if (sym_len == _REDUCE_SYMB_TAG_LONG) {
if ((r = _reduce_uint_read (reader, data->aux_data)) < 0) break;
sym_len = r;
}
if (sym_len > _REDUCE_MAX_SYMB_LEN || pos + sym_len > _REDUCE_BUF_LEN) break;
if (reader (&data->buf[pos], sym_len, data->aux_data) != sym_len) break;
for (uint32_t i = 0; i < sym_len; i++, pos++, curr_ind++)
decode_data->ind2pos[curr_ind] = pos;
}
ref_len = tag & _REDUCE_REF_TAG_LONG;
if (ref_len != 0) {
if (ref_len == _REDUCE_REF_TAG_LONG) {
if ((r = _reduce_uint_read (reader, data->aux_data)) < 0) break;
ref_len = r;
}
ref_len += _REDUCE_START_LEN - 1;
if ((r = _reduce_uint_read (reader, data->aux_data)) < 0) break;
ref_ind = r;
if (curr_ind < ref_ind) break;
sym_pos = decode_data->ind2pos[curr_ind - ref_ind];
if (sym_pos + ref_len > _REDUCE_BUF_LEN) break;
memcpy (&data->buf[pos], &data->buf[sym_pos], ref_len);
decode_data->ind2pos[curr_ind++] = pos;
pos += ref_len;
}
if (pos >= _REDUCE_BUF_LEN) {
assert (pos == _REDUCE_BUF_LEN);
data->check_hash = mir_hash_strict (data->buf, pos, data->check_hash);
data->buf_bound = _REDUCE_BUF_LEN;
decode_data->buf_get_pos = 0;
return data->buf[decode_data->buf_get_pos++];
}
}
data->ok_p = FALSE;
return -1;
}
static inline int reduce_decode_finish (struct reduce_data *data) {
uint8_t tag;
int ok_p
= data->ok_p && data->u.decode.eof_p && data->u.decode.reader (&tag, 1, data->aux_data) == 0;
free (data);
return ok_p;
}
#define _REDUCE_WRITE_IO_LEN 256
static inline int reduce_encode (reduce_reader_t reader, reduce_writer_t writer, void *aux_data) {
size_t i, size;
uint8_t buf[_REDUCE_WRITE_IO_LEN];
struct reduce_data *data = reduce_encode_start (writer, aux_data);
if (data == NULL) return FALSE;
for (;;) {
if ((size = reader (buf, _REDUCE_WRITE_IO_LEN, data->aux_data)) == 0) break;
for (i = 0; i < size; i++) reduce_encode_put (data, buf[i]);
}
return reduce_encode_finish (data);
}
static inline int reduce_decode (reduce_reader_t reader, reduce_writer_t writer, void *aux_data) {
int c, i;
uint8_t buf[_REDUCE_WRITE_IO_LEN];
struct reduce_data *data = reduce_decode_start (reader, aux_data);
if (data == NULL) return FALSE;
for (;;) {
for (i = 0; i < _REDUCE_WRITE_IO_LEN && (c = reduce_decode_get (data)) >= 0; i++) buf[i] = c;
if (i != 0) writer (buf, i, aux_data);
if (c < 0) break;
}
return reduce_decode_finish (data);
}
#endif /* #ifndef MIR_REDUCE_H */

@ -0,0 +1,170 @@
/* This file is a part of MIR project.
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
#ifndef MIR_VARR_H
#define MIR_VARR_H
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#if !defined(VARR_ENABLE_CHECKING) && !defined(NDEBUG)
#define VARR_ENABLE_CHECKING
#endif
#ifndef VARR_ENABLE_CHECKING
#define VARR_ASSERT(EXPR, OP, T) ((void) (EXPR))
#else
static inline void mir_var_assert_fail (const char *op, const char *var) {
fprintf (stderr, "wrong %s for %s", op, var);
assert (0);
}
#define VARR_ASSERT(EXPR, OP, T) (void) ((EXPR) ? 0 : (mir_var_assert_fail (OP, #T), 0))
#endif
#ifdef __GNUC__
#define MIR_VARR_NO_RETURN __attribute__ ((noreturn))
#else
#define MIR_VARR_NO_RETURN
#endif
static inline void MIR_VARR_NO_RETURN mir_varr_error (const char *message) {
#ifdef MIR_VARR_ERROR
MIR_VARR_ERROR (message);
assert (0);
#else
fprintf (stderr, "%s\n", message);
#endif
exit (1);
}
/*---------------- Typed variable length arrays -----------------------------*/
#define VARR_CONCAT2(A, B) A##B
#define VARR_CONCAT3(A, B, C) A##B##C
#define VARR(T) VARR_CONCAT2 (VARR_, T)
#define VARR_OP(T, OP) VARR_CONCAT3 (VARR_, T, OP)
#define VARR_T(T) \
typedef struct VARR (T) { \
size_t els_num; \
size_t size; \
T *varr; \
} VARR (T)
#define VARR_DEFAULT_SIZE 64
/* Vector of pointer to object. */
#define DEF_VARR(T) \
VARR_T (T); \
\
static inline void VARR_OP (T, create) (VARR (T) * *varr, size_t size) { \
VARR (T) * va; \
if (size == 0) size = VARR_DEFAULT_SIZE; \
*varr = va = (VARR (T) *) malloc (sizeof (VARR (T))); \
if (va == NULL) mir_varr_error ("varr: no memory"); \
va->els_num = 0; \
va->size = size; \
va->varr = (T *) malloc (size * sizeof (T)); \
} \
\
static inline void VARR_OP (T, destroy) (VARR (T) * *varr) { \
VARR (T) *va = *varr; \
VARR_ASSERT (va && va->varr, "destroy", T); \
free (va->varr); \
free (va); \
*varr = NULL; \
} \
\
static inline size_t VARR_OP (T, length) (const VARR (T) * varr) { \
VARR_ASSERT (varr, "length", T); \
return varr->els_num; \
} \
\
static inline T *VARR_OP (T, addr) (const VARR (T) * varr) { \
VARR_ASSERT (varr, "addr", T); \
return &varr->varr[0]; \
} \
\
static inline T VARR_OP (T, last) (const VARR (T) * varr) { \
VARR_ASSERT (varr && varr->varr && varr->els_num, "last", T); \
return varr->varr[varr->els_num - 1]; \
} \
\
static inline T VARR_OP (T, get) (const VARR (T) * varr, unsigned ix) { \
VARR_ASSERT (varr && varr->varr && ix < varr->els_num, "get", T); \
return varr->varr[ix]; \
} \
\
static inline T VARR_OP (T, set) (const VARR (T) * varr, unsigned ix, T obj) { \
T old_obj; \
VARR_ASSERT (varr && varr->varr && ix < varr->els_num, "set", T); \
old_obj = varr->varr[ix]; \
varr->varr[ix] = obj; \
return old_obj; \
} \
\
static inline void VARR_OP (T, trunc) (VARR (T) * varr, size_t size) { \
VARR_ASSERT (varr && varr->varr && varr->els_num >= size, "trunc", T); \
varr->els_num = size; \
} \
\
static inline int VARR_OP (T, expand) (VARR (T) * varr, size_t size) { \
VARR_ASSERT (varr && varr->varr, "expand", T); \
if (varr->size < size) { \
size += size / 2; \
varr->varr = (T *) realloc (varr->varr, sizeof (T) * size); \
varr->size = size; \
return 1; \
} \
return 0; \
} \
\
static inline void VARR_OP (T, tailor) (VARR (T) * varr, size_t size) { \
VARR_ASSERT (varr && varr->varr, "tailor", T); \
if (varr->size != size) varr->varr = (T *) realloc (varr->varr, sizeof (T) * size); \
varr->els_num = varr->size = size; \
} \
\
static inline void VARR_OP (T, push) (VARR (T) * varr, T obj) { \
T *slot; \
VARR_OP (T, expand) (varr, varr->els_num + 1); \
slot = &varr->varr[varr->els_num++]; \
*slot = obj; \
} \
\
static inline void VARR_OP (T, push_arr) (VARR (T) * varr, const T *objs, size_t len) { \
size_t i; \
T *slot; \
VARR_OP (T, expand) (varr, varr->els_num + len); \
for (i = 0; i < len; i++) { \
slot = &varr->varr[varr->els_num++]; \
*slot = objs[i]; \
} \
} \
\
static inline T VARR_OP (T, pop) (VARR (T) * varr) { \
T obj; \
VARR_ASSERT (varr && varr->varr && varr->els_num, "pop", T); \
obj = varr->varr[--varr->els_num]; \
return obj; \
}
#define VARR_CREATE(T, V, L) (VARR_OP (T, create) (&(V), L))
#define VARR_DESTROY(T, V) (VARR_OP (T, destroy) (&(V)))
#define VARR_LENGTH(T, V) (VARR_OP (T, length) (V))
#define VARR_ADDR(T, V) (VARR_OP (T, addr) (V))
#define VARR_LAST(T, V) (VARR_OP (T, last) (V))
#define VARR_GET(T, V, I) (VARR_OP (T, get) (V, I))
#define VARR_SET(T, V, I, O) (VARR_OP (T, set) (V, I, O))
#define VARR_TRUNC(T, V, S) (VARR_OP (T, trunc) (V, S))
#define VARR_EXPAND(T, V, S) (VARR_OP (T, expand) (V, S))
#define VARR_TAILOR(T, V, S) (VARR_OP (T, tailor) (V, S))
#define VARR_PUSH(T, V, O) (VARR_OP (T, push) (V, O))
#define VARR_PUSH_ARR(T, V, A, L) (VARR_OP (T, push_arr) (V, A, L))
#define VARR_POP(T, V) (VARR_OP (T, pop) (V))
#endif /* #ifndef MIR_VARR_H */

@ -0,0 +1,354 @@
/* This file is a part of MIR project.
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
void *_MIR_get_bstart_builtin (MIR_context_t ctx) {
static const uint8_t bstart_code[] = {
0x48, 0x8d, 0x44, 0x24, 0x08, /* rax = rsp + 8 (lea) */
0xc3, /* ret */
};
return _MIR_publish_code (ctx, bstart_code, sizeof (bstart_code));
}
void *_MIR_get_bend_builtin (MIR_context_t ctx) {
static const uint8_t bend_code[] = {
0x48, 0x8b, 0x04, 0x24, /* rax = (rsp) */
0x48, 0x89, 0xfc, /* rsp = rdi */
0xff, 0xe0, /* jmp *rax */
};
return _MIR_publish_code (ctx, bend_code, sizeof (bend_code));
}
struct x86_64_va_list {
uint32_t gp_offset, fp_offset;
uint64_t *overflow_arg_area, *reg_save_area;
};
void *va_arg_builtin (void *p, uint64_t t) {
struct x86_64_va_list *va = p;
MIR_type_t type = t;
int fp_p = type == MIR_T_F || type == MIR_T_D;
void *a;
if (fp_p && va->fp_offset <= 160) {
a = (char *) va->reg_save_area + va->fp_offset;
va->fp_offset += 16;
} else if (!fp_p && type != MIR_T_LD && va->gp_offset <= 40) {
a = (char *) va->reg_save_area + va->gp_offset;
va->gp_offset += 8;
} else {
a = va->overflow_arg_area;
va->overflow_arg_area += type == MIR_T_LD ? 2 : 1;
}
return a;
}
void va_start_interp_builtin (MIR_context_t ctx, void *p, void *a) {
struct x86_64_va_list *va = p;
va_list *vap = a;
assert (sizeof (struct x86_64_va_list) == sizeof (va_list));
*va = *(struct x86_64_va_list *) vap;
}
void va_end_interp_builtin (MIR_context_t ctx, void *p) {}
/* r11=<address to go to>; jump *r11 */
void *_MIR_get_thunk (MIR_context_t ctx) {
void *res;
static const uint8_t pattern[] = {
0x49, 0xbb, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0: movabsq 0, r11 */
0x41, 0xff, 0xe3, /* 0x14: jmpq *%r11 */
};
res = _MIR_publish_code (ctx, pattern, sizeof (pattern));
return res;
}
void _MIR_redirect_thunk (MIR_context_t ctx, void *thunk, void *to) {
_MIR_update_code (ctx, thunk, 1, 2, to);
}
static const uint8_t save_pat[] = {
0x48, 0x81, 0xec, 0x80, 0, 0, 0, /*sub $0x80,%rsp */
0xf3, 0x0f, 0x7f, 0x04, 0x24, /*movdqu %xmm0,(%rsp) */
0xf3, 0x0f, 0x7f, 0x4c, 0x24, 0x10, /*movdqu %xmm1,0x10(%rsp) */
0xf3, 0x0f, 0x7f, 0x54, 0x24, 0x20, /*movdqu %xmm2,0x20(%rsp) */
0xf3, 0x0f, 0x7f, 0x5c, 0x24, 0x30, /*movdqu %xmm3,0x30(%rsp) */
0xf3, 0x0f, 0x7f, 0x64, 0x24, 0x40, /*movdqu %xmm4,0x40(%rsp) */
0xf3, 0x0f, 0x7f, 0x6c, 0x24, 0x50, /*movdqu %xmm5,0x50(%rsp) */
0xf3, 0x0f, 0x7f, 0x74, 0x24, 0x60, /*movdqu %xmm6,0x60(%rsp) */
0xf3, 0x0f, 0x7f, 0x7c, 0x24, 0x70, /*movdqu %xmm7,0x70(%rsp) */
0x41, 0x51, /*push %r9 */
0x41, 0x50, /*push %r8 */
0x51, /*push %rcx */
0x52, /*push %rdx */
0x56, /*push %rsi */
0x57, /*push %rdi */
};
static const uint8_t restore_pat[] = {
0x5f, /*pop %rdi */
0x5e, /*pop %rsi */
0x5a, /*pop %rdx */
0x59, /*pop %rcx */
0x41, 0x58, /*pop %r8 */
0x41, 0x59, /*pop %r9 */
0xf3, 0x0f, 0x6f, 0x04, 0x24, /*movdqu (%rsp),%xmm0 */
0xf3, 0x0f, 0x6f, 0x4c, 0x24, 0x10, /*movdqu 0x10(%rsp),%xmm1 */
0xf3, 0x0f, 0x6f, 0x54, 0x24, 0x20, /*movdqu 0x20(%rsp),%xmm2 */
0xf3, 0x0f, 0x6f, 0x5c, 0x24, 0x30, /*movdqu 0x30(%rsp),%xmm3 */
0xf3, 0x0f, 0x6f, 0x64, 0x24, 0x40, /*movdqu 0x40(%rsp),%xmm4 */
0xf3, 0x0f, 0x6f, 0x6c, 0x24, 0x50, /*movdqu 0x50(%rsp),%xmm5 */
0xf3, 0x0f, 0x6f, 0x74, 0x24, 0x60, /*movdqu 0x60(%rsp),%xmm6 */
0xf3, 0x0f, 0x6f, 0x7c, 0x24, 0x70, /*movdqu 0x70(%rsp),%xmm7 */
0x48, 0x81, 0xc4, 0x80, 0, 0, 0, /*add $0x80,%rsp */
};
static uint8_t *push_insns (MIR_context_t ctx, const uint8_t *pat, size_t pat_len) {
for (size_t i = 0; i < pat_len; i++) VARR_PUSH (uint8_t, machine_insns, pat[i]);
return VARR_ADDR (uint8_t, machine_insns) + VARR_LENGTH (uint8_t, machine_insns) - pat_len;
}
static void gen_mov (MIR_context_t ctx, uint32_t offset, uint32_t reg, int ld_p) {
static const uint8_t ld_gp_reg[] = {0x48, 0x8b, 0x83, 0, 0, 0, 0 /* mov <offset>(%rbx),%reg */};
static const uint8_t st_gp_reg[] = {0x48, 0x89, 0x83, 0, 0, 0, 0 /* mov %reg,<offset>(%rbx) */};
uint8_t *addr = push_insns (ctx, ld_p ? ld_gp_reg : st_gp_reg,
ld_p ? sizeof (ld_gp_reg) : sizeof (st_gp_reg));
memcpy (addr + 3, &offset, sizeof (uint32_t));
assert (reg <= 15);
addr[0] |= (reg >> 1) & 4;
addr[2] |= (reg & 7) << 3;
}
static void gen_movxmm (MIR_context_t ctx, uint32_t offset, uint32_t reg, int b32_p, int ld_p) {
static const uint8_t ld_xmm_reg_pat[] = {
0xf2, 0x0f, 0x10, 0x83, 0, 0, 0, 0 /* movs[sd] <offset>(%rbx),%xmm */
};
static const uint8_t st_xmm_reg_pat[] = {
0xf2, 0x0f, 0x11, 0x83, 0, 0, 0, 0 /* movs[sd] %xmm, <offset>(%rbx) */
};
uint8_t *addr = push_insns (ctx, ld_p ? ld_xmm_reg_pat : st_xmm_reg_pat,
ld_p ? sizeof (ld_xmm_reg_pat) : sizeof (st_xmm_reg_pat));
memcpy (addr + 4, &offset, sizeof (uint32_t));
assert (reg <= 7);
addr[3] |= reg << 3;
if (b32_p) addr[0] |= 1;
}
static void gen_ldst (MIR_context_t ctx, uint32_t sp_offset, uint32_t src_offset, int b64_p) {
static const uint8_t ldst_pat[] = {
0x44, 0x8b, 0x93, 0, 0, 0, 0, /* mov <src_offset>(%rbx),%r10 */
0x44, 0x89, 0x94, 0x24, 0, 0, 0, 0, /* mov %r10,<sp_offset>(%sp) */
};
uint8_t *addr = push_insns (ctx, ldst_pat, sizeof (ldst_pat));
memcpy (addr + 3, &src_offset, sizeof (uint32_t));
memcpy (addr + 11, &sp_offset, sizeof (uint32_t));
if (b64_p) {
addr[0] |= 8;
addr[7] |= 8;
}
}
static void gen_ldst80 (MIR_context_t ctx, uint32_t sp_offset, uint32_t src_offset) {
static uint8_t const ldst80_pat[] = {
0xdb, 0xab, 0, 0, 0, 0, /* fldt <src_offset>(%rbx) */
0xdb, 0xbc, 0x24, 0, 0, 0, 0, /* fstpt <sp_offset>(%sp) */
};
uint8_t *addr = push_insns (ctx, ldst80_pat, sizeof (ldst80_pat));
memcpy (addr + 2, &src_offset, sizeof (uint32_t));
memcpy (addr + 9, &sp_offset, sizeof (uint32_t));
}
static void gen_st80 (MIR_context_t ctx, uint32_t src_offset) {
static const uint8_t st80_pat[] = {0xdb, 0xbb, 0, 0, 0, 0 /* fstpt <src_offset>(%rbx) */};
memcpy (push_insns (ctx, st80_pat, sizeof (st80_pat)) + 2, &src_offset, sizeof (uint32_t));
}
/* Generation: fun (fun_addr, res_arg_addresses):
push rbx; sp-=sp_offset; r11=fun_addr; rbx=res/arg_addrs
r10=mem[rbx,<offset>]; (arg_reg=mem[r10] or r10=mem[r10];mem[sp,sp_offset]=r10) ...
rax=8; call *r11; sp+=offset
r10=mem[rbx,<offset>]; res_reg=mem[r10]; ...
pop rbx; ret. */
void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, size_t nargs,
MIR_type_t *arg_types) {
static const uint8_t prolog[] = {
0x53, /* pushq %rbx */
0x48, 0x81, 0xec, 0, 0, 0, 0, /* subq <sp_offset>, %rsp */
0x49, 0x89, 0xfb, /* mov $rdi, $r11 -- fun addr */
0x48, 0x89, 0xf3, /* mov $rsi, $rbx -- result/arg addresses */
};
static const uint8_t call_end[] = {
0x48, 0xc7, 0xc0, 0x08, 0, 0, 0, /* mov $8, rax -- to save xmm varargs */
0x41, 0xff, 0xd3, /* callq *%r11 */
0x48, 0x81, 0xc4, 0, 0, 0, 0, /* addq <sp_offset>, %rsp */
};
static const uint8_t epilog[] = {
0x5b, /* pop %rbx */
0xc3, /* ret */
};
static const uint8_t iregs[] = {7, 6, 2, 1, 8, 9}; /* rdi, rsi, rdx, rcx, r8, r9 */
uint32_t n_iregs = 0, n_xregs = 0, n_fregs, sp_offset = 0;
uint8_t *addr;
VARR_TRUNC (uint8_t, machine_insns, 0);
push_insns (ctx, prolog, sizeof (prolog));
for (size_t i = 0; i < nargs; i++) {
if ((MIR_T_I8 <= arg_types[i] && arg_types[i] <= MIR_T_U64) || arg_types[i] == MIR_T_P) {
if (n_iregs < 6) {
gen_mov (ctx, (i + nres) * sizeof (long double), iregs[n_iregs++], TRUE);
} else {
gen_ldst (ctx, sp_offset, (i + nres) * sizeof (long double), TRUE);
sp_offset += 8;
}
} else if (arg_types[i] == MIR_T_F || arg_types[i] == MIR_T_D) {
if (n_xregs < 8) {
gen_movxmm (ctx, (i + nres) * sizeof (long double), n_xregs++, arg_types[i] == MIR_T_F,
TRUE);
} else {
gen_ldst (ctx, sp_offset, (i + nres) * sizeof (long double), arg_types[i] == MIR_T_D);
sp_offset += 8;
}
} else if (arg_types[i] == MIR_T_LD) {
gen_ldst80 (ctx, sp_offset, (i + nres) * sizeof (long double));
sp_offset += 16;
} else {
(*error_func) (MIR_call_op_error, "wrong type of arg value");
}
}
sp_offset = (sp_offset + 15) / 16 * 16;
addr = VARR_ADDR (uint8_t, machine_insns);
memcpy (addr + 4, &sp_offset, sizeof (uint32_t));
addr = push_insns (ctx, call_end, sizeof (call_end));
memcpy (addr + 13, &sp_offset, sizeof (uint32_t));
n_iregs = n_xregs = n_fregs = 0;
for (size_t i = 0; i < nres; i++) {
if (((MIR_T_I8 <= res_types[i] && res_types[i] <= MIR_T_U64) || res_types[i] == MIR_T_P)
&& n_iregs < 2) {
gen_mov (ctx, i * sizeof (long double), n_iregs++ == 0 ? 0 : 2, FALSE); /* rax or rdx */
} else if ((res_types[i] == MIR_T_F || res_types[i] == MIR_T_D) && n_xregs < 2) {
gen_movxmm (ctx, i * sizeof (long double), n_xregs++, res_types[i] == MIR_T_F, FALSE);
} else if (res_types[i] == MIR_T_LD && n_fregs < 2) {
gen_st80 (ctx, i * sizeof (long double));
} else {
(*error_func) (MIR_ret_error, "x86-64 can not handle this combination of return values");
}
}
push_insns (ctx, epilog, sizeof (epilog));
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
}
void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handler) {
static const uint8_t push_rbx[] = {0x53, /*push %rbx */};
static const uint8_t prepare_pat[] = {
/* 0: */ 0x48, 0x83, 0xec, 0x20, /* sub 32,%rsp */
/* 4: */ 0x48, 0x89, 0xe2, /* mov %rsp,%rdx */
/* 7: */ 0xc7, 0x02, 0, 0, 0, 0, /* movl 0,(%rdx) */
/* d: */ 0xc7, 0x42, 0x04, 0x30, 0, 0, 0, /* movl 48, 4(%rdx) */
/* 14: */ 0x48, 0x8d, 0x44, 0x24, 0x20, /* lea 32(%rsp),%rax */
/* 19: */ 0x48, 0x89, 0x42, 0x10, /* mov %rax,16(%rdx) */
/* 1d: */ 0x48, 0x8d, 0x84, 0x24, 0xe0, 0, 0, 0, /* lea 224(%rsp),%rax */
/* 25: */ 0x48, 0x89, 0x42, 0x08, /* mov %rax,8(%rdx) */
/* 29: */ 0x48, 0x81, 0xec, 0, 0, 0, 0, /* sub <n>,%rsp */
/* 30: */ 0x48, 0x89, 0xe3, /* mov %rsp,%rbx */
/* 33: */ 0x48, 0x89, 0xe1, /* mov %rsp,%rcx */
/* 36: */ 0x48, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, /* movabs <ctx>,%rdi */
/* 40: */ 0x48, 0xbe, 0, 0, 0, 0, 0, 0, 0, 0, /* movabs <func_item>,%rsi */
/* 4a: */ 0x48, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, /* movabs <handler>,%rax */
/* 54: */ 0xff, 0xd0, /* callq *%rax */
};
static const uint8_t shim_end[] = {
/* 0: */ 0x48, 0x81, 0xc4, 0, 0, 0, 0, /*add 208+n,%rsp*/
/* 7: */ 0x5b, /*pop %rbx*/
/* 8: */ 0xc3, /*retq */
};
static const uint8_t ld_pat[]
= {0x48, 0x8b, 0x83, 0, 0, 0, 0}; /* movss <offset>(%rbx), %xmm[01] */
static const uint8_t movss_pat[]
= {0xf3, 0x0f, 0x10, 0x83, 0, 0, 0, 0}; /* movss <offset>(%rbx), %xmm[01] */
static const uint8_t movsd_pat[]
= {0xf2, 0x0f, 0x10, 0x83, 0, 0, 0, 0}; /* movsd <offset>(%rbx), %xmm[01] */
static const uint8_t fldt_pat[] = {0xdb, 0xab, 0, 0, 0, 0}; /* fldt <offset>(%rbx) */
static const uint8_t fxch_pat[] = {0xd9, 0xc9}; /* fxch */
uint8_t *addr;
uint32_t imm, n_iregs, n_xregs, n_fregs, offset;
uint32_t nres = func_item->u.func->nres;
MIR_type_t *results = func_item->u.func->res_types;
VARR_TRUNC (uint8_t, machine_insns, 0);
push_insns (ctx, push_rbx, sizeof (push_rbx));
push_insns (ctx, save_pat, sizeof (save_pat));
addr = push_insns (ctx, prepare_pat, sizeof (prepare_pat));
imm = nres * 16;
memcpy (addr + 0x2c, &imm, sizeof (uint32_t));
memcpy (addr + 0x38, &ctx, sizeof (void *));
memcpy (addr + 0x42, &func_item, sizeof (void *));
memcpy (addr + 0x4c, &handler, sizeof (void *));
/* move results: */
n_iregs = n_xregs = n_fregs = offset = 0;
for (uint32_t i = 0; i < nres; i++) {
if (results[i] == MIR_T_F && n_xregs < 2) {
addr = push_insns (ctx, movss_pat, sizeof (movss_pat));
addr[3] |= n_xregs << 3;
memcpy (addr + 4, &offset, sizeof (uint32_t));
n_xregs++;
} else if (results[i] == MIR_T_D && n_xregs < 2) {
addr = push_insns (ctx, movsd_pat, sizeof (movsd_pat));
addr[3] |= n_xregs << 3;
memcpy (addr + 4, &offset, sizeof (uint32_t));
n_xregs++;
} else if (results[i] == MIR_T_LD && n_fregs < 2) {
addr = push_insns (ctx, fldt_pat, sizeof (fldt_pat));
memcpy (addr + 2, &offset, sizeof (uint32_t));
if (n_fregs == 1) push_insns (ctx, fxch_pat, sizeof (fxch_pat));
n_fregs++;
} else if (n_iregs < 2) {
addr = push_insns (ctx, ld_pat, sizeof (ld_pat));
addr[2] |= n_iregs << 4;
memcpy (addr + 3, &offset, sizeof (uint32_t));
n_iregs++;
} else {
(*error_func) (MIR_ret_error, "x86-64 can not handle this combination of return values");
}
offset += 16;
}
addr = push_insns (ctx, shim_end, sizeof (shim_end));
imm = 208 + nres * 16;
memcpy (addr + 3, &imm, sizeof (uint32_t));
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
}
/* save regs; r10 = call hook_address (ctx, called_func); restore regs; jmp *r10
*/
void *_MIR_get_wrapper (MIR_context_t ctx, MIR_item_t called_func, void *hook_address) {
static const uint8_t push_rax[] = {0x50, /*push %rax */};
static const uint8_t wrap_end[] = {
0x58, /*pop %rax */
0x41, 0xff, 0xe2, /*jmpq *%r10 */
};
static const uint8_t call_pat[] = {
0x48, 0xbe, 0, 0, 0, 0, 0, 0, 0, 0, /*movabs called_func,%rsi */
0x48, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, /*movabs ctx,%rdi */
0x49, 0xba, 0, 0, 0, 0, 0, 0, 0, 0, /*movabs <hook_address>,%r10 */
0x41, 0xff, 0xd2, /*callq *%r10 */
0x49, 0x89, 0xc2, /*mov %rax,%r10 */
};
uint8_t *addr;
VARR_TRUNC (uint8_t, machine_insns, 0);
push_insns (ctx, push_rax, sizeof (push_rax));
push_insns (ctx, save_pat, sizeof (save_pat));
addr = push_insns (ctx, call_pat, sizeof (call_pat));
memcpy (addr + 2, &called_func, sizeof (void *));
memcpy (addr + 12, &ctx, sizeof (void *));
memcpy (addr + 22, &hook_address, sizeof (void *));
push_insns (ctx, restore_pat, sizeof (restore_pat));
push_insns (ctx, wrap_end, sizeof (wrap_end));
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
}
static void machine_init (MIR_context_t ctx) { VARR_CREATE (uint8_t, machine_insns, 1024); }
static void machine_finish (MIR_context_t ctx) { VARR_DESTROY (uint8_t, machine_insns); }

File diff suppressed because it is too large Load Diff

@ -0,0 +1,584 @@
/* This file is a part of MIR project.
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
#ifndef MIR_H
#define MIR_H
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include "mir-dlist.h"
#include "mir-varr.h"
#include "mir-htab.h"
#ifdef NDEBUG
static inline int mir_assert (int cond) { return 0 && cond; }
#else
#define mir_assert(cond) assert (cond)
#endif
#define FALSE 0
#define TRUE 1
/* Redefine MIR_NO_IO or/and MIR_NO_SCAN if you don't need the functionality they provide. */
#ifndef MIR_NO_IO
#define MIR_NO_IO 0
#endif
#ifndef MIR_NO_SCAN
#define MIR_NO_SCAN 0
#endif
#ifdef __GNUC__
#define MIR_UNUSED __attribute__ ((unused))
#else
#define MIR_UNUSED
#endif
#define REP2(M, a1, a2) M (a1) REP_SEP M (a2)
#define REP3(M, a1, a2, a3) REP2 (M, a1, a2) REP_SEP M (a3)
#define REP4(M, a1, a2, a3, a4) REP3 (M, a1, a2, a3) REP_SEP M (a4)
#define REP5(M, a1, a2, a3, a4, a5) REP4 (M, a1, a2, a3, a4) REP_SEP M (a5)
#define REP6(M, a1, a2, a3, a4, a5, a6) REP5 (M, a1, a2, a3, a4, a5) REP_SEP M (a6)
#define REP7(M, a1, a2, a3, a4, a5, a6, a7) REP6 (M, a1, a2, a3, a4, a5, a6) REP_SEP M (a7)
#define REP8(M, a1, a2, a3, a4, a5, a6, a7, a8) REP7 (M, a1, a2, a3, a4, a5, a6, a7) REP_SEP M (a8)
#define REP_SEP ,
#define ERR_EL(e) MIR_##e##_error
typedef enum MIR_error_type {
REP8 (ERR_EL, no, syntax, binary_io, alloc, finish, no_module, nested_module, no_func),
REP4 (ERR_EL, func, vararg_func, nested_func, wrong_param_value),
REP4 (ERR_EL, reserved_name, import_export, undeclared_func_reg, repeated_decl),
REP8 (ERR_EL, reg_type, unique_reg, undeclared_op_ref, ops_num, call_op, ret, op_mode, out_op),
ERR_EL (invalid_insn)
} MIR_error_type_t;
#ifdef __GNUC__
#define MIR_NO_RETURN __attribute__ ((noreturn))
#else
#define MIR_NO_RETURN
#endif
typedef void MIR_NO_RETURN (*MIR_error_func_t) (MIR_error_type_t error_type, const char *format,
...);
#define INSN_EL(i) MIR_##i
/* The most MIR insns have destination operand and one or two source
operands. The destination can be ony a register or memory.
There are additional constraints on insn operands:
o A register in porgram can contain only one type values: integer,
float, double, or long double.
o Operand types should be what the insn expects */
typedef enum {
/* Abbreviations:
I - 64-bit int, S - short (32-bit), U - unsigned, F -float, D - double, LD - long double. */
/* 2 operand insns: */
REP4 (INSN_EL, MOV, FMOV, DMOV, LDMOV), /* Moves */
/* Extensions. Truncation is not necessary because we can use an extension to use a part. */
REP6 (INSN_EL, EXT8, EXT16, EXT32, UEXT8, UEXT16, UEXT32),
REP3 (INSN_EL, I2F, I2D, I2LD), /* Integer to float or (long) double conversion */
REP3 (INSN_EL, UI2F, UI2D, UI2LD), /* Unsigned integer to float or (long) double conversion */
REP3 (INSN_EL, F2I, D2I, LD2I), /* Float or (long) double to integer conversion */
REP6 (INSN_EL, F2D, F2LD, D2F, D2LD, LD2F, LD2D), /* Float, (long) double conversions */
REP5 (INSN_EL, NEG, NEGS, FNEG, DNEG, LDNEG), /* Changing sign */
/* 3 operand insn: */
REP5 (INSN_EL, ADD, ADDS, FADD, DADD, LDADD), /* Addition */
REP5 (INSN_EL, SUB, SUBS, FSUB, DSUB, LDSUB), /* Subtraction */
REP5 (INSN_EL, MUL, MULS, FMUL, DMUL, LDMUL), /* Multiplication */
REP7 (INSN_EL, DIV, DIVS, UDIV, UDIVS, FDIV, DDIV, LDDIV), /* Division */
REP4 (INSN_EL, MOD, MODS, UMOD, UMODS), /* Modulo */
REP6 (INSN_EL, AND, ANDS, OR, ORS, XOR, XORS), /* Logical */
REP6 (INSN_EL, LSH, LSHS, RSH, RSHS, URSH, URSHS), /* Right signed/unsigned shift */
REP5 (INSN_EL, EQ, EQS, FEQ, DEQ, LDEQ), /* Equality */
REP5 (INSN_EL, NE, NES, FNE, DNE, LDNE), /* Inequality */
REP7 (INSN_EL, LT, LTS, ULT, ULTS, FLT, DLT, LDLT), /* Less then */
REP7 (INSN_EL, LE, LES, ULE, ULES, FLE, DLE, LDLE), /* Less or equal */
REP7 (INSN_EL, GT, GTS, UGT, UGTS, FGT, DGT, LDGT), /* Greater then */
REP7 (INSN_EL, GE, GES, UGE, UGES, FGE, DGE, LDGE), /* Greater or equal */
/* Uncoditional (1 operand) and conditional (2 operands) branch
insns. The first operand is a label. */
REP5 (INSN_EL, JMP, BT, BTS, BF, BFS),
/* Compare and branch (3 operand) insns. The first operand is the
label. */
REP5 (INSN_EL, BEQ, BEQS, FBEQ, DBEQ, LDBEQ),
REP5 (INSN_EL, BNE, BNES, FBNE, DBNE, LDBNE),
REP7 (INSN_EL, BLT, BLTS, UBLT, UBLTS, FBLT, DBLT, LDBLT),
REP7 (INSN_EL, BLE, BLES, UBLE, UBLES, FBLE, DBLE, LDBLE),
REP7 (INSN_EL, BGT, BGTS, UBGT, UBGTS, FBGT, DBGT, LDBGT),
REP7 (INSN_EL, BGE, BGES, UBGE, UBGES, FBGE, DBGE, LDBGE),
/* 1st operand is a prototype, 2nd one is ref or op containing func
address, 3rd and subsequent ops are optional result (if result in
the prototype is not of void type), call arguments. */
REP2 (INSN_EL, CALL, INLINE),
/* 1st operand is an index, subsequent ops are labels to which goto
according the index (1st label has index zero). The insn
behaviour is undefined if there is no label for the index. */
INSN_EL (SWITCH),
/* 1 operand insn: */
INSN_EL (RET),
INSN_EL (ALLOCA), /* 2 operands: result address and size */
REP2 (INSN_EL, BSTART, BEND), /* block start: result addr; block end: addr from block start */
/* Special insns: */
INSN_EL (VA_ARG), /* result is arg address, operands: va_list addr and memory */
INSN_EL (VA_START),
INSN_EL (VA_END), /* operand is va_list */
INSN_EL (LABEL), /* One immediate operand is unique label number */
INSN_EL (INVALID_INSN),
INSN_EL (INSN_BOUND), /* Should be the last */
} MIR_insn_code_t;
#define TYPE_EL(t) MIR_T_##t
/* Data types: */
typedef enum {
REP8 (TYPE_EL, I8, U8, I16, U16, I32, U32, I64, U64), /* Integer types of different size: */
REP3 (TYPE_EL, F, D, LD), /* Float or (long) double type */
TYPE_EL (P), /* Pointer */
REP2 (TYPE_EL, UNDEF, BOUND),
} MIR_type_t;
#if UINTPTR_MAX == 0xffffffff
#define MIR_PTR32 1
#define MIR_PTR64 0
#elif UINTPTR_MAX == 0xffffffffffffffffu
#define MIR_PTR32 0
#define MIR_PTR64 1
#else
#error MIR can work only for 32- or 64-bit targets
#endif
typedef uint8_t MIR_scale_t; /* Index reg scale in memory */
#define MIR_MAX_SCALE UINT8_MAX
typedef int64_t MIR_disp_t; /* Address displacement in memory */
/* Register number (> 0). A register always contain only one type
value: integer, float, or (long) double. Register numbers in insn
operands can be changed in MIR_finish_func. */
typedef uint32_t MIR_reg_t;
#define MIR_MAX_REG_NUM UINT32_MAX
#define MIR_NON_HARD_REG MIR_MAX_REG_NUM
/* Immediate in immediate moves. */
typedef union {
int64_t i;
uint64_t u;
float f;
double d;
long double ld;
} MIR_imm_t;
/* Memory: mem:type[base + index * scale + disp]. It also can be
memory with hard regs but such memory used only internally. An
integer type memory value expands to int64_t value when the insn is
executed. */
typedef struct {
MIR_type_t type : 8;
MIR_scale_t scale;
/* 0 means no reg for memory. MIR_NON_HARD_REG means no reg for
hard reg memory. */
MIR_reg_t base, index;
MIR_disp_t disp;
} MIR_mem_t;
typedef struct MIR_insn *MIR_label_t;
typedef const char *MIR_name_t;
#define OP_EL(op) MIR_OP_##op
/* Operand mode */
typedef enum {
REP8 (OP_EL, UNDEF, REG, HARD_REG, INT, UINT, FLOAT, DOUBLE, LDOUBLE),
REP6 (OP_EL, REF, STR, MEM, HARD_REG_MEM, LABEL, BOUND),
} MIR_op_mode_t;
typedef struct MIR_item *MIR_item_t;
struct MIR_str {
size_t len;
const char *s;
};
typedef struct MIR_str MIR_str_t;
/* An insn operand */
typedef struct {
void *data; /* Aux data */
MIR_op_mode_t mode;
/* Defined after MIR_func_finish. Only MIR_OP_INT, MIR_OP_UINT,
MIR_OP_FLOAT, MIR_OP_DOUBLE, MIR_OP_LDOUBLE: */
MIR_op_mode_t value_mode;
union {
MIR_reg_t reg;
MIR_reg_t hard_reg; /* Used only internally */
int64_t i;
uint64_t u;
float f;
double d;
long double ld;
MIR_item_t ref; /* non-export/non-forward after simplification */
MIR_str_t str;
MIR_mem_t mem;
MIR_mem_t hard_reg_mem; /* Used only internally */
MIR_label_t label;
} u;
} MIR_op_t;
typedef struct MIR_insn *MIR_insn_t;
/* Definition of link of double list of insns */
DEF_DLIST_LINK (MIR_insn_t);
struct MIR_insn {
void *data; /* Aux data */
DLIST_LINK (MIR_insn_t) insn_link;
MIR_insn_code_t code : 32;
unsigned int nops : 32; /* number of operands */
MIR_op_t ops[1];
};
/* Definition of double list of insns */
DEF_DLIST (MIR_insn_t, insn_link);
typedef struct MIR_var {
MIR_type_t type;
const char *name;
} MIR_var_t;
DEF_VARR (MIR_var_t);
/* Function definition */
typedef struct MIR_func {
const char *name;
DLIST (MIR_insn_t) insns, original_insns;
uint32_t nres, nargs, last_temp_num, n_inlines;
MIR_type_t *res_types;
char vararg_p; /* flag of variable number of arguments */
char expr_p; /* flag of that the func can be used as a linker expression */
VARR (MIR_var_t) * vars; /* args and locals but temps */
void *machine_code; /* address of generated machine code or NULL */
void *call_addr; /* address to call the function, it can be the same as machine_code */
} * MIR_func_t;
typedef struct MIR_proto {
const char *name;
uint32_t nres;
MIR_type_t *res_types; /* != MIR_T_UNDEF */
char vararg_p; /* flag of variable number of arguments */
VARR (MIR_var_t) * args; /* args name can be NULL */
} * MIR_proto_t;
typedef struct MIR_data {
const char *name; /* can be NULL */
MIR_type_t el_type;
size_t nel;
union {
long double d; /* for alignment of temporary literals */
uint8_t els[1];
} u;
} * MIR_data_t;
typedef struct MIR_ref_data {
const char *name; /* can be NULL */
MIR_item_t ref_item; /* base */
int64_t disp; /* disp relative to base */
void *load_addr;
} * MIR_ref_data_t;
typedef struct MIR_expr_data {
const char *name; /* can be NULL */
MIR_item_t expr_item; /* a special function can be called during linking */
void *load_addr;
} * MIR_expr_data_t;
typedef struct MIR_bss {
const char *name; /* can be NULL */
uint64_t len;
} * MIR_bss_t;
typedef struct MIR_module *MIR_module_t;
/* Definition of link of double list of MIR_item_t type elements */
DEF_DLIST_LINK (MIR_item_t);
#define ITEM_EL(i) MIR_##i##_item
typedef enum {
REP8 (ITEM_EL, func, proto, import, export, forward, data, ref_data, expr_data),
ITEM_EL (bss),
} MIR_item_type_t;
#undef ERR_EL
#undef INSN_EL
#undef TYPE_EL
#undef OP_EL
#undef ITEM_EL
#undef REP_SEP
/* MIR module items (function or import): */
struct MIR_item {
void *data;
MIR_module_t module;
DLIST_LINK (MIR_item_t) item_link;
MIR_item_type_t item_type; /* item type */
/* Non-null only for export/forward items and import item after
linking. It forms a chain to the final definition. */
MIR_item_t ref_def;
/* address of loaded data/bss items, function to call the function
item, imported definition or proto object */
void *addr;
char export_p; /* true for export items (only func items) */
union {
MIR_func_t func;
MIR_proto_t proto;
MIR_name_t import;
MIR_name_t export;
MIR_name_t forward;
MIR_data_t data;
MIR_ref_data_t ref_data;
MIR_expr_data_t expr_data;
MIR_bss_t bss;
} u;
};
/* Definition of double list of MIR_item_t type elements */
DEF_DLIST (MIR_item_t, item_link);
/* Definition of link of double list of MIR_module_t type elements */
DEF_DLIST_LINK (MIR_module_t);
/* MIR module: */
struct MIR_module {
void *data;
const char *name;
DLIST (MIR_item_t) items; /* module items */
DLIST_LINK (MIR_module_t) module_link;
uint32_t last_temp_item_num; /* Used only internally */
};
/* Definition of double list of MIR_item_t type elements */
DEF_DLIST (MIR_module_t, module_link);
struct MIR_context;
typedef struct MIR_context *MIR_context_t;
static inline int MIR_FP_branch_code_p (MIR_insn_code_t code) {
return (code == MIR_FBEQ || code == MIR_DBEQ || code == MIR_LDBEQ || code == MIR_FBNE
|| code == MIR_DBNE || code == MIR_LDBNE || code == MIR_FBLT || code == MIR_DBLT
|| code == MIR_LDBLT || code == MIR_FBLE || code == MIR_DBLE || code == MIR_LDBLE
|| code == MIR_FBGT || code == MIR_DBGT || code == MIR_LDBGT || code == MIR_FBGE
|| code == MIR_DBGE || code == MIR_LDBGE);
}
static inline int MIR_call_code_p (MIR_insn_code_t code) {
return code == MIR_CALL || code == MIR_INLINE;
}
static inline int MIR_int_branch_code_p (MIR_insn_code_t code) {
return (code == MIR_BT || code == MIR_BTS || code == MIR_BF || code == MIR_BFS || code == MIR_BEQ
|| code == MIR_BEQS || code == MIR_BNE || code == MIR_BNES || code == MIR_BLT
|| code == MIR_BLTS || code == MIR_UBLT || code == MIR_UBLTS || code == MIR_BLE
|| code == MIR_BLES || code == MIR_UBLE || code == MIR_UBLES || code == MIR_BGT
|| code == MIR_BGTS || code == MIR_UBGT || code == MIR_UBGTS || code == MIR_BGE
|| code == MIR_BGES || code == MIR_UBGE || code == MIR_UBGES);
}
static inline int MIR_branch_code_p (MIR_insn_code_t code) {
return (code == MIR_JMP || MIR_int_branch_code_p (code) || MIR_FP_branch_code_p (code));
}
/* Use only the following API to create MIR code. */
extern MIR_context_t MIR_init (void);
extern void MIR_finish (MIR_context_t ctx);
extern MIR_module_t MIR_new_module (MIR_context_t ctx, const char *name);
extern DLIST (MIR_module_t) * MIR_get_module_list (MIR_context_t ctx);
extern MIR_item_t MIR_new_import (MIR_context_t ctx, const char *name);
extern MIR_item_t MIR_new_export (MIR_context_t ctx, const char *name);
extern MIR_item_t MIR_new_forward (MIR_context_t ctx, const char *name);
extern MIR_item_t MIR_new_bss (MIR_context_t ctx, const char *name,
size_t len); /* name can be NULL */
extern MIR_item_t MIR_new_data (MIR_context_t ctx, const char *name, MIR_type_t el_type, size_t nel,
const void *els); /* name can be NULL */
extern MIR_item_t MIR_new_string_data (MIR_context_t ctx, const char *name,
MIR_str_t str); /* name can be NULL */
extern MIR_item_t MIR_new_ref_data (MIR_context_t ctx, const char *name, MIR_item_t item,
int64_t disp); /* name can be NULL */
extern MIR_item_t MIR_new_expr_data (MIR_context_t ctx, const char *name,
MIR_item_t expr_item); /* name can be NULL */
extern MIR_item_t MIR_new_proto_arr (MIR_context_t ctx, const char *name, size_t nres,
MIR_type_t *res_types, size_t nargs, MIR_var_t *vars);
extern MIR_item_t MIR_new_proto (MIR_context_t ctx, const char *name, size_t nres,
MIR_type_t *res_types, size_t nargs, ...);
extern MIR_item_t MIR_new_vararg_proto_arr (MIR_context_t ctx, const char *name, size_t nres,
MIR_type_t *res_types, size_t nargs, MIR_var_t *vars);
extern MIR_item_t MIR_new_vararg_proto (MIR_context_t ctx, const char *name, size_t nres,
MIR_type_t *res_types, size_t nargs, ...);
extern MIR_item_t MIR_new_func_arr (MIR_context_t ctx, const char *name, size_t nres,
MIR_type_t *res_types, size_t nargs, MIR_var_t *vars);
extern MIR_item_t MIR_new_func (MIR_context_t ctx, const char *name, size_t nres,
MIR_type_t *res_types, size_t nargs, ...);
extern MIR_item_t MIR_new_vararg_func_arr (MIR_context_t ctx, const char *name, size_t nres,
MIR_type_t *res_types, size_t nargs, MIR_var_t *vars);
extern MIR_item_t MIR_new_vararg_func (MIR_context_t ctx, const char *name, size_t nres,
MIR_type_t *res_types, size_t nargs, ...);
extern const char *MIR_item_name (MIR_context_t ctx, MIR_item_t item);
extern MIR_reg_t MIR_new_func_reg (MIR_context_t ctx, MIR_func_t func, MIR_type_t type,
const char *name);
extern void MIR_finish_func (MIR_context_t ctx);
extern void MIR_finish_module (MIR_context_t ctx);
extern MIR_error_func_t MIR_get_error_func (MIR_context_t ctx);
extern void MIR_set_error_func (MIR_context_t ctx, MIR_error_func_t func);
extern MIR_insn_t MIR_new_insn_arr (MIR_context_t ctx, MIR_insn_code_t code, size_t nops,
MIR_op_t *ops);
extern MIR_insn_t MIR_new_insn (MIR_context_t ctx, MIR_insn_code_t code, ...);
extern MIR_insn_t MIR_new_call_insn (MIR_context_t ctx, size_t nops, ...);
extern MIR_insn_t MIR_new_ret_insn (MIR_context_t ctx, size_t nops, ...);
extern MIR_insn_t MIR_copy_insn (MIR_context_t ctx, MIR_insn_t insn);
extern const char *MIR_insn_name (MIR_context_t ctx, MIR_insn_code_t code);
extern size_t MIR_insn_nops (MIR_context_t ctx, MIR_insn_t insn);
extern MIR_op_mode_t MIR_insn_op_mode (MIR_context_t ctx, MIR_insn_t insn, size_t nop, int *out_p);
extern MIR_insn_t MIR_new_label (MIR_context_t ctx);
extern MIR_reg_t MIR_reg (MIR_context_t ctx, const char *reg_name, MIR_func_t func);
extern MIR_type_t MIR_reg_type (MIR_context_t ctx, MIR_reg_t reg, MIR_func_t func);
extern const char *MIR_reg_name (MIR_context_t ctx, MIR_reg_t reg, MIR_func_t func);
extern MIR_op_t MIR_new_reg_op (MIR_context_t ctx, MIR_reg_t reg);
extern MIR_op_t MIR_new_int_op (MIR_context_t ctx, int64_t v);
extern MIR_op_t MIR_new_uint_op (MIR_context_t ctx, uint64_t v);
extern MIR_op_t MIR_new_float_op (MIR_context_t ctx, float v);
extern MIR_op_t MIR_new_double_op (MIR_context_t ctx, double v);
extern MIR_op_t MIR_new_ldouble_op (MIR_context_t ctx, long double v);
extern MIR_op_t MIR_new_ref_op (MIR_context_t ctx, MIR_item_t item);
extern MIR_op_t MIR_new_str_op (MIR_context_t ctx, MIR_str_t str);
extern MIR_op_t MIR_new_mem_op (MIR_context_t ctx, MIR_type_t type, MIR_disp_t disp, MIR_reg_t base,
MIR_reg_t index, MIR_scale_t scale);
extern MIR_op_t MIR_new_label_op (MIR_context_t ctx, MIR_label_t label);
extern int MIR_op_eq_p (MIR_context_t ctx, MIR_op_t op1, MIR_op_t op2);
extern htab_hash_t MIR_op_hash_step (MIR_context_t ctx, htab_hash_t h, MIR_op_t op);
extern void MIR_append_insn (MIR_context_t ctx, MIR_item_t func, MIR_insn_t insn);
extern void MIR_prepend_insn (MIR_context_t ctx, MIR_item_t func, MIR_insn_t insn);
extern void MIR_insert_insn_after (MIR_context_t ctx, MIR_item_t func, MIR_insn_t after,
MIR_insn_t insn);
extern void MIR_insert_insn_before (MIR_context_t ctx, MIR_item_t func, MIR_insn_t before,
MIR_insn_t insn);
extern void MIR_remove_insn (MIR_context_t ctx, MIR_item_t func, MIR_insn_t insn);
extern const char *MIR_type_str (MIR_context_t ctx, MIR_type_t tp);
extern void MIR_output_op (MIR_context_t ctx, FILE *f, MIR_op_t op, MIR_func_t func);
extern void MIR_output_insn (MIR_context_t ctx, FILE *f, MIR_insn_t insn, MIR_func_t func,
int newline_p);
extern void MIR_output_item (MIR_context_t ctx, FILE *f, MIR_item_t item);
extern void MIR_output_module (MIR_context_t ctx, FILE *f, MIR_module_t module);
extern void MIR_output (MIR_context_t ctx, FILE *f);
#if !MIR_NO_IO
extern void MIR_write (MIR_context_t ctx, FILE *f);
extern void MIR_write_module (MIR_context_t ctx, FILE *f, MIR_module_t module);
extern void MIR_read (MIR_context_t ctx, FILE *f);
extern void MIR_write_with_func (MIR_context_t ctx,
const int (*writer_func) (MIR_context_t, uint8_t));
extern void MIR_write_module_with_func (MIR_context_t ctx,
const int (*writer_func) (MIR_context_t, uint8_t),
MIR_module_t module);
extern void MIR_read_with_func (MIR_context_t ctx, const int (*reader_func) (MIR_context_t));
#endif
#if !MIR_NO_SCAN
extern void MIR_scan_string (MIR_context_t ctx, const char *str);
#endif
extern MIR_item_t MIR_get_global_item (MIR_context_t ctx, const char *name);
extern void MIR_load_module (MIR_context_t ctx, MIR_module_t m);
extern void MIR_load_external (MIR_context_t ctx, const char *name, void *addr);
extern void MIR_link (MIR_context_t ctx, void (*set_interface) (MIR_context_t ctx, MIR_item_t item),
void *(*import_resolver) (const char *) );
/* Interpreter: */
typedef union {
MIR_insn_code_t ic;
void *a;
int64_t i;
uint64_t u;
float f;
double d;
long double ld;
} MIR_val_t;
extern void MIR_interp (MIR_context_t ctx, MIR_item_t func_item, MIR_val_t *results, size_t nargs,
...);
extern void MIR_interp_arr (MIR_context_t ctx, MIR_item_t func_item, MIR_val_t *results,
size_t nargs, MIR_val_t *vals);
extern void MIR_interp_arr_varg (MIR_context_t ctx, MIR_item_t func_item, MIR_val_t *results,
size_t nargs, MIR_val_t *vals, va_list va);
extern void MIR_set_interp_interface (MIR_context_t ctx, MIR_item_t func_item);
/* Private: */
extern const char *_MIR_uniq_string (MIR_context_t ctx, const char *str);
extern int _MIR_reserved_ref_name_p (MIR_context_t ctx, const char *name);
extern int _MIR_reserved_name_p (MIR_context_t ctx, const char *name);
extern MIR_reg_t _MIR_new_temp_reg (MIR_context_t ctx, MIR_type_t type,
MIR_func_t func); /* for internal use only */
extern size_t _MIR_type_size (MIR_context_t ctx, MIR_type_t type);
extern MIR_op_mode_t _MIR_insn_code_op_mode (MIR_context_t ctx, MIR_insn_code_t code, size_t nop,
int *out_p);
extern void _MIR_duplicate_func_insns (MIR_context_t ctx, MIR_item_t func_item);
extern void _MIR_restore_func_insns (MIR_context_t ctx, MIR_item_t func_item);
extern void _MIR_simplify_insn (MIR_context_t ctx, MIR_item_t func_item, MIR_insn_t insn,
int keep_ref_p, int mem_float_p);
extern const char *_MIR_get_temp_item_name (MIR_context_t ctx, MIR_module_t module);
extern MIR_op_t _MIR_new_hard_reg_op (MIR_context_t ctx, MIR_reg_t hard_reg);
extern MIR_op_t _MIR_new_hard_reg_mem_op (MIR_context_t ctx, MIR_type_t type, MIR_disp_t disp,
MIR_reg_t base, MIR_reg_t index, MIR_scale_t scale);
extern MIR_item_t _MIR_builtin_proto (MIR_context_t ctx, MIR_module_t module, const char *name,
size_t nres, MIR_type_t *res_types, size_t nargs, ...);
extern MIR_item_t _MIR_builtin_func (MIR_context_t ctx, MIR_module_t module, const char *name,
void *addr);
extern uint8_t *_MIR_publish_code (MIR_context_t ctx, const uint8_t *code, size_t code_len);
struct MIR_code_reloc {
size_t offset;
void *value;
};
typedef struct MIR_code_reloc MIR_code_reloc_t;
extern void _MIR_update_code_arr (MIR_context_t ctx, uint8_t *base, size_t nloc,
const MIR_code_reloc_t *relocs);
extern void _MIR_update_code (MIR_context_t ctx, uint8_t *base, size_t nloc, ...);
extern void *va_arg_builtin (void *p, uint64_t t);
extern void va_start_interp_builtin (MIR_context_t ctx, void *p, void *a);
extern void va_end_interp_builtin (MIR_context_t ctx, void *p);
extern void *_MIR_get_bstart_builtin (MIR_context_t ctx);
extern void *_MIR_get_bend_builtin (MIR_context_t ctx);
extern void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, size_t nargs,
MIR_type_t *arg_types);
extern void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handler);
extern void *_MIR_get_thunk (MIR_context_t ctx);
extern void _MIR_redirect_thunk (MIR_context_t ctx, void *thunk, void *to);
extern void *_MIR_get_wrapper (MIR_context_t ctx, MIR_item_t called_func, void *hook_address);
#endif /* #ifndef MIR_H */

@ -58,10 +58,10 @@ function testbits()
d == 0)
print'+'
a = toint(2^30 - 1)
b = toint(2^30 - 1)
c = toint(2^30)
d = toint(2^30)
a = @integer math.tointeger(2^30) - 1
b = @integer math.tointeger(2^30) - 1
c = @integer math.tointeger(2^30)
d = @integer math.tointeger(2^30)
assert((a) << c == 0)
assert((b) >> d == 0)
print'+'

@ -8,6 +8,10 @@ print(t)
local atable = { t }
defer
print('deferred')
end
local function func_with_varargs(...)
local t = { ... }
print(table.unpack(t))

File diff suppressed because it is too large Load Diff

@ -78,4 +78,12 @@ dotest 'return @integer[] {}'
dotest 'return @number[] {}'
dotest 'return @closure function() end'
dotest 'return @number 54.4'
dotest 'return @User.Type a'
dotest 'return @User.Type a'
dotest 'for i=1,10 do print(i+1) end return'
dotest 'for i=1.0, 10.0 do print(i+4.2) end return'
dotest 'return {1,2,3}'
dotest 'local a: integer return {1+a}'
dotest 'return {[1] = a}'

@ -17,9 +17,11 @@ function()
function()
--upvalues a
return
--[primary start]
a --upvalue ?
--[primary end]
--[suffixed expr start] any
--[primary start] any
a --upvalue ?
--[primary end]
--[suffixed expr end]
end
end
local
@ -37,19 +39,25 @@ function()
function()
--upvalues a
return
--[primary start]
a --upvalue ?
--[primary end]
--[suffixed expr start] any
--[primary start] any
a --upvalue ?
--[primary end]
--[suffixed expr end]
end
end
return
--[primary start]
y --local symbol function
--[primary end]
--[suffixed expr start] closure
--[primary start] closure
y --local symbol function
--[primary end]
--[suffixed expr end]
,
--[primary start]
z --local symbol function
--[primary end]
--[suffixed expr start] closure
--[primary start] closure
z --local symbol function
--[primary end]
--[suffixed expr end]
end
end
@ -68,51 +76,67 @@ function()
)
--locals a, b, c, d, e
if
--[binary expr start]
--[primary start]
a --local symbol ?
--[primary end]
--[binary expr start] any
--[suffixed expr start] any
--[primary start] any
a --local symbol ?
--[primary end]
--[suffixed expr end]
==
--[primary start]
b --local symbol ?
--[primary end]
--[suffixed expr start] any
--[primary start] any
b --local symbol ?
--[primary end]
--[suffixed expr end]
--[binary expr end]
then
goto l1
elseif
--[binary expr start]
--[primary start]
a --local symbol ?
--[primary end]
--[binary expr start] any
--[suffixed expr start] any
--[primary start] any
a --local symbol ?
--[primary end]
--[suffixed expr end]
==
--[primary start]
c --local symbol ?
--[primary end]
--[suffixed expr start] any
--[primary start] any
c --local symbol ?
--[primary end]
--[suffixed expr end]
--[binary expr end]
then
goto l2
elseif
--[binary expr start]
--[primary start]
a --local symbol ?
--[primary end]
--[binary expr start] any
--[suffixed expr start] any
--[primary start] any
a --local symbol ?
--[primary end]
--[suffixed expr end]
==
--[primary start]
d --local symbol ?
--[primary end]
--[suffixed expr start] any
--[primary start] any
d --local symbol ?
--[primary end]
--[suffixed expr end]
--[binary expr end]
then
goto l2
else
if
--[binary expr start]
--[primary start]
a --local symbol ?
--[primary end]
--[binary expr start] any
--[suffixed expr start] any
--[primary start] any
a --local symbol ?
--[primary end]
--[suffixed expr end]
==
--[primary start]
e --local symbol ?
--[primary end]
--[suffixed expr start] any
--[primary start] any
e --local symbol ?
--[primary end]
--[suffixed expr end]
--[binary expr end]
then
goto l3
@ -134,25 +158,31 @@ function()
)
--locals a
while
--[binary expr start]
--[primary start]
a --local symbol ?
--[primary end]
--[binary expr start] any
--[suffixed expr start] any
--[primary start] any
a --local symbol ?
--[primary end]
--[suffixed expr end]
<
10
--[binary expr end]
do
--[expression statement start]
--[var list start]
--[primary start]
a --local symbol ?
--[primary end]
= --[var list end]
--[expression list start]
--[binary expr start]
--[primary start]
--[suffixed expr start] any
--[primary start] any
a --local symbol ?
--[primary end]
--[suffixed expr end]
= --[var list end]
--[expression list start]
--[binary expr start] any
--[suffixed expr start] any
--[primary start] any
a --local symbol ?
--[primary end]
--[suffixed expr end]
+
1
--[binary expr end]
@ -172,30 +202,38 @@ function()
if
--[unary expr start] any
not
--[primary start]
--[binary expr start]
--[primary start]
a --local symbol ?
--[primary end]
<
10
--[binary expr end]
--[primary end]
--[suffixed expr start] any
--[primary start] any
--[binary expr start] any
--[suffixed expr start] any
--[primary start] any
a --local symbol ?
--[primary end]
--[suffixed expr end]
<
10
--[binary expr end]
--[primary end]
--[suffixed expr end]
--[unary expr end]
then
goto L1
end
--[expression statement start]
--[var list start]
--[primary start]
a --local symbol ?
--[primary end]
= --[var list end]
--[expression list start]
--[binary expr start]
--[primary start]
--[suffixed expr start] any
--[primary start] any
a --local symbol ?
--[primary end]
--[suffixed expr end]
= --[var list end]
--[expression list start]
--[binary expr start] any
--[suffixed expr start] any
--[primary start] any
a --local symbol ?
--[primary end]
--[suffixed expr end]
+
1
--[binary expr end]
@ -211,31 +249,35 @@ function()
function()
--[expression statement start]
--[expression list start]
--[primary start]
function()
end
--[primary end]
--[suffix list start]
--[function call start]
(
{ --[table constructor start] table
--[indexed assign start]
--[value start]
--[primary start]
f --global symbol ?
--[primary end]
--[suffix list start]
--[function call start]
(
)
--[function call end]
--[suffix list end]
--[value end]
--[indexed assign end]
} --[table constructor end]
)
--[function call end]
--[suffix list end]
--[suffixed expr start] any
--[primary start] closure
function()
end
--[primary end]
--[suffix list start]
--[function call start] any
(
{ --[table constructor start] table
--[indexed assign start] any
--[value start]
--[suffixed expr start] any
--[primary start] any
f --global symbol ?
--[primary end]
--[suffix list start]
--[function call start] any
(
)
--[function call end]
--[suffix list end]
--[suffixed expr end]
--[value end]
--[indexed assign end]
} --[table constructor end]
)
--[function call end]
--[suffix list end]
--[suffixed expr end]
--[expression list end]
--[expression statement end]
end
@ -249,7 +291,7 @@ function()
--[symbols]
sum --local symbol ?
for
j --local symbol ?
j --local symbol integer
=
1
,
@ -257,16 +299,18 @@ function()
do
--[expression statement start]
--[var list start]
--[primary start]
sum --local symbol ?
--[primary end]
--[suffixed expr start] any
--[primary start] any
sum --local symbol ?
--[primary end]
--[suffixed expr end]
= --[var list end]
--[expression list start]
0.0000000000000000
--[expression list end]
--[expression statement end]
for
k --local symbol ?
k --local symbol integer
=
1
,
@ -274,30 +318,40 @@ function()
do
--[expression statement start]
--[var list start]
--[primary start]
sum --local symbol ?
--[primary end]
= --[var list end]
--[expression list start]
--[binary expr start]
--[primary start]
--[suffixed expr start] any
--[primary start] any
sum --local symbol ?
--[primary end]
--[suffixed expr end]
= --[var list end]
--[expression list start]
--[binary expr start] any
--[suffixed expr start] any
--[primary start] any
sum --local symbol ?
--[primary end]
--[suffixed expr end]
+
--[binary expr start]
--[binary expr start] number
1.0000000000000000
/
--[primary start]
--[binary expr start]
--[primary start]
k --local symbol ?
--[primary end]
*
--[primary start]
k --local symbol ?
--[primary end]
--[binary expr end]
--[primary end]
--[suffixed expr start] integer
--[primary start] integer
--[binary expr start] integer
--[suffixed expr start] integer
--[primary start] integer
k --local symbol integer
--[primary end]
--[suffixed expr end]
*
--[suffixed expr start] integer
--[primary start] integer
k --local symbol integer
--[primary end]
--[suffixed expr end]
--[binary expr end]
--[primary end]
--[suffixed expr end]
--[binary expr end]
--[binary expr end]
--[expression list end]
@ -305,9 +359,596 @@ function()
end
end
return
--[primary start]
sum --local symbol ?
--[primary end]
--[suffixed expr start] any
--[primary start] any
sum --local symbol ?
--[primary end]
--[suffixed expr end]
end
end
function()
--locals a
local
--[symbols]
a --local symbol integer
return
--[binary expr start] integer
--[suffixed expr start] integer
--[primary start] integer
a --local symbol integer
--[primary end]
--[suffixed expr end]
+
3
--[binary expr end]
end
function()
--locals i
local
--[symbols]
i --local symbol integer
return
--[suffixed expr start] any
--[primary start] any
t --global symbol ?
--[primary end]
--[suffix list start]
--[Y index start] any
[
--[binary expr start] number
--[suffixed expr start] integer
--[primary start] integer
i --local symbol integer
--[primary end]
--[suffixed expr end]
/
5
--[binary expr end]
]
--[Y index end]
--[suffix list end]
--[suffixed expr end]
end
function()
--locals t
local
--[symbols]
t --local symbol integer[]
return
--[suffixed expr start] integer
--[primary start] integer[]
t --local symbol integer[]
--[primary end]
--[suffix list start]
--[Y index start] integer
[
0
]
--[Y index end]
--[suffix list end]
--[suffixed expr end]
end
function()
return
--[suffixed expr start] any
--[primary start] any
f --global symbol ?
--[primary end]
--[suffix list start]
--[function call start] any
(
)
--[function call end]
--[Y index start] any
[
1
]
--[Y index end]
--[suffix list end]
--[suffixed expr end]
end
function()
return
--[suffixed expr start] any
--[primary start] any
x --global symbol ?
--[primary end]
--[suffix list start]
--[field selector start] any
.
'y'
--[field selector end]
--[Y index start] any
[
1
]
--[Y index end]
--[suffix list end]
--[suffixed expr end]
end
function()
--locals t
local
--[symbols]
t --local symbol integer[]
if
--[suffixed expr start] boolean
--[primary start] boolean
--[binary expr start] boolean
--[suffixed expr start] integer
--[primary start] integer[]
t --local symbol integer[]
--[primary end]
--[suffix list start]
--[Y index start] integer
[
1
]
--[Y index end]
--[suffix list end]
--[suffixed expr end]
==
5
--[binary expr end]
--[primary end]
--[suffixed expr end]
then
return
true
end
return
false
end
function()
--locals t, len
local
--[symbols]
t --local symbol table
local
--[symbols]
len --local symbol integer
--[expressions]
--[unary expr start] integer
@integer
--[unary expr start] any
#
--[suffixed expr start] table
--[primary start] table
t --local symbol table
--[primary end]
--[suffixed expr end]
--[unary expr end]
--[unary expr end]
return
--[suffixed expr start] integer
--[primary start] integer
len --local symbol integer
--[primary end]
--[suffixed expr end]
end
function()
return
function(
t --local symbol table
,
i --local symbol integer
)
--locals t, i
--[expression statement start]
--[var list start]
--[suffixed expr start] integer
--[primary start] integer
i --local symbol integer
--[primary end]
--[suffixed expr end]
= --[var list end]
--[expression list start]
--[unary expr start] integer
@integer
--[unary expr start] any
#
--[suffixed expr start] table
--[primary start] table
t --local symbol table
--[primary end]
--[suffixed expr end]
--[unary expr end]
--[unary expr end]
--[expression list end]
--[expression statement end]
end
end
function()
matmul --global symbol ?
=
function(
a --local symbol table
,
b --local symbol table
)
--locals a, b, m, n, p, x, c, i, xi, j, sum, ai, cj, k
--[expression statement start]
--[expression list start]
--[suffixed expr start] any
--[primary start] any
assert --global symbol ?
--[primary end]
--[suffix list start]
--[function call start] any
(
--[binary expr start] any
--[unary expr start] integer
@integer
--[suffixed expr start] any
--[primary start] any
--[unary expr start] any
#
--[suffixed expr start] any
--[primary start] table
a --local symbol table
--[primary end]
--[suffix list start]
--[Y index start] any
[
1
]
--[Y index end]
--[suffix list end]
--[suffixed expr end]
--[unary expr end]
--[primary end]
--[suffixed expr end]
--[unary expr end]
==
--[unary expr start] any
#
--[suffixed expr start] table
--[primary start] table
b --local symbol table
--[primary end]
--[suffixed expr end]
--[unary expr end]
--[binary expr end]
)
--[function call end]
--[suffix list end]
--[suffixed expr end]
--[expression list end]
--[expression statement end]
local
--[symbols]
m --local symbol integer
,
n --local symbol integer
,
p --local symbol integer
,
x --local symbol table
--[expressions]
--[unary expr start] integer
@integer
--[unary expr start] any
#
--[suffixed expr start] table
--[primary start] table
a --local symbol table
--[primary end]
--[suffixed expr end]
--[unary expr end]
--[unary expr end]
,
--[unary expr start] integer
@integer
--[unary expr start] any
#
--[suffixed expr start] any
--[primary start] table
a --local symbol table
--[primary end]
--[suffix list start]
--[Y index start] any
[
1
]
--[Y index end]
--[suffix list end]
--[suffixed expr end]
--[unary expr end]
--[unary expr end]
,
--[unary expr start] integer
@integer
--[unary expr start] any
#
--[suffixed expr start] any
--[primary start] table
b --local symbol table
--[primary end]
--[suffix list start]
--[Y index start] any
[
1
]
--[Y index end]
--[suffix list end]
--[suffixed expr end]
--[unary expr end]
--[unary expr end]
,
{ --[table constructor start] table
} --[table constructor end]
local
--[symbols]
c --local symbol table
--[expressions]
--[suffixed expr start] any
--[primary start] any
matrix --global symbol ?
--[primary end]
--[suffix list start]
--[field selector start] any
.
'T'
--[field selector end]
--[function call start] any
(
--[suffixed expr start] table
--[primary start] table
b --local symbol table
--[primary end]
--[suffixed expr end]
)
--[function call end]
--[suffix list end]
--[suffixed expr end]
for
i --local symbol integer
=
1
,
--[suffixed expr start] integer
--[primary start] integer
m --local symbol integer
--[primary end]
--[suffixed expr end]
do
local
--[symbols]
xi --local symbol number[]
--[expressions]
--[suffixed expr start] any
--[primary start] any
table --global symbol ?
--[primary end]
--[suffix list start]
--[field selector start] any
.
'numarray'
--[field selector end]
--[function call start] any
(
--[suffixed expr start] integer
--[primary start] integer
p --local symbol integer
--[primary end]
--[suffixed expr end]
,
0.0000000000000000
)
--[function call end]
--[suffix list end]
--[suffixed expr end]
--[expression statement start]
--[var list start]
--[suffixed expr start] any
--[primary start] table
x --local symbol table
--[primary end]
--[suffix list start]
--[Y index start] any
[
--[suffixed expr start] integer
--[primary start] integer
i --local symbol integer
--[primary end]
--[suffixed expr end]
]
--[Y index end]
--[suffix list end]
--[suffixed expr end]
= --[var list end]
--[expression list start]
--[suffixed expr start] number[]
--[primary start] number[]
xi --local symbol number[]
--[primary end]
--[suffixed expr end]
--[expression list end]
--[expression statement end]
for
j --local symbol integer
=
1
,
--[suffixed expr start] integer
--[primary start] integer
p --local symbol integer
--[primary end]
--[suffixed expr end]
do
local
--[symbols]
sum --local symbol number
,
ai --local symbol number[]
,
cj --local symbol number[]
--[expressions]
0.0000000000000000
,
--[unary expr start] number[]
@number[]
--[suffixed expr start] any
--[primary start] any
--[suffixed expr start] any
--[primary start] table
a --local symbol table
--[primary end]
--[suffix list start]
--[Y index start] any
[
--[suffixed expr start] integer
--[primary start] integer
i --local symbol integer
--[primary end]
--[suffixed expr end]
]
--[Y index end]
--[suffix list end]
--[suffixed expr end]
--[primary end]
--[suffixed expr end]
--[unary expr end]
,
--[unary expr start] number[]
@number[]
--[suffixed expr start] any
--[primary start] any
--[suffixed expr start] any
--[primary start] table
c --local symbol table
--[primary end]
--[suffix list start]
--[Y index start] any
[
--[suffixed expr start] integer
--[primary start] integer
j --local symbol integer
--[primary end]
--[suffixed expr end]
]
--[Y index end]
--[suffix list end]
--[suffixed expr end]
--[primary end]
--[suffixed expr end]
--[unary expr end]
for
k --local symbol integer
=
1
,
--[suffixed expr start] integer
--[primary start] integer
n --local symbol integer
--[primary end]
--[suffixed expr end]
do
--[expression statement start]
--[var list start]
--[suffixed expr start] number
--[primary start] number
sum --local symbol number
--[primary end]
--[suffixed expr end]
= --[var list end]
--[expression list start]
--[binary expr start] number
--[suffixed expr start] number
--[primary start] number
sum --local symbol number
--[primary end]
--[suffixed expr end]
+
--[binary expr start] number
--[suffixed expr start] number
--[primary start] number[]
ai --local symbol number[]
--[primary end]
--[suffix list start]
--[Y index start] number
[
--[suffixed expr start] integer
--[primary start] integer
k --local symbol integer
--[primary end]
--[suffixed expr end]
]
--[Y index end]
--[suffix list end]
--[suffixed expr end]
*
--[suffixed expr start] number
--[primary start] number[]
cj --local symbol number[]
--[primary end]
--[suffix list start]
--[Y index start] number
[
--[suffixed expr start] integer
--[primary start] integer
k --local symbol integer
--[primary end]
--[suffixed expr end]
]
--[Y index end]
--[suffix list end]
--[suffixed expr end]
--[binary expr end]
--[binary expr end]
--[expression list end]
--[expression statement end]
end
--[expression statement start]
--[var list start]
--[suffixed expr start] number
--[primary start] number[]
xi --local symbol number[]
--[primary end]
--[suffix list start]
--[Y index start] number
[
--[suffixed expr start] integer
--[primary start] integer
j --local symbol integer
--[primary end]
--[suffixed expr end]
]
--[Y index end]
--[suffix list end]
--[suffixed expr end]
= --[var list end]
--[expression list start]
--[suffixed expr start] number
--[primary start] number
sum --local symbol number
--[primary end]
--[suffixed expr end]
--[expression list end]
--[expression statement end]
end
end
return
--[suffixed expr start] table
--[primary start] table
x --local symbol table
--[primary end]
--[suffixed expr end]
end
return
--[suffixed expr start] any
--[primary start] any
matmul --global symbol ?
--[primary end]
--[suffixed expr end]
end

@ -73,4 +73,73 @@ str=
return sum
end
]]
doast(str)
str=
[[local a: integer return a+3
]]
doast(str)
str=
[[local i: integer; return t[i/5]
]]
doast(str)
str=
[[local t: integer[]; return t[0]
]]
doast(str)
str=
[[return f()[1]
]]
doast(str)
str=
[[return x.y[1]
]]
doast(str)
str=
[[local t: integer[]
if (t[1] == 5) then
return true
end
return false
]]
doast(str)
str=
[[local t: table
local len: integer = #t
return len
]]
doast(str)
str=
[[return function(t: table, i: integer)
i = #t
end
]]
doast(str)
str=
[[function matmul(a: table, b: table)
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
local xi: number[] = table.numarray(p, 0.0)
x[i] = xi
for j = 1, p do
local sum: number, ai: number[], cj: number[] = 0.0, @number[](a[i]), @number[](c[j]);
-- for luajit, caching c[j] or not makes no difference; lua is not so clever
for k = 1, n do sum = sum + ai[k] * cj[k] end
xi[j] = sum;
end
end
return x
end
return matmul
]]
doast(str)

@ -1,4 +1,6 @@
ravi.auto(true)
if ravi then
ravi.auto(true)
end
print "testing code generation and optimizations"
T = ravi
@ -121,9 +123,10 @@ opcodes_coverage.TOTYPE = 0
opcodes_coverage.TOSTRING = 0
opcodes_coverage.TOCLOSURE = 0
opcodes_coverage.SELF_SK = 0
opcodes_coverage.DEFER = 0
local compile = function(f)
if ravi.jit() then
if ravi and ravi.jit() then
assert(ravi.compile(f))
end
return true
@ -136,6 +139,9 @@ end
-- testing opcodes
function check (f, ...)
if not T then
return true
end
local arg = {...}
local c = T.listcode(f)
for i=1, #arg do
@ -148,6 +154,9 @@ end
function checkequal (a, b)
if not T then
return true
end
a = T.listcode(a)
b = T.listcode(b)
for i = 1, #a do
@ -1705,6 +1714,128 @@ compile(x)
x()
print 'Test 75 OK'
-- Test that % of ints results in int
function x(a: integer, b:integer)
return a%b == 0
end
check(x, 'TOINT', 'TOINT', 'MOD',
'EQ_II', 'JMP', 'LOADBOOL', 'LOADBOOL', 'RETURN', 'RETURN')
assert(x(10,5))
compile(x)
assert(x(10,5))
print 'Test 76 OK'
-- Test that ^ applied to numbers results in a number
function x(a:number, b:number)
local c:number = a^b
return c
end
check(x, 'TOFLT', 'TOFLT', 'POW', 'RETURN', 'RETURN')
assert(x(2,3) == 2^3)
compile(x)
assert(x(2,3) == 2^3)
print 'Test 77 OK'
-- Test defer statement
y = 0
function x()
defer y = y + 1 end
defer y = y + 1 end
end
check(x, 'DEFER', 'CLOSURE', 'DEFER', 'CLOSURE', 'RETURN')
x()
assert(y == 2)
compile(x)
x()
assert(y == 4)
print 'Test 78 OK'
-- Test defer statement
y = 0
function x()
defer y = y + 1 end
error('raise error')
defer y = y + 2 end -- will not be called
end
pcall(x)
assert(y == 1)
compile(x)
pcall(x)
assert(y == 2)
print 'Test 79 OK'
-- Test defer statement
y = 0
function x()
defer y = y + 1 end
defer y = y + 2; error('err') end
defer y = y + 3 end
end
pcall(x)
assert(y == 6)
compile(x)
pcall(x)
assert(y == 12)
print 'Test 80 OK'
-- Test defer statement in tailcalls
y = 0
function x (n)
defer y = y + 1 end
if n > 0 then return x(n - 1) end
end
pcall(x, 3)
assert(y == 4)
compile(x)
pcall(x, 3)
assert(y == 8)
print 'Test 81 OK'
-- Simulate a test of resource closure with defer
y = 0
z = { count = 0 }
z.__index = z;
function z:new()
local object = {}
setmetatable(object, z)
return object
end
function z:open(arg)
if (arg) then
z.count = z.count + 1
return
end
y = 1
error('error opening')
end
function z.close()
z.count = z.count - 1
end
function x(arg)
local f = z:new()
f:open(arg)
assert(z.count == 1)
defer f:close() end
end
x('filename')
assert(y == 0)
assert(z.count == 0)
pcall(x, false)
assert(z.count == 0)
assert(y == 1)
y = 0
compile(x)
compile(z.new)
compile(z.open)
compile(z.close)
x('filename')
assert(y == 0)
assert(z.count == 0)
pcall(x, false)
assert(z.count == 0)
assert(y == 1)
print 'Test 82 OK'
for k,v in pairs(opcodes_coverage)
do
print(k, v)

@ -122,6 +122,7 @@ opcodes_coverage.TABLE_SELF_SK = 0
opcodes_coverage.TOTYPE = 0
opcodes_coverage.TOSTRING = 0
opcodes_coverage.TOCLOSURE = 0
opcodes_coverage.DEFER = 0
--ravi.verbosity(1)

@ -13,6 +13,7 @@ Contents:
ravi-overview
ravi-reference
ravi-mir-instructions
ravi-omr-instructions
ravi-llvm-instructions
ravi-dmrc

@ -0,0 +1,13 @@
Instructions for Building With MIR JIT support
==============================================
Please note that currently `MIR <https://github.com/vnmakarov/mir>`_ JIT support is only available on Linux X86-64 platforms.
Building with MIR support is straightforward as MIR is included in Ravi::
mkdir buildmir
cd buildmir
cmake -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" -DMIR_JIT=ON ..
make install
That's it.

@ -1,19 +1,75 @@
New Parser and Code Generator for Ravi
======================================
Status
------
The basic parser and type checker have been implemented. However the ``defer`` statement is not yet done.
Progress is very slow but things are moving every now and then when I get time.
Usage
-----
The parse tree can be generated as follows::
tree, errmessage = ast.parse 'some lua code'
if not tree then
print(errmessage)
else
print(tree:tostring())
end
Examples::
tree, errmessage = ast.parse 'print "hello"'
if not tree then
print(errmessage)
else
print(tree:tostring())
end
This generates output::
function()
--[expression statement start]
--[expression list start]
--[suffixed expr start] any
--[primary start] any
print --global symbol ?
--[primary end]
--[suffix list start]
--[function call start] any
(
'hello'
)
--[function call end]
--[suffix list end]
--[suffixed expr end]
--[expression list end]
--[expression statement end]
end
For more examples please see:
* `ravi-tests/ravi_test_ast.lua <https://github.com/dibyendumajumdar/ravi/blob/master/ravi-tests/ravi_test_ast.lua>`_
* `ravi-tests/ravi_test_ast2.lua <https://github.com/dibyendumajumdar/ravi/blob/master/ravi-tests/ravi_test_ast2.lua>`_.
If you run these scripts the parse AST will be dumped to stdout.
Design Notes
------------
These are some design notes on the new parser / code generator.
There will be several phases:
1. Convert input into syntax tree - this will look very much like the input source, i.e. there will be fornum loops, if statements,
while and repeat loops etc. During this phase only the types for literals and local decalarations will be known.
while and repeat loops etc. During this phase only the types for literals and local decalarations will be known. MOSTLY DONE.
2. The next phase will be a type checking phase. In this phase types will be derive for expressions, and also type assertions will be
added where required such as unpon function entry, and after function calls. But the overall syntax tree will still resemble the input
source except for the additional instructions.
source except for the additional instructions. MOSTLY DONE.
3. Third phase will be to assign virtual registers; first to locals, and then to temporaries. For simplicity I will probably keep the
temporaries and locals in separate ranges.
4. Next phase will be linearize the instructions - during this phase the loops, if statements etc will get translated to equivalent of
conditional and unconditional jumps.
conditional and unconditional jumps. We will probably create intermediate structures that can easily map to Ravi bytecodes.
5. In the first phase we will stop here, generate byte code and finish.
6. The next phase will be translate into basic blocks.
7. Following that we will construct a CFG, perform dominator analysis and convert to SSA form.
@ -28,8 +84,11 @@ Some other things
to generate more optimized code.
Current Status
Implementation
--------------
We have a parser implementation that can convert Ravi source to an abstract syntax tree (AST). Static type checking is being worked on. Progress is very slow but things are moving every now and then when I get time.
The new Ravi Parser and Code Generator implementation is in:
* `ravi_ast_parse.c <https://github.com/dibyendumajumdar/ravi/blob/master/src/ravi_ast_parse.c>`_ - contains the parser that builds AST
* `ravi_ast_print.c <https://github.com/dibyendumajumdar/ravi/blob/master/src/ravi_ast_print.c>`_ - contains utilities for printing out the AST
* `ravi_ast_typecheck.c <https://github.com/dibyendumajumdar/ravi/blob/master/src/ravi_ast_typecheck.c>`_ - contains the type checking phase of the parser
For examples of how to call the parser please see `ravi-tests/ravi_test_ast.lua <https://github.com/dibyendumajumdar/ravi/blob/master/ravi-tests/ravi_test_ast.lua>`_ and `ravi-tests\ravi_test_ast2.lua <https://github.com/dibyendumajumdar/ravi/blob/master/ravi-tests/ravi_test_ast2.lua>`_. If you run these scripts the parse AST will be dumped to stdout.

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

@ -228,8 +228,8 @@ Each slice holds an internal reference to the underlying array to ensure that th
For an example use of slices please see the `matmul1_ravi.lua <https://github.com/dibyendumajumdar/ravi/blob/master/ravi-tests/matmul1_ravi.lua>`_ benchmark program in the repository. Note that this feature is highly experimental and not very well tested.
Examples
--------
Type Annotation Examples
------------------------
Example of code that works - you can copy this to the command line input::
function tryme()
@ -275,3 +275,32 @@ Another example using arrays. Here the function receives a parameter ``arr`` of
print(sum(table.numarray(10, 2.0)))
The ``table.numarray(n, initial_value)`` creates a ``number[]`` of specified size and initializes the array with the given initial value.
``defer`` statement
-------------------
A new addition to Ravi is the ``defer`` statement. The statement has the form::
defer
block
end
Where ``block`` is a set of Lua statements.
The ``defer`` statement creates an anonymous ``closure`` that will be invoked when the enclosing scope is exited, whether
normally or because of an error.
Example::
y = 0
function x()
defer y = y + 1 end
defer y = y + 1 end
end
x()
assert(y == 2)
``defer`` statements are meant to be used for releasing resources in a deterministic manner. The syntax and functionality is
inspired by the similar statement in the Go language. The implementation is based upon Lua 5.4.
Note that the ``defer`` statement should be considered a beta feature not yet ready for production use as it is undergoing testing.

@ -7,7 +7,7 @@
PLAT= none
#CC= gcc -std=gnu99
CFLAGS= -O2 -Wall -Wextra -DNDEBUG -fomit-frame-pointer -DLUA_COMPAT_5_2 -DLUA_COMPAT_5_1 $(SYSCFLAGS) $(MYCFLAGS) -I../include -I../dmr_c/src -I../dmr_c/null-backend
CFLAGS= -O2 -Wall -DNDEBUG -fomit-frame-pointer -DLUA_COMPAT_5_2 -DLUA_COMPAT_5_1 $(SYSCFLAGS) $(MYCFLAGS) -I../include -I../dmr_c/src -I../dmr_c/null-backend
CXXFLAGS=$(CFLAGS) -fno-rtti -Wno-sign-compare -std=c++14 -fno-exceptions -I../include
LDFLAGS= $(SYSLDFLAGS) $(MYLDFLAGS)
LIBS= -lm $(SYSLIBS) $(MYLIBS)
@ -35,14 +35,11 @@ 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 ltests.o \
ltm.o lundump.o lvm.o lzio.o ravi_profile.o ravi_membuf.o \
ravi_jitshared.o ravi_nojit.o ravi_ast.o ravi_alloc.o $(CORE_CPP_O)
ravi_jitshared.o ravi_nojit.o ravi_ast_parse.o ravi_ast_print.o ravi_ast_typecheck.o ravi_alloc.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
DMRC_O= allocate.o builtin.o char.o expression.o evaluate.o expand.o inline.o \
lib.o linearize.o liveness.o parse.o target.o tokenize.o pre-process.o \
ptrlist.o scope.o show-parse.o symbol.o walksymbol.o \
ravi_dmrc_parsesymbols.o
DMRC_O= allocate.o ptrlist.o
BASE_O= $(CORE_O) $(LIB_O) $(DMRC_O) $(MYOBJS)
LUA_T= ravi
@ -140,13 +137,15 @@ bit.o: bit.c ../include/lua.h ../include/luaconf.h ../include/lauxlib.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/lzio.h ../include/lmem.h ../include/lopcodes.h \
../include/ravi_arch.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
../include/luaconf.h ../include/lauxlib.h ../include/lua.h \
../include/ravi_alloc.h
lbaselib.o: lbaselib.c ../include/lprefix.h ../include/lua.h \
../include/luaconf.h ../include/lauxlib.h ../include/lua.h \
../include/lualib.h
@ -157,11 +156,11 @@ 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
../include/ravi_arch.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
@ -173,40 +172,42 @@ ldblib.o: ldblib.c ../include/lprefix.h ../include/lua.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
../include/ltm.h ../include/lzio.h ../include/lmem.h \
../include/lopcodes.h ../include/ravi_arch.h ../include/lcode.h \
../include/llex.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/lzio.h ../include/lmem.h ../include/lopcodes.h \
../include/ravi_arch.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
../include/ldebug.h ../include/lfunc.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
../include/lopcodes.h ../include/ravi_arch.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
../include/lopcodes.h ../include/ravi_arch.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/lzio.h ../include/lmem.h ../include/lopcodes.h \
../include/ravi_arch.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
@ -219,7 +220,8 @@ liolib.o: liolib.c ../include/lprefix.h ../include/lua.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/ltm.h ../include/lzio.h ../include/lmem.h \
../include/lopcodes.h ../include/ravi_arch.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
@ -229,7 +231,8 @@ lmathlib.o: lmathlib.c ../include/lprefix.h ../include/lua.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/lzio.h ../include/lmem.h ../include/lopcodes.h \
../include/ravi_arch.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 \
@ -238,13 +241,15 @@ 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
../include/lmem.h ../include/lopcodes.h ../include/ravi_arch.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/ravi_arch.h ../include/lobject.h ../include/lstate.h \
../include/lobject.h ../include/ltm.h ../include/lzio.h \
../include/lmem.h ../include/lopcodes.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 \
@ -253,23 +258,25 @@ 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
../include/ravi_arch.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/ltm.h ../include/lzio.h ../include/lmem.h \
../include/lopcodes.h ../include/ravi_arch.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
../include/ravijit.h ../include/ravi_profile.h ../include/ravi_alloc.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/ltm.h ../include/lzio.h ../include/lmem.h \
../include/lopcodes.h ../include/ravi_arch.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 \
@ -278,7 +285,8 @@ lstrlib.o: lstrlib.c ../include/lprefix.h ../include/lua.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/ltm.h ../include/lzio.h ../include/lmem.h \
../include/lopcodes.h ../include/ravi_arch.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
@ -289,31 +297,32 @@ 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
../include/lopcodes.h ../include/ravi_arch.h ../include/lauxlib.h \
../include/lcode.h ../include/llex.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
../include/lzio.h ../include/lmem.h ../include/lopcodes.h \
../include/ravi_arch.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
../include/lopcodes.h ../include/ravi_arch.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/ltm.h ../include/lzio.h ../include/lmem.h \
../include/lopcodes.h ../include/ravi_arch.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
@ -323,42 +332,101 @@ lutf8lib.o: lutf8lib.c ../include/lprefix.h ../include/lua.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/lzio.h ../include/lmem.h ../include/lopcodes.h \
../include/ravi_arch.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
../include/ravi_profile.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
../include/ltm.h ../include/lzio.h ../include/lmem.h \
../include/lopcodes.h ../include/ravi_arch.h ../include/lzio.h
ravi_alloc.o: ravi_alloc.c
ravi_ast_parse.o: ravi_ast_parse.c ../include/ravi_ast.h \
../include/lprefix.h ../include/lua.h ../include/luaconf.h \
../include/lcode.h ../include/llex.h ../include/lobject.h \
../include/llimits.h ../include/lzio.h ../include/lmem.h \
../include/lopcodes.h ../include/ravi_arch.h ../include/lparser.h \
../include/ldo.h ../include/lstate.h ../include/ltm.h \
../include/lstring.h ../include/lgc.h ../include/ltable.h \
../include/lauxlib.h ../include/ravi_ast.h ../include/ravi_membuf.h \
../dmr_c/src/allocate.h ../dmr_c/src/port.h ../dmr_c/src/ptrlist.h
ravi_ast_print.o: ravi_ast_print.c ../include/ravi_ast.h \
../include/lprefix.h ../include/lua.h ../include/luaconf.h \
../include/lcode.h ../include/llex.h ../include/lobject.h \
../include/llimits.h ../include/lzio.h ../include/lmem.h \
../include/lopcodes.h ../include/ravi_arch.h ../include/lparser.h \
../include/ldo.h ../include/lstate.h ../include/ltm.h \
../include/lstring.h ../include/lgc.h ../include/ltable.h \
../include/lauxlib.h ../include/ravi_ast.h ../include/ravi_membuf.h \
../dmr_c/src/allocate.h ../dmr_c/src/port.h ../dmr_c/src/ptrlist.h
ravi_ast_typecheck.o: ravi_ast_typecheck.c ../include/ravi_ast.h \
../include/lprefix.h ../include/lua.h ../include/luaconf.h \
../include/lcode.h ../include/llex.h ../include/lobject.h \
../include/llimits.h ../include/lzio.h ../include/lmem.h \
../include/lopcodes.h ../include/ravi_arch.h ../include/lparser.h \
../include/ldo.h ../include/lstate.h ../include/ltm.h \
../include/lstring.h ../include/lgc.h ../include/ltable.h \
../include/lauxlib.h ../include/ravi_ast.h ../include/ravi_membuf.h \
../dmr_c/src/allocate.h ../dmr_c/src/port.h ../dmr_c/src/ptrlist.h
ravi_dmrc_parsesymbols.o: ravi_dmrc_parsesymbols.c \
../dmr_c/src/allocate.h ../dmr_c/src/port.h \
../dmr_c/null-backend/dmr_c.h ../dmr_c/src/expression.h \
../dmr_c/src/lib.h ../dmr_c/src/ptrlist.h ../dmr_c/src/symbol.h \
../dmr_c/src/target.h ../dmr_c/src/token.h ../dmr_c/src/ident-list.h \
../dmr_c/src/parse.h ../dmr_c/src/scope.h ../include/lua.h \
../include/luaconf.h ../include/lauxlib.h ../include/lua.h \
../include/lualib.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
../include/lzio.h ../include/lmem.h ../include/lopcodes.h \
../include/ravi_arch.h ../include/ldo.h ../include/lfunc.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
../include/ltm.h ../include/lzio.h ../include/lmem.h \
../include/lopcodes.h ../include/ravi_arch.h ../include/ldo.h \
../include/lfunc.h ../include/lstring.h ../include/lgc.h \
../include/ltable.h ../include/lvm.h ../include/ravi_membuf.h
ravi_omrjitapi.o: ravi_omrjitapi.c ../include/ravi_omrjit.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/lopcodes.h ../include/ravi_arch.h ../include/ldo.h \
../include/lfunc.h ../include/lstring.h ../include/lgc.h \
../include/ltable.h ../include/lvm.h ../include/ravi_membuf.h \
../include/ravijit.h ../include/lauxlib.h ../include/lobject.h \
../include/lstate.h ../include/lua.h
ravi_omrjit.o: ravi_omrjit.c ../include/ravi_omrjit.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/lopcodes.h ../include/ravi_arch.h ../include/ldo.h \
../include/lfunc.h ../include/lstring.h ../include/lgc.h \
../include/ltable.h ../include/lvm.h ../include/ravi_membuf.h \
../include/ravijit.h ../include/lauxlib.h ../include/lobject.h \
../include/lstate.h ../include/lua.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
../include/ravi_arch.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
../include/lzio.h ../include/lmem.h ../include/lopcodes.h \
../include/ravi_arch.h ../include/ldo.h ../include/lfunc.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

@ -29,3 +29,26 @@ The LLVM JIT implementation is in following sources:
* ravi_llvmcall.cpp - implements OP_CALL, OP_JMP
* ravi_llvmtable.cpp - implements OP_GETTABLE, OP_SETTABLE and various other table operations, OP_SELF, and also upvalue operations
* ravi_llvmrest.cpp - OP_CLOSURE, OP_VARARG, OP_CONCAT
Apart from LLVM backend, we also have MIR and OMR JIT backends.
These backends use C as the intermediate language. The common C code generator is in:
* ravi_jitshared.c - this is the C code generator for a given Ravi / Lua function
The MIR JIT implementation is in:
* ravi_mirjit.c - defines the driver functions. The MIR backend has its own C preprocessor, parser and code generator.
The OMR JIT driver is in:
* ravi_omrjit.c - defines the driver functions. The OMR JIT backend uses the dmrC project as the C preprocessor, parser and code generator.
The new Ravi Parser and Code Generator implementation is in:
* ravi_ast_parse.c - contains the parser that builds AST
* ravi_ast_print.c - contains utilities for printing out the AST
* ravi_ast_typecheck.c - contains the type checking phase of the parser
Ravi also uses Doug Lea's malloc implementation. The implementation is in:
* ravi_alloc.c - Doug Lea's malloc implementation, adapted for Ravi.

@ -5,7 +5,7 @@
*/
/*
** Portions Copyright (C) 2015-2017 Dibyendu Majumdar
** Portions Copyright (C) 2015-2020 Dibyendu Majumdar
*/

@ -5,7 +5,7 @@
*/
/*
** Portions Copyright (C) 2015-2017 Dibyendu Majumdar
** Portions Copyright (C) 2015-2020 Dibyendu Majumdar
*/
#define lcode_c
@ -1387,7 +1387,13 @@ static void codebinexpval (FuncState *fs, OpCode op,
&& (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 || e1->ravi_type == RAVI_TNUMFLT)
&& (e2->ravi_type == RAVI_TNUMINT || e2->ravi_type == RAVI_TNUMFLT))
e1->ravi_type = RAVI_TNUMINT;
else if (op == OP_POW && (e1->ravi_type == RAVI_TNUMFLT || e1->ravi_type == RAVI_TNUMINT) &&
(e2->ravi_type == RAVI_TNUMFLT || e2->ravi_type == RAVI_TNUMINT))
e1->ravi_type = RAVI_TNUMFLT;
else if (op == OP_MOD && (e1->ravi_type == RAVI_TNUMINT && e2->ravi_type == RAVI_TNUMINT))
e1->ravi_type = RAVI_TNUMINT;
else
e1->ravi_type = RAVI_TANY;

@ -4,6 +4,10 @@
** See Copyright Notice in lua.h
*/
/*
** Portions Copyright (C) 2015-2020 Dibyendu Majumdar
*/
#define ldo_c
#define LUA_CORE
@ -90,7 +94,7 @@ struct lua_longjmp {
};
static void seterrorobj (lua_State *L, int errcode, StkId oldtop) {
void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
switch (errcode) {
case LUA_ERRMEM: { /* memory error? */
setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */
@ -123,7 +127,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
}
else { /* no handler at all; abort */
if (g->panic) { /* panic function? */
seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */
luaD_seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */
if (L->ci->top < L->top)
L->ci->top = L->top; /* pushing msg. can break this invariant */
lua_unlock(L);
@ -713,8 +717,8 @@ static int recover (lua_State *L, int status) {
if (ci == NULL) return 0; /* no recovery point */
/* "finish" luaD_pcall */
oldtop = restorestack(L, ci->extra);
luaF_close(L, oldtop);
seterrorobj(L, status, oldtop);
luaF_close(L, oldtop, status);
luaD_seterrorobj(L, status, oldtop);
L->ci = ci;
L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */
L->nny = 0; /* should be zero to be yieldable */
@ -800,7 +804,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
}
if (errorstatus(status)) { /* unrecoverable error? */
L->status = cast_byte(status); /* mark thread as 'dead' */
seterrorobj(L, status, L->top); /* push error message */
luaD_seterrorobj(L, status, L->top); /* push error message */
L->ci->top = L->top;
}
else lua_assert(status == L->status); /* normal end or yield */
@ -858,11 +862,12 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u,
status = luaD_rawrunprotected(L, func, u);
if (status != LUA_OK) { /* an error occurred? */
StkId oldtop = restorestack(L, old_top);
luaF_close(L, oldtop); /* close possible pending closures */
seterrorobj(L, status, oldtop);
L->ci = old_ci;
L->allowhook = old_allowhooks;
L->nny = old_nny;
status = luaF_close(L, oldtop, status); /* close possible pending closures */
oldtop = restorestack(L, old_top);
luaD_seterrorobj(L, status, oldtop);
luaD_shrinkstack(L);
}
L->errfunc = old_errfunc;

@ -5,7 +5,7 @@
*/
/*
** Portions Copyright (C) 2015-2017 Dibyendu Majumdar
** Portions Copyright (C) 2015-2020 Dibyendu Majumdar
*/

@ -5,7 +5,7 @@
*/
/*
** Portions Copyright (C) 2015-2017 Dibyendu Majumdar
** Portions Copyright (C) 2015-2020 Dibyendu Majumdar
*/
@ -19,6 +19,8 @@
#include "lua.h"
#include "ldebug.h"
#include "ldo.h"
#include "lfunc.h"
#include "lgc.h"
#include "lmem.h"
@ -66,13 +68,15 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
lua_assert(isintwups(L) || L->openupval == NULL);
while (*pp != NULL && (p = *pp)->v >= level) {
lua_assert(upisopen(p));
if (p->v == level) /* found a corresponding upvalue? */
return p; /* return it */
if (p->v == level && !p->flags) /* found a corresponding upvalue that is not a deferred value? */ {
return p; /* return it */
}
pp = &p->u.open.next;
}
/* not found: create a new upvalue */
uv = luaM_new(L, UpVal);
uv->refcount = 0;
uv->flags = 0;
uv->u.open.next = *pp; /* link it to list of open upvalues */
uv->u.open.touched = 1;
*pp = uv;
@ -84,20 +88,84 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
return uv;
}
static void calldeferred(lua_State *L, void *ud) {
UNUSED(ud);
luaD_callnoyield(L, L->top - 2, 0);
}
/*
** Prepare deferred function plus its arguments for object 'obj' with
** error message 'err'. (This function assumes EXTRA_STACK.)
*/
static int preparetocall(lua_State *L, TValue *func, TValue *err) {
StkId top = L->top;
setobj2s(L, top, func); /* will call deferred function */
if (err) {
setobj2s(L, top + 1, err); /* and error msg. as 1st argument */
}
else {
setnilvalue(top + 1);
}
L->top = top + 2; /* add function and arguments */
return 1;
}
/*
** Prepare and call a deferred function. If status is OK, code is still
** inside the original protected call, and so any error will be handled
** there. Otherwise, a previous error already activated the original
** protected call, and so the call to the deferred method must be
** protected here. (A status == -1 behaves like a previous
** error, to also run the closing method in protected mode).
** If status is OK, the call to the deferred method will be pushed
** at the top of the stack. Otherwise, values are pushed after
** the 'level' of the upvalue containing deferred function, as everything after
** that won't be used again.
*/
static int calldeferredfunction(lua_State *L, StkId level, int status) {
TValue *uv = level; /* value being closed */
if (status == LUA_OK) {
preparetocall(L, uv, NULL); /* something to call? */
calldeferred(L, NULL); /* call closing method */
}
else { /* must close the object in protected mode */
ptrdiff_t oldtop;
level++; /* space for error message */
oldtop = savestack(L, level + 1); /* top will be after that */
luaD_seterrorobj(L, status, level); /* set error message */
preparetocall(L, uv, level);
int newstatus = luaD_pcall(L, calldeferred, NULL, oldtop, 0);
if (newstatus != LUA_OK && status == -1) /* first error? */
status = newstatus; /* this will be the new error */
else {
/* leave original error (or nil) on top */
L->top = restorestack(L, oldtop);
}
}
return status;
}
void luaF_close (lua_State *L, StkId level) {
int luaF_close (lua_State *L, StkId level, int status) {
UpVal *uv;
while (L->openupval != NULL && (uv = L->openupval)->v >= level) {
lua_assert(upisopen(uv));
L->openupval = uv->u.open.next; /* remove from 'open' list */
if (uv->refcount == 0) /* no references? */
luaM_free(L, uv); /* free upvalue */
L->openupval = uv->u.open.next; /* remove from 'open' list */
if (uv->refcount == 0) { /* no references? */
UpVal uv1 = *uv; /* copy the upvalue as we will free it below */
luaM_free(L, uv); /* free upvalue before invoking any deferred functions */
if (uv1.flags && ttisfunction(uv1.v)) {
ptrdiff_t levelrel = savestack(L, level);
status = calldeferredfunction(L, uv1.v, status);
level = restorestack(L, levelrel);
}
}
else {
setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */
uv->v = &uv->u.value; /* now current value lives here */
luaC_upvalbarrier(L, uv);
}
}
return status;
}

@ -52,10 +52,12 @@ static const luaL_Reg loadedlibs[] = {
{LUA_UTF8LIBNAME, luaopen_utf8},
{LUA_DBLIBNAME, luaopen_debug},
{LUA_RAVILIBNAME, raviopen_llvmjit},
#ifdef USE_LLVM
{LUA_LLVMLIBNAME, raviopen_llvmluaapi},
#endif
//#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

@ -40,7 +40,7 @@
static const char *const luaX_tokens [] = {
"and", "break", "do", "else", "elseif",
"end", "false", "for", "function", "goto", "if",
"in", "local", "nil", "not", "or", "repeat",
"in", "local", "defer", "nil", "not", "or", "repeat",
"return", "then", "true", "until", "while",
"//", "..", "...", "==", ">=", "<=", "~=",
"<<", ">>", "::", "<eof>",

@ -5,7 +5,7 @@
*/
/*
** Portions Copyright (C) 2015-2017 Dibyendu Majumdar
** Portions Copyright (C) 2015-2020 Dibyendu Majumdar
*/
@ -163,6 +163,7 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
"SELF_SK", /* _SK*/ /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
"SETFIELD", /*_SK */ /* A B C R(A)[RK(B)] := RK(C), string key */
"GETTABUP_SK",
"DEFER",
NULL
};
@ -304,6 +305,9 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_RAVI_SELF_SK */
,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_RAVI_SETFIELD */
,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_RAVI_GETTABUP_SK */
,opmode(0, 1, OpArgN, OpArgN, iABC) /* OP_RAVI_DEFER */
};

@ -5,7 +5,7 @@
*/
/*
** Portions Copyright (C) 2015-2017 Dibyendu Majumdar
** Portions Copyright (C) 2015-2020 Dibyendu Majumdar
*/
#define lparser_c
@ -16,6 +16,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <lparser.h>
#include "lua.h"
@ -919,10 +920,17 @@ static Proto *addprototype (LexState *ls) {
** so that, if it invokes the GC, the GC knows which registers
** are in use at that time.
*/
static void codeclosure (LexState *ls, expdesc *v) {
static void codeclosure (LexState *ls, expdesc *v, int deferred) {
FuncState *fs = ls->fs->prev;
int pc = -1;
if (deferred) {
pc = luaK_codeABC(fs, OP_RAVI_DEFER, 0, 0, 0);
}
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 */
if (deferred) {
SETARG_A(fs->f->code[pc], v->u.info);
}
DEBUG_VARS(raviY_printf(ls->fs, "codeclosure -> closure created %e\n", v));
}
@ -1283,24 +1291,26 @@ static void parlist (LexState *ls) {
}
static void body (LexState *ls, expdesc *e, int ismethod, int line) {
static void body (LexState *ls, expdesc *e, int ismethod, int line, int deferred) {
/* body -> '(' parlist ')' block END */
FuncState new_fs;
BlockCnt bl;
new_fs.f = addprototype(ls);
new_fs.f->linedefined = line;
open_func(ls, &new_fs, &bl);
checknext(ls, '(');
if (ismethod) {
new_localvarliteral(ls, "self"); /* create 'self' parameter */
adjustlocalvars(ls, 1);
if (!deferred) {
checknext(ls, '(');
if (ismethod) {
new_localvarliteral(ls, "self"); /* create 'self' parameter */
adjustlocalvars(ls, 1);
}
parlist(ls);
checknext(ls, ')');
}
parlist(ls);
checknext(ls, ')');
statlist(ls);
new_fs.f->lastlinedefined = ls->linenumber;
check_match(ls, TK_END, TK_FUNCTION, line);
codeclosure(ls, e);
codeclosure(ls, e, deferred);
close_func(ls);
}
@ -1592,7 +1602,7 @@ static void simpleexp (LexState *ls, expdesc *v) {
}
case TK_FUNCTION: {
luaX_next(ls);
body(ls, v, 0, ls->linenumber);
body(ls, v, 0, ls->linenumber, 0);
return;
}
default: {
@ -2177,13 +2187,19 @@ static void ifstat (LexState *ls, int line) {
}
/* parse a local function statement - called from statement() */
static void localfunc (LexState *ls) {
static void localfunc (LexState *ls, int defer) {
expdesc b = {.ravi_type = RAVI_TANY, .pc = -1};
FuncState *fs = ls->fs;
/* RAVI change - add type */
new_localvar(ls, str_checkname(ls), RAVI_TFUNCTION, NULL); /* new local variable */
if (defer) {
static const char funcname[] = "(deferred function)";
new_localvar(ls, luaX_newstring(ls, funcname, sizeof funcname-1), RAVI_TFUNCTION, NULL); /* new local variable */
markupval(fs, fs->nactvar);
} else {
/* RAVI change - add type */
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 */
body(ls, &b, 0, ls->linenumber, defer); /* function created in next register */
/* debug information will only see the variable after this point! */
getlocvar(fs, b.u.info)->startpc = fs->pc;
}
@ -2246,7 +2262,7 @@ static void funcstat (LexState *ls, int line) {
luaX_next(ls); /* skip FUNCTION */
ismethod = funcname(ls, &v);
DEBUG_VARS(raviY_printf(ls->fs, "funcstat -> declaring function %e\n", &v));
body(ls, &b, ismethod, line);
body(ls, &b, ismethod, line, 0);
luaK_storevar(ls->fs, &v, &b);
luaK_fixline(ls->fs, line); /* definition "happens" in the first line */
}
@ -2339,11 +2355,16 @@ static void statement (LexState *ls) {
case TK_LOCAL: { /* stat -> localstat */
luaX_next(ls); /* skip LOCAL */
if (testnext(ls, TK_FUNCTION)) /* local function? */
localfunc(ls);
localfunc(ls, 0);
else
localstat(ls);
break;
}
case TK_DEFER: { /* stat -> deferstat */
luaX_next(ls); /* skip DEFER */
localfunc(ls, 1);
break;
}
case TK_DBCOLON: { /* stat -> label */
luaX_next(ls); /* skip double colon */
labelstat(ls, str_checkname(ls), line);

@ -270,7 +270,7 @@ void *ravi_alloc_f(void *msp, void *ptr, size_t osize, size_t nsize)
static void close_state (lua_State *L) {
global_State *g = G(L);
luaF_close(L, L->stack); /* close all upvalues for this thread */
luaF_close(L, L->stack, -1); /* close all upvalues for this thread */
luaC_freeallobjects(L); /* collect all objects */
if (g->version) /* closing a fully built state? */
luai_userstateclose(L);
@ -317,7 +317,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
void luaE_freethread (lua_State *L, lua_State *L1) {
LX *l = fromstate(L1);
luaF_close(L1, L1->stack); /* close all upvalues for this thread */
luaF_close(L1, L1->stack, -1); /* close all upvalues for this thread */
lua_assert(L1->openupval == NULL);
luai_userstatefree(L, L1);
freestack(L1);

@ -620,7 +620,7 @@ const TValue *luaH_getshortstr (Table *t, TString *key) {
}
#else
/* Continue search from n */
const TValue *luaH_getshortstr_continue(Table *t, TString *key, Node *n) {
const TValue *luaH_getshortstr_continue(TString *key, Node *n) {
for (;;) { /* check whether 'key' is somewhere in the chain starting from next node after n */
int nx = gnext(n);
if (nx == 0)

@ -50,6 +50,8 @@
#define RAVI_OPTION_STRING3 " LLVM-" LLVM_VERSION_STRING " ORC=" ravi_xstringify(USE_ORC_JIT) " v2=" ravi_xstringify(USE_ORCv2_JIT)
#elif USE_OMRJIT
#define RAVI_OPTION_STRING3 " omrjit"
#elif USE_MIRJIT
#define RAVI_OPTION_STRING3 " mirjit"
#else
#define RAVI_OPTION_STRING3 " nojit"
#endif

@ -5,7 +5,7 @@
*/
/*
** Portions Copyright (C) 2015-2017 Dibyendu Majumdar
** Portions Copyright (C) 2015-2020 Dibyendu Majumdar
*/
#define lundump_c

@ -5,7 +5,7 @@
*/
/*
** Portions Copyright (C) 2015-2017 Dibyendu Majumdar
** Portions Copyright (C) 2015-2020 Dibyendu Majumdar
*/
@ -1025,10 +1025,14 @@ void luaV_finishOp (lua_State *L) {
** Execute a jump instruction. The 'updatemask' allows signals to stop
** tight loops. (Without it, the local copy of 'mask' could never change.)
*/
#define dojump(ci,i,e) \
{ int a = GETARG_A(i); \
if (a != 0) luaF_close(L, ci->u.l.base + a - 1); \
pc += GETARG_sBx(i) + e; updatemask(L); }
#define dojump(ci, i, e) \
{ \
int a = GETARG_A(i); \
if (a != 0) \
Protect_base(luaF_close(L, ci->u.l.base + a - 1, LUA_OK)); \
pc += GETARG_sBx(i) + e; \
updatemask(L); \
}
/* for test instructions, execute the jump instruction that follows it */
#define donextjump(ci) { i = *pc; dojump(ci, i, 1); }
@ -1269,7 +1273,8 @@ int luaV_execute (lua_State *L) {
&&vmlabel(OP_RAVI_GETFIELD),
&&vmlabel(OP_RAVI_SELF_SK),
&&vmlabel(OP_RAVI_SETFIELD),
&&vmlabel(OP_RAVI_GETTABUP_SK)
&&vmlabel(OP_RAVI_GETTABUP_SK),
&&vmlabel(OP_RAVI_DEFER),
};
#endif
@ -1387,14 +1392,6 @@ int luaV_execute (lua_State *L) {
checkGC(L, ra + 1);
vmbreak;
}
vmcase(OP_RAVI_SELF_SK) {
StkId rb = RB(i); /* variable - may not be a table */
/* we know that the key a short string constant */
TValue *rc = RKC(i);
setobjs2s(L, ra + 1, rb);
GETTABLE_INLINE_SSKEY_PROTECTED(L, rb, rc, ra);
vmbreak;
}
vmcase(OP_SELF) {
const TValue *aux;
StkId rb = RB(i);
@ -1720,7 +1717,8 @@ int luaV_execute (lua_State *L) {
StkId lim = nci->u.l.base + getproto(nfunc)->numparams;
int aux;
/* close all upvalues from previous call */
if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base);
if (cl->p->sizep > 0)
Protect_base(luaF_close(L, oci->u.l.base, LUA_OK));
/* move new frame into old one */
for (aux = 0; nfunc + aux < lim; aux++)
setobjs2s(L, ofunc + aux, nfunc + aux);
@ -1737,7 +1735,8 @@ int luaV_execute (lua_State *L) {
}
vmcase(OP_RETURN) {
int b = GETARG_B(i);
if (cl->p->sizep > 0) luaF_close(L, base);
if (cl->p->sizep > 0)
Protect_base(luaF_close(L, base, LUA_OK));
savepc(L);
int nres = (b != 0 ? b - 1 : cast_int(L->top - ra));
b = luaD_poscall(L, ci, ra, nres);
@ -1847,6 +1846,14 @@ int luaV_execute (lua_State *L) {
vmcase(OP_SETLIST) {
int n = GETARG_B(i);
int c = GETARG_C(i);
#if 1
if (c == 0) {
lua_assert(GET_OPCODE(*pc) == OP_EXTRAARG);
c = GETARG_Ax(*pc++);
}
savepc(L); /* in case of allocation errors */
raviV_op_setlist(L, ci, ra, n, c);
#else
unsigned int last;
Table *h;
if (n == 0) n = cast_int(L->top - ra) - 1;
@ -1906,6 +1913,7 @@ int luaV_execute (lua_State *L) {
}
}
L->top = ci->top; /* correct top (in case of previous open call) */
#endif
vmbreak;
}
vmcase(OP_CLOSURE) {
@ -1921,6 +1929,9 @@ int luaV_execute (lua_State *L) {
vmbreak;
}
vmcase(OP_VARARG) {
#if 1
Protect_base(raviV_op_vararg(L, ci, cl, GETARG_A(i), GETARG_B(i)));
#else
int b = GETARG_B(i) - 1; /* required results */
int j;
int n = cast_int(base - ci->func) - cl->p->numparams - 1;
@ -1936,6 +1947,7 @@ int luaV_execute (lua_State *L) {
setobjs2s(L, ra + j, base - n + j);
for (; j < b; j++) /* complete required results with nil */
setnilvalue(ra + j);
#endif
vmbreak;
}
vmcase(OP_EXTRAARG) {
@ -2106,6 +2118,25 @@ int luaV_execute (lua_State *L) {
short string but the variable may or may not be
a table
*/
#if 1
vmcase(OP_RAVI_SELF_SK) vmcase(OP_RAVI_GETTABUP_SK) vmcase(OP_RAVI_GETFIELD) {
StkId rb = (op == OP_RAVI_GETTABUP_SK)
? cl->upvals[GETARG_B(i)]->v
: RB(i); /* variable - may not be a table */
TValue* rc = RKC(i);
if (op == OP_RAVI_SELF_SK) setobjs2s(L, ra + 1, rb);
Protect(raviV_gettable_sskey(L, rb, rc, ra));
vmbreak;
}
#else
vmcase(OP_RAVI_SELF_SK) {
StkId rb = RB(i); /* variable - may not be a table */
/* we know that the key a short string constant */
TValue *rc = RKC(i);
setobjs2s(L, ra + 1, rb);
GETTABLE_INLINE_SSKEY_PROTECTED(L, rb, rc, ra);
vmbreak;
}
vmcase(OP_RAVI_GETTABUP_SK) {
StkId rb = cl->upvals[GETARG_B(i)]->v; /* variable - may not be a table */
lua_assert(ISK(GETARG_C(i)));
@ -2122,6 +2153,7 @@ int luaV_execute (lua_State *L) {
GETTABLE_INLINE_SSKEY_PROTECTED(L, rb, rc, ra);
vmbreak;
}
#endif
vmcase(OP_RAVI_TABLE_SELF_SK)
vmcase(OP_RAVI_TABLE_GETFIELD) {
/* This opcode is used when the key is known to be
@ -2462,6 +2494,12 @@ int luaV_execute (lua_State *L) {
}
vmbreak;
}
vmcase(OP_RAVI_DEFER) {
UpVal *up = luaF_findupval(L, ra); /* create new upvalue */
up->flags = 1; /* mark it as deferred */
setnilvalue(ra); /* initialize it with nil */
vmbreak;
}
}
}
}
@ -2971,7 +3009,6 @@ void raviV_gettable_i(lua_State *L, const TValue *t, TValue *key, StkId val) {
GETTABLE_INLINE_I(L, t, key, val);
}
/*
** Main function for table assignment (invoking metamethods if needed).
** Compute 't[key] = val'
@ -2995,5 +3032,14 @@ void raviV_op_totype(lua_State *L, TValue *ra, TValue *rb) {
luaG_runerror(L, "type mismatch: expected %s", getstr(key));
}
/*
** OP_RAVI_DEFER
*/
void raviV_op_defer(lua_State *L, TValue *ra) {
UpVal *up = luaF_findupval(L, ra); /* create new upvalue */
up->flags = 1; /* mark it as deferred */
setnilvalue(ra); /* initialize it with nil */
}
/* }================================================================== */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,520 @@
/*
Copyright (C) 2018-2020 Dibyendu Majumdar
*/
#include <ravi_ast.h>
#include "ravi_ast.h"
static const char *type_name(ravitype_t tt) {
switch (tt) {
case RAVI_TANY:
return "any";
case RAVI_TNIL:
return "nil";
case RAVI_TBOOLEAN:
return "boolean";
case RAVI_TNUMFLT:
return "number";
case RAVI_TNUMINT:
return "integer";
case RAVI_TTABLE:
return "table";
case RAVI_TSTRING:
return "string";
case RAVI_TARRAYINT:
return "integer[]";
case RAVI_TARRAYFLT:
return "number[]";
case RAVI_TFUNCTION:
return "closure";
case RAVI_TUSERDATA:
return "";
default:
return "";
}
}
static void printf_buf(membuff_t *buf, const char *format, ...) {
static const char *PADDING = " ";
char tbuf[128] = {0};
va_list ap;
const char *cp;
va_start(ap, format);
for (cp = format; *cp; cp++) {
if (cp[0] == '%' && cp[1] == 'p') { /* padding */
int level = va_arg(ap, int);
snprintf(tbuf, sizeof tbuf, "%.*s", level, PADDING);
membuff_add_string(buf, tbuf);
cp++;
}
else if (cp[0] == '%' && cp[1] == 't') { /* TString */
const TString *ts;
ts = va_arg(ap, const TString *);
const char *s = getstr(ts);
membuff_add_string(buf, s);
cp++;
}
else if (cp[0] == '%' && cp[1] == 'T') { /* struct var_type */
const struct var_type *type;
type = va_arg(ap, const struct var_type *);
if (type->type_code == RAVI_TUSERDATA) {
const char *s = getstr(type->type_name);
membuff_add_string(buf, s);
}
else {
membuff_add_string(buf, type_name(type->type_code));
}
cp++;
}
else if (cp[0] == '%' && cp[1] == 's') { /* const char * */
const char *s;
s = va_arg(ap, const char *);
membuff_add_string(buf, s);
cp++;
}
else if (cp[0] == '%' && cp[1] == 'c') { /* comment */
const char *s;
s = va_arg(ap, const char *);
membuff_add_fstring(buf, "--%s", s);
cp++;
}
else if (cp[0] == '%' && cp[1] == 'i') { /* integer */
lua_Integer i;
i = va_arg(ap, lua_Integer);
membuff_add_longlong(buf, i);
cp++;
}
else if (cp[0] == '%' && cp[1] == 'f') { /* float */
double d;
d = va_arg(ap, double);
membuff_add_fstring(buf, "%.16f", d);
cp++;
}
else if (cp[0] == '%' && cp[1] == 'b') { /* boolean */
lua_Integer i;
i = va_arg(ap, lua_Integer);
membuff_add_bool(buf, i != 0);
cp++;
}
else {
membuff_add_char(buf, *cp);
}
}
va_end(ap);
}
static void print_ast_node_list(membuff_t *buf, struct ast_node_list *list, int level, const char *delimiter) {
struct ast_node *node;
bool is_first = true;
FOR_EACH_PTR(list, node) {
if (is_first)
is_first = false;
else if (delimiter)
printf_buf(buf, "%p%s\n", level, delimiter);
raviA_print_ast_node(buf, node, level + 1);
}
END_FOR_EACH_PTR(node);
}
static void print_statement_list(membuff_t *buf, struct ast_node_list *statement_list, int level) {
print_ast_node_list(buf, statement_list, level + 1, NULL);
}
static inline const char *get_as_str(const TString *ts) { return ts ? getstr(ts) : ""; }
static void print_symbol(membuff_t *buf, struct lua_symbol *sym, int level) {
switch (sym->symbol_type) {
case SYM_GLOBAL: {
printf_buf(buf, "%p%t %c %s %s\n", level, sym->var.var_name, "global symbol",
raviY_typename(sym->value_type.type_code), get_as_str(sym->value_type.type_name));
break;
}
case SYM_LOCAL: {
printf_buf(buf, "%p%t %c %s %s\n", level, sym->var.var_name, "local symbol",
raviY_typename(sym->value_type.type_code), get_as_str(sym->value_type.type_name));
break;
}
case SYM_UPVALUE: {
printf_buf(buf, "%p%t %c %s %s\n", level, sym->upvalue.var->var.var_name, "upvalue",
raviY_typename(sym->upvalue.var->value_type.type_code),
get_as_str(sym->upvalue.var->value_type.type_name));
break;
}
default:
assert(0);
}
}
static void print_symbol_name(membuff_t *buf, struct lua_symbol *sym) {
switch (sym->symbol_type) {
case SYM_LOCAL:
case SYM_GLOBAL: {
printf_buf(buf, "%t", sym->var.var_name);
break;
}
case SYM_UPVALUE: {
printf_buf(buf, "%t", sym->upvalue.var->var.var_name);
break;
}
default:
assert(0);
}
}
static void print_symbol_list(membuff_t *buf, struct lua_symbol_list *list, int level, const char *delimiter) {
struct lua_symbol *node;
bool is_first = true;
FOR_EACH_PTR(list, node) {
if (is_first)
is_first = false;
else if (delimiter)
printf_buf(buf, "%p%s\n", level, delimiter);
print_symbol(buf, node, level + 1);
}
END_FOR_EACH_PTR(node);
}
static void print_symbol_names(membuff_t *buf, struct lua_symbol_list *list) {
struct lua_symbol *node;
bool is_first = true;
FOR_EACH_PTR(list, node) {
if (is_first)
is_first = false;
else
printf_buf(buf, ", ");
print_symbol_name(buf, node);
}
END_FOR_EACH_PTR(node);
}
static const char *get_unary_opr_str(UnOpr op) {
switch (op) {
case OPR_NOT:
return "not";
case OPR_MINUS:
return "-";
case OPR_BNOT:
return "~";
case OPR_LEN:
return "#";
case OPR_TO_INTEGER:
return "@integer";
case OPR_TO_NUMBER:
return "@number";
case OPR_TO_INTARRAY:
return "@integer[]";
case OPR_TO_NUMARRAY:
return "@number[]";
case OPR_TO_TABLE:
return "@table";
case OPR_TO_CLOSURE:
return "@closure";
case OPR_TO_STRING:
return "@string";
case OPR_TO_TYPE:
return "@<usertype>";
default:
return "";
}
}
static const char *get_binary_opr_str(BinOpr op) {
switch (op) {
case OPR_ADD:
return "+";
case OPR_SUB:
return "-";
case OPR_MUL:
return "*";
case OPR_MOD:
return "%";
case OPR_POW:
return "^";
case OPR_DIV:
return "/";
case OPR_IDIV:
return "//";
case OPR_BAND:
return "&";
case OPR_BOR:
return "|";
case OPR_BXOR:
return "~";
case OPR_SHL:
return "<<";
case OPR_SHR:
return ">>";
case OPR_CONCAT:
return "..";
case OPR_NE:
return "~=";
case OPR_EQ:
return "==";
case OPR_LT:
return "<";
case OPR_LE:
return "<=";
case OPR_GT:
return ">";
case OPR_GE:
return ">=";
case OPR_AND:
return "and";
case OPR_OR:
return "or";
default:
return "";
}
}
void raviA_print_ast_node(membuff_t *buf, struct ast_node *node, int level) {
switch (node->type) {
case AST_FUNCTION_EXPR: {
if (node->function_expr.args) {
printf_buf(buf, "%pfunction(\n", level);
print_symbol_list(buf, node->function_expr.args, level + 1, ",");
printf_buf(buf, "%p)\n", level);
}
else {
printf_buf(buf, "%pfunction()\n", level);
}
if (node->function_expr.locals) {
printf_buf(buf, "%p%c ", level, "locals ");
print_symbol_names(buf, node->function_expr.locals);
printf_buf(buf, "\n");
}
if (node->function_expr.upvalues) {
printf_buf(buf, "%p%c ", level, "upvalues ");
print_symbol_names(buf, node->function_expr.upvalues);
printf_buf(buf, "\n");
}
print_statement_list(buf, node->function_expr.function_statement_list, level);
printf_buf(buf, "%pend\n", level);
break;
}
case AST_NONE:
break;
case AST_RETURN_STMT: {
printf_buf(buf, "%preturn\n", level);
print_ast_node_list(buf, node->return_stmt.expr_list, level + 1, ",");
break;
}
case AST_LOCAL_STMT: {
printf_buf(buf, "%plocal\n", level);
printf_buf(buf, "%p%c\n", level, "[symbols]");
print_symbol_list(buf, node->local_stmt.var_list, level + 1, ",");
if (node->local_stmt.expr_list) {
printf_buf(buf, "%p%c\n", level, "[expressions]");
print_ast_node_list(buf, node->local_stmt.expr_list, level + 1, ",");
}
break;
}
case AST_FUNCTION_STMT: {
raviA_print_ast_node(buf, node->function_stmt.name, level);
if (node->function_stmt.selectors) {
printf_buf(buf, "%p%c\n", level + 1, "[selectors]");
print_ast_node_list(buf, node->function_stmt.selectors, level + 2, NULL);
}
if (node->function_stmt.method_name) {
printf_buf(buf, "%p%c\n", level + 1, "[method name]");
raviA_print_ast_node(buf, node->function_stmt.method_name, level + 2);
}
printf_buf(buf, "%p=\n", level + 1);
raviA_print_ast_node(buf, node->function_stmt.function_expr, level + 2);
break;
}
case AST_LABEL_STMT: {
printf_buf(buf, "%p::%t::\n", level, node->label_stmt.symbol->label.label_name);
break;
}
case AST_GOTO_STMT: {
printf_buf(buf, "%pgoto %t\n", level, node->goto_stmt.name);
break;
}
case AST_DO_STMT: {
printf_buf(buf, "%pdo\n", level);
print_ast_node_list(buf, node->do_stmt.do_statement_list, level + 1, NULL);
printf_buf(buf, "%pend\n", level);
break;
}
case AST_EXPR_STMT: {
printf_buf(buf, "%p%c\n", level, "[expression statement start]");
if (node->expression_stmt.var_expr_list) {
printf_buf(buf, "%p%c\n", level + 1, "[var list start]");
print_ast_node_list(buf, node->expression_stmt.var_expr_list, level + 2, ",");
printf_buf(buf, "%p= %c\n", level + 1, "[var list end]");
}
printf_buf(buf, "%p%c\n", level + 1, "[expression list start]");
print_ast_node_list(buf, node->expression_stmt.expr_list, level + 2, ",");
printf_buf(buf, "%p%c\n", level + 1, "[expression list end]");
printf_buf(buf, "%p%c\n", level, "[expression statement end]");
break;
}
case AST_IF_STMT: {
struct ast_node *test_then_block;
bool is_first = true;
FOR_EACH_PTR(node->if_stmt.if_condition_list, test_then_block) {
if (is_first) {
is_first = false;
printf_buf(buf, "%pif\n", level);
}
else
printf_buf(buf, "%pelseif\n", level);
raviA_print_ast_node(buf, test_then_block->test_then_block.condition, level + 1);
printf_buf(buf, "%pthen\n", level);
print_ast_node_list(buf, test_then_block->test_then_block.test_then_statement_list, level + 1, NULL);
}
END_FOR_EACH_PTR(node);
if (node->if_stmt.else_block) {
printf_buf(buf, "%pelse\n", level);
print_ast_node_list(buf, node->if_stmt.else_statement_list, level + 1, NULL);
}
printf_buf(buf, "%pend\n", level);
break;
}
case AST_WHILE_STMT: {
printf_buf(buf, "%pwhile\n", level);
raviA_print_ast_node(buf, node->while_or_repeat_stmt.condition, level + 1);
printf_buf(buf, "%pdo\n", level);
print_ast_node_list(buf, node->while_or_repeat_stmt.loop_statement_list, level + 1, NULL);
printf_buf(buf, "%pend\n", level);
break;
}
case AST_REPEAT_STMT: {
printf_buf(buf, "%prepeat\n", level);
print_ast_node_list(buf, node->while_or_repeat_stmt.loop_statement_list, level + 1, NULL);
printf_buf(buf, "%puntil\n", level);
raviA_print_ast_node(buf, node->while_or_repeat_stmt.condition, level + 1);
printf_buf(buf, "%p%c\n", level, "[repeat end]");
break;
}
case AST_FORIN_STMT: {
printf_buf(buf, "%pfor\n", level);
print_symbol_list(buf, node->for_stmt.symbols, level + 1, ",");
printf_buf(buf, "%pin\n", level);
print_ast_node_list(buf, node->for_stmt.expr_list, level + 1, ",");
printf_buf(buf, "%pdo\n", level);
print_statement_list(buf, node->for_stmt.for_statement_list, level + 1);
printf_buf(buf, "%pend\n", level);
break;
}
case AST_FORNUM_STMT: {
printf_buf(buf, "%pfor\n", level);
print_symbol_list(buf, node->for_stmt.symbols, level + 1, NULL);
printf_buf(buf, "%p=\n", level);
print_ast_node_list(buf, node->for_stmt.expr_list, level + 1, ",");
printf_buf(buf, "%pdo\n", level);
print_statement_list(buf, node->for_stmt.for_statement_list, level + 1);
printf_buf(buf, "%pend\n", level);
break;
}
case AST_SUFFIXED_EXPR: {
printf_buf(buf, "%p%c %T\n", level, "[suffixed expr start]", &node->suffixed_expr.type);
printf_buf(buf, "%p%c %T\n", level+1, "[primary start]", &node->suffixed_expr.primary_expr->common_expr.type);
raviA_print_ast_node(buf, node->suffixed_expr.primary_expr, level + 2);
printf_buf(buf, "%p%c\n", level+1, "[primary end]");
if (node->suffixed_expr.suffix_list) {
printf_buf(buf, "%p%c\n", level+1, "[suffix list start]");
print_ast_node_list(buf, node->suffixed_expr.suffix_list, level + 2, NULL);
printf_buf(buf, "%p%c\n", level+1, "[suffix list end]");
}
printf_buf(buf, "%p%c\n", level, "[suffixed expr end]");
break;
}
case AST_FUNCTION_CALL_EXPR: {
printf_buf(buf, "%p%c %T\n", level, "[function call start]", &node->function_call_expr.type);
if (node->function_call_expr.method_name) {
printf_buf(buf, "%p: %t (\n", level + 1, node->function_call_expr.method_name);
}
else {
printf_buf(buf, "%p(\n", level + 1);
}
print_ast_node_list(buf, node->function_call_expr.arg_list, level + 2, ",");
printf_buf(buf, "%p)\n", level + 1);
printf_buf(buf, "%p%c\n", level, "[function call end]");
break;
}
case AST_SYMBOL_EXPR: {
print_symbol(buf, node->symbol_expr.var, level + 1);
break;
}
case AST_BINARY_EXPR: {
printf_buf(buf, "%p%c %T\n", level, "[binary expr start]", &node->binary_expr.type);
raviA_print_ast_node(buf, node->binary_expr.expr_left, level + 1);
printf_buf(buf, "%p%s\n", level, get_binary_opr_str(node->binary_expr.binary_op));
raviA_print_ast_node(buf, node->binary_expr.expr_right, level + 1);
printf_buf(buf, "%p%c\n", level, "[binary expr end]");
break;
}
case AST_UNARY_EXPR: {
printf_buf(buf, "%p%c %T\n", level, "[unary expr start]", &node->unary_expr.type);
printf_buf(buf, "%p%s\n", level, get_unary_opr_str(node->unary_expr.unary_op));
raviA_print_ast_node(buf, node->unary_expr.expr, level + 1);
printf_buf(buf, "%p%c\n", level, "[unary expr end]");
break;
}
case AST_LITERAL_EXPR: {
printf_buf(buf, "%p", level);
switch (node->literal_expr.type.type_code) {
case RAVI_TNIL:
printf_buf(buf, "nil");
break;
case RAVI_TBOOLEAN:
printf_buf(buf, "%b", node->literal_expr.u.i);
break;
case RAVI_TNUMINT:
printf_buf(buf, "%i", node->literal_expr.u.i);
break;
case RAVI_TNUMFLT:
printf_buf(buf, "%f", node->literal_expr.u.n);
break;
case RAVI_TSTRING:
printf_buf(buf, "'%t'", node->literal_expr.u.s);
break;
default:
assert(0);
}
printf_buf(buf, "\n");
break;
}
case AST_FIELD_SELECTOR_EXPR: {
printf_buf(buf, "%p%c %T\n", level, "[field selector start]", &node->index_expr.type);
printf_buf(buf, "%p.\n", level + 1);
raviA_print_ast_node(buf, node->index_expr.expr, level + 2);
printf_buf(buf, "%p%c\n", level, "[field selector end]");
break;
}
case AST_Y_INDEX_EXPR: {
printf_buf(buf, "%p%c %T\n", level, "[Y index start]", &node->index_expr.type);
printf_buf(buf, "%p[\n", level + 1);
raviA_print_ast_node(buf, node->index_expr.expr, level + 2);
printf_buf(buf, "%p]\n", level + 1);
printf_buf(buf, "%p%c\n", level, "[Y index end]");
break;
}
case AST_INDEXED_ASSIGN_EXPR: {
printf_buf(buf, "%p%c %T\n", level, "[indexed assign start]", &node->indexed_assign_expr.type);
if (node->indexed_assign_expr.index_expr) {
printf_buf(buf, "%p%c\n", level, "[index start]");
raviA_print_ast_node(buf, node->indexed_assign_expr.index_expr, level + 1);
printf_buf(buf, "%p%c\n", level, "[index end]");
}
printf_buf(buf, "%p%c\n", level, "[value start]");
raviA_print_ast_node(buf, node->indexed_assign_expr.value_expr, level + 1);
printf_buf(buf, "%p%c\n", level, "[value end]");
printf_buf(buf, "%p%c\n", level, "[indexed assign end]");
break;
}
case AST_TABLE_EXPR: {
printf_buf(buf, "%p{ %c %T\n", level, "[table constructor start]", &node->table_expr.type);
print_ast_node_list(buf, node->table_expr.expr_list, level + 1, ",");
printf_buf(buf, "%p} %c\n", level, "[table constructor end]");
break;
}
default:
printf_buf(buf, "%pUnsupported node type %d\n", level, node->type);
assert(0);
}
}

@ -0,0 +1,476 @@
/*
Copyright (C) 2018-2020 Dibyendu Majumdar
*/
#include <ravi_ast.h>
#include "ravi_ast.h"
/* Type checker - WIP */
static void typecheck_ast_node(struct ast_container *container, struct ast_node *function, struct ast_node *node);
/* Type checker - WIP */
static void typecheck_ast_list(struct ast_container *container, struct ast_node *function, struct ast_node_list *list) {
struct ast_node *node;
FOR_EACH_PTR(list, node) { typecheck_ast_node(container, function, node); }
END_FOR_EACH_PTR(node);
}
/* Type checker - WIP */
static void typecheck_unaryop(struct ast_container *container, struct ast_node *function, struct ast_node *node) {
UnOpr op = node->unary_expr.unary_op;
typecheck_ast_node(container, function, node->unary_expr.expr);
ravitype_t subexpr_type = node->unary_expr.expr->common_expr.type.type_code;
switch (op) {
case OPR_MINUS:
if (subexpr_type == RAVI_TNUMINT) {
set_type(node->unary_expr.type, RAVI_TNUMINT);
}
else if (subexpr_type == RAVI_TNUMFLT) {
set_type(node->unary_expr.type, RAVI_TNUMFLT);
}
break;
case OPR_LEN:
if (subexpr_type == RAVI_TARRAYINT || subexpr_type == RAVI_TARRAYFLT) {
set_type(node->unary_expr.type, RAVI_TNUMINT);
}
break;
case OPR_TO_INTEGER:
set_type(node->unary_expr.type, RAVI_TNUMINT);
break;
case OPR_TO_NUMBER:
set_type(node->unary_expr.type, RAVI_TNUMFLT);
break;
case OPR_TO_CLOSURE:
set_type(node->unary_expr.type, RAVI_TFUNCTION);
break;
case OPR_TO_STRING:
set_type(node->unary_expr.type, RAVI_TSTRING);
break;
case OPR_TO_INTARRAY:
set_type(node->unary_expr.type, RAVI_TARRAYINT);
if (node->unary_expr.expr->type == AST_TABLE_EXPR) {
set_type(node->unary_expr.expr->table_expr.type, RAVI_TARRAYINT);
}
break;
case OPR_TO_NUMARRAY:
set_type(node->unary_expr.type, RAVI_TARRAYFLT);
if (node->unary_expr.expr->type == AST_TABLE_EXPR) {
set_type(node->unary_expr.expr->table_expr.type, RAVI_TARRAYFLT);
}
break;
case OPR_TO_TABLE:
set_type(node->unary_expr.type, RAVI_TTABLE);
break;
case OPR_TO_TYPE:
lua_assert(node->unary_expr.type.type_name != NULL); // Should already be set by the parser
set_typecode(node->unary_expr.type, RAVI_TUSERDATA);
break;
default:
break;
}
}
/* Type checker - WIP */
static void typecheck_binaryop(struct ast_container *container, struct ast_node *function, struct ast_node *node) {
BinOpr op = node->binary_expr.binary_op;
struct ast_node *e1 = node->binary_expr.expr_left;
struct ast_node *e2 = node->binary_expr.expr_right;
typecheck_ast_node(container, function, e1);
typecheck_ast_node(container, function, e2);
switch (op) {
case OPR_ADD:
case OPR_SUB:
case OPR_MUL:
case OPR_DIV:
if (e1->common_expr.type.type_code == RAVI_TNUMFLT && e2->common_expr.type.type_code == RAVI_TNUMFLT)
set_typecode(node->binary_expr.type, RAVI_TNUMFLT);
else if (e1->common_expr.type.type_code == RAVI_TNUMFLT && e2->common_expr.type.type_code == RAVI_TNUMINT)
set_typecode(node->binary_expr.type, RAVI_TNUMFLT);
else if (e1->common_expr.type.type_code == RAVI_TNUMINT && e2->common_expr.type.type_code == RAVI_TNUMFLT)
set_typecode(node->binary_expr.type, RAVI_TNUMFLT);
else if (op != OPR_DIV && e1->common_expr.type.type_code == RAVI_TNUMINT &&
e2->common_expr.type.type_code == RAVI_TNUMINT)
set_typecode(node->binary_expr.type, RAVI_TNUMINT);
else if (op == OPR_DIV && e1->common_expr.type.type_code == RAVI_TNUMINT &&
e2->common_expr.type.type_code == RAVI_TNUMINT)
set_typecode(node->binary_expr.type, RAVI_TNUMFLT);
break;
case OPR_IDIV:
if (e1->common_expr.type.type_code == RAVI_TNUMINT && e2->common_expr.type.type_code == RAVI_TNUMINT)
set_typecode(node->binary_expr.type, RAVI_TNUMINT);
// FIXME missing cases
break;
case OPR_BAND:
case OPR_BOR:
case OPR_BXOR:
case OPR_SHL:
case OPR_SHR:
if ((e1->common_expr.type.type_code == RAVI_TNUMFLT || e1->common_expr.type.type_code == RAVI_TNUMINT) &&
(e2->common_expr.type.type_code == RAVI_TNUMFLT || e2->common_expr.type.type_code == RAVI_TNUMINT))
set_typecode(node->binary_expr.type, RAVI_TNUMINT);
break;
case OPR_EQ:
case OPR_NE:
case OPR_GE:
case OPR_GT:
case OPR_LE:
case OPR_LT:
/* This case is not handled in default parser - why? */
if ((e1->common_expr.type.type_code == RAVI_TNUMINT || e1->common_expr.type.type_code == RAVI_TNUMFLT ||
e1->common_expr.type.type_code == RAVI_TBOOLEAN) &&
(e2->common_expr.type.type_code == RAVI_TNUMFLT || e2->common_expr.type.type_code == RAVI_TNUMINT ||
e2->common_expr.type.type_code == RAVI_TBOOLEAN))
set_typecode(node->binary_expr.type, RAVI_TBOOLEAN);
break;
case OPR_POW:
if ((e1->common_expr.type.type_code == RAVI_TNUMFLT || e1->common_expr.type.type_code == RAVI_TNUMINT) &&
(e2->common_expr.type.type_code == RAVI_TNUMFLT || e2->common_expr.type.type_code == RAVI_TNUMINT))
set_typecode(node->binary_expr.type, RAVI_TNUMFLT);
break;
case OPR_MOD:
if (e1->common_expr.type.type_code == RAVI_TNUMINT && e2->common_expr.type.type_code == RAVI_TNUMINT)
set_typecode(node->binary_expr.type, RAVI_TNUMINT);
else if ((e1->common_expr.type.type_code == RAVI_TNUMINT && e2->common_expr.type.type_code == RAVI_TNUMFLT) ||
(e1->common_expr.type.type_code == RAVI_TNUMFLT && e2->common_expr.type.type_code == RAVI_TNUMINT))
set_typecode(node->binary_expr.type, RAVI_TNUMFLT);
break;
default:
set_typecode(node->binary_expr.type, RAVI_TANY);
break;
}
}
static bool is_unindexable_type(struct var_type *type) {
switch (type->type_code) {
case RAVI_TNUMFLT:
case RAVI_TNUMINT:
case RAVI_TBOOLEAN:
case RAVI_TNIL:
return true;
default:
return false;
}
}
/*
* Suffixed expression examples:
* f()[1]
* x[1][2]
* x.y[1]
*/
static void typecheck_suffixedexpr(struct ast_container *container, struct ast_node *function, struct ast_node *node) {
typecheck_ast_node(container, function, node->suffixed_expr.primary_expr);
struct ast_node *prev_node = node->suffixed_expr.primary_expr;
struct ast_node *this_node;
FOR_EACH_PTR(node->suffixed_expr.suffix_list, this_node) {
typecheck_ast_node(container, function, this_node);
if (this_node->type == AST_Y_INDEX_EXPR) {
if (prev_node->common_expr.type.type_code == RAVI_TARRAYFLT) {
if (this_node->index_expr.expr->common_expr.type.type_code == RAVI_TNUMINT) {
set_typecode(this_node->index_expr.type, RAVI_TNUMFLT);
}
else {
// FIXME Error
}
}
else if (prev_node->common_expr.type.type_code == RAVI_TARRAYINT) {
if (this_node->index_expr.expr->common_expr.type.type_code == RAVI_TNUMINT) {
set_typecode(this_node->index_expr.type, RAVI_TNUMINT);
}
else {
// FIXME Error
}
}
else if (is_unindexable_type(&prev_node->common_expr.type)) {
// FIXME Error
}
}
prev_node = this_node;
}
END_FOR_EACH_PTR(node);
copy_type(node->suffixed_expr.type, prev_node->common_expr.type);
}
static void insert_cast(struct ast_container *container, struct ast_node *expr, UnOpr opcode, ravitype_t target_type) {
/* convert the node to @integer node, the original content of node goes into the subexpr */
struct ast_node *copy_expr = dmrC_allocator_allocate(&container->ast_node_allocator, 0);
*copy_expr = *expr;
expr->type = AST_UNARY_EXPR;
expr->unary_expr.expr = copy_expr;
expr->unary_expr.unary_op = opcode;
set_typecode(expr->unary_expr.type, target_type);
}
static void typecheck_var_assignment(struct ast_container *container, struct var_type *var_type, struct ast_node *expr,
const char *var_name) {
if (var_type->type_code == RAVI_TANY)
// Any value can be assigned to type ANY
return;
struct var_type *expr_type = &expr->common_expr.type;
if (var_type->type_code == RAVI_TNUMINT) {
/* if the expr is of type number or # operator then insert @integer operator */
if (expr_type->type_code == RAVI_TNUMFLT ||
(expr->type == AST_UNARY_EXPR && expr->unary_expr.unary_op == OPR_LEN)) {
insert_cast(container, expr, OPR_TO_INTEGER, RAVI_TNUMINT);
}
else if (expr_type->type_code != RAVI_TNUMINT) {
fprintf(stderr, "Assignment to local symbol %s is not type compatible\n", var_name);
}
return;
}
if (var_type->type_code == RAVI_TNUMFLT) {
if (expr_type->type_code == RAVI_TNUMINT) {
/* cast to number */
insert_cast(container, expr, OPR_TO_NUMBER, RAVI_TNUMFLT);
}
else if (expr_type->type_code != RAVI_TNUMFLT) {
fprintf(stderr, "Assignment to local symbol %s is not type compatible\n", var_name);
}
return;
}
// all other types must strictly match
if (!is_type_same(*var_type, *expr_type)) { // We should probably check type convert-ability here
fprintf(stderr, "Assignment to local symbol %s is not type compatible\n", var_name);
}
}
static void typecheck_local_statement(struct ast_container *container, struct ast_node *function,
struct ast_node *node) {
// The local vars should already be annotated
// We need to typecheck the expressions to the right of =
// Then we need to ensure that the assignments are valid
// We can perhaps insert type assertions where we have a mismatch?
typecheck_ast_list(container, function, node->local_stmt.expr_list);
struct lua_symbol *var;
struct ast_node *expr;
PREPARE_PTR_LIST(node->local_stmt.var_list, var);
PREPARE_PTR_LIST(node->local_stmt.expr_list, expr);
for (;;) {
if (!var || !expr)
break;
struct var_type *var_type = &var->value_type;
const char *var_name = getstr(var->var.var_name);
typecheck_var_assignment(container, var_type, expr, var_name);
NEXT_PTR_LIST(var);
NEXT_PTR_LIST(expr);
}
}
static void typecheck_expr_statement(struct ast_container *container, struct ast_node *function,
struct ast_node *node) {
if (node->expression_stmt.var_expr_list)
typecheck_ast_list(container, function, node->expression_stmt.var_expr_list);
typecheck_ast_list(container, function, node->expression_stmt.expr_list);
if (!node->expression_stmt.var_expr_list)
return;
struct ast_node *var;
struct ast_node *expr;
PREPARE_PTR_LIST(node->expression_stmt.var_expr_list, var);
PREPARE_PTR_LIST(node->local_stmt.expr_list, expr);
for (;;) {
if (!var || !expr)
break;
struct var_type *var_type = &var->common_expr.type;
const char *var_name = ""; // FIXME how do we get this?
typecheck_var_assignment(container, var_type, expr, var_name);
NEXT_PTR_LIST(var);
NEXT_PTR_LIST(expr);
}
}
static void typecheck_for_in_statment(struct ast_container *container, struct ast_node *function,
struct ast_node *node) {
typecheck_ast_list(container, function, node->for_stmt.expr_list);
typecheck_ast_list(container, function, node->for_stmt.for_statement_list);
}
static void typecheck_for_num_statment(struct ast_container *container, struct ast_node *function,
struct ast_node *node) {
typecheck_ast_list(container, function, node->for_stmt.expr_list);
struct ast_node *expr;
enum { I = 1, F = 2, A = 4 }; /* bits representing integer, number, any */
int index_type = 0;
FOR_EACH_PTR(node->for_stmt.expr_list, expr) {
switch (expr->common_expr.type.type_code) {
case RAVI_TNUMFLT:
index_type |= F;
break;
case RAVI_TNUMINT:
index_type |= I;
break;
default:
index_type |= A;
break;
}
if ((index_type & A) != 0)
break;
}
END_FOR_EACH_PTR(expr);
if ((index_type & A) == 0) { /* not any */
/* for I+F we use F */
ravitype_t symbol_type = index_type == I ? RAVI_TNUMINT : RAVI_TNUMFLT;
struct lua_symbol_list *symbols = node->for_stmt.symbols;
struct lua_symbol *sym;
/* actually there will be only index variable */
FOR_EACH_PTR(symbols, sym) {
if (sym->symbol_type == SYM_LOCAL) {
set_typecode(sym->value_type, symbol_type);
}
else {
assert(0); /* cannot happen */
}
}
END_FOR_EACH_PTR(sym);
}
typecheck_ast_list(container, function, node->for_stmt.for_statement_list);
}
static void typecheck_if_statement(struct ast_container *container, struct ast_node *function, struct ast_node *node) {
struct ast_node *test_then_block;
FOR_EACH_PTR(node->if_stmt.if_condition_list, test_then_block) {
typecheck_ast_node(container, function, test_then_block->test_then_block.condition);
typecheck_ast_list(container, function, test_then_block->test_then_block.test_then_statement_list);
}
END_FOR_EACH_PTR(node);
if (node->if_stmt.else_statement_list) {
typecheck_ast_list(container, function, node->if_stmt.else_statement_list);
}
}
static void typecheck_while_or_repeat_statement(struct ast_container *container, struct ast_node *function,
struct ast_node *node) {
typecheck_ast_node(container, function, node->while_or_repeat_stmt.condition);
if (node->while_or_repeat_stmt.loop_statement_list) {
typecheck_ast_list(container, function, node->while_or_repeat_stmt.loop_statement_list);
}
}
/* Type checker - WIP */
static void typecheck_ast_node(struct ast_container *container, struct ast_node *function, struct ast_node *node) {
switch (node->type) {
case AST_FUNCTION_EXPR: {
typecheck_ast_list(container, function, node->function_expr.function_statement_list);
break;
}
case AST_NONE: {
break;
}
case AST_RETURN_STMT: {
typecheck_ast_list(container, function, node->return_stmt.expr_list);
break;
}
case AST_LOCAL_STMT: {
typecheck_local_statement(container, function, node);
break;
}
case AST_FUNCTION_STMT: {
typecheck_ast_node(container, function, node->function_stmt.function_expr);
break;
}
case AST_LABEL_STMT: {
break;
}
case AST_GOTO_STMT: {
break;
}
case AST_DO_STMT: {
break;
}
case AST_EXPR_STMT: {
typecheck_expr_statement(container, function, node);
break;
}
case AST_IF_STMT: {
typecheck_if_statement(container, function, node);
break;
}
case AST_WHILE_STMT:
case AST_REPEAT_STMT: {
typecheck_while_or_repeat_statement(container, function, node);
break;
}
case AST_FORIN_STMT: {
typecheck_for_in_statment(container, function, node);
break;
}
case AST_FORNUM_STMT: {
typecheck_for_num_statment(container, function, node);
break;
}
case AST_SUFFIXED_EXPR: {
typecheck_suffixedexpr(container, function, node);
break;
}
case AST_FUNCTION_CALL_EXPR: {
if (node->function_call_expr.method_name) {
}
else {
}
typecheck_ast_list(container, function, node->function_call_expr.arg_list);
break;
}
case AST_SYMBOL_EXPR: {
/* symbol type should have been set when symbol was created */
copy_type(node->symbol_expr.type, node->symbol_expr.var->value_type);
break;
}
case AST_BINARY_EXPR: {
typecheck_binaryop(container, function, node);
break;
}
case AST_UNARY_EXPR: {
typecheck_unaryop(container, function, node);
break;
}
case AST_LITERAL_EXPR: {
/* type set during parsing */
break;
}
case AST_FIELD_SELECTOR_EXPR: {
typecheck_ast_node(container, function, node->index_expr.expr);
break;
}
case AST_Y_INDEX_EXPR: {
typecheck_ast_node(container, function, node->index_expr.expr);
break;
}
case AST_INDEXED_ASSIGN_EXPR: {
if (node->indexed_assign_expr.index_expr) {
typecheck_ast_node(container, function, node->indexed_assign_expr.index_expr);
}
typecheck_ast_node(container, function, node->indexed_assign_expr.value_expr);
copy_type(node->indexed_assign_expr.type, node->indexed_assign_expr.value_expr->common_expr.type);
break;
}
case AST_TABLE_EXPR: {
typecheck_ast_list(container, function, node->table_expr.expr_list);
break;
}
default:
assert(0);
}
}
/* Type checker - WIP */
static void typecheck_function(struct ast_container *container, struct ast_node *func) {
typecheck_ast_list(container, func, func->function_expr.function_statement_list);
}
/* Type checker - WIP */
void raviA_ast_typecheck(struct ast_container *container) {
struct ast_node *main_function = container->main_function;
typecheck_function(container, main_function);
}

File diff suppressed because it is too large Load Diff

@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
* Copyright (C) 2015-2020 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the

@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
* Copyright (C) 2015-2020 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -676,7 +676,11 @@ void RaviCodeGenerator::emit_MOD(RaviFunctionDef *def, int A, int B, int C,
lhs = emit_load_local_n(def, nb);
rhs = emit_load_local_n(def, nc);
#if LLVM_VERSION_MAJOR >= 9
llvm::Value *fmod_result = CreateCall2(def->builder, def->fmodFunc.getCallee(), lhs, rhs);
#else
llvm::Value *fmod_result = CreateCall2(def->builder, def->fmodFunc, lhs, rhs);
#endif
// if ((m)*(b) < 0) (m) += (b);
llvm::Value *mb = def->builder->CreateFMul(fmod_result, rhs);
@ -1002,7 +1006,11 @@ void RaviCodeGenerator::emit_POW(RaviFunctionDef *def, int A, int B, int C,
llvm::Instruction *lhs = emit_load_local_n(def, nb);
llvm::Instruction *rhs = emit_load_local_n(def, nc);
#if LLVM_VERSION_MAJOR >= 9
llvm::Value *pow_result = CreateCall2(def->builder, def->powFunc.getCallee(), lhs, rhs);
#else
llvm::Value *pow_result = CreateCall2(def->builder, def->powFunc, lhs, rhs);
#endif
emit_store_reg_n_withtype(def, pow_result, ra);

@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
* Copyright (C) 2015-2020 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -44,15 +44,17 @@ void RaviCodeGenerator::emit_JMP(RaviFunctionDef *def, int A, int sBx, int pc) {
def->builder->SetInsertPoint(jmp_block);
}
emit_debug_trace(def, OP_JMP, pc);
bool traced = emit_debug_trace(def, OP_JMP, pc);
// if (a > 0) luaF_close(L, ci->u.l.base + a - 1);
if (A > 0) {
emit_load_base(def);
// base + a - 1
llvm::Value *val = emit_gep_register(def, A - 1);
if (!traced)
emit_update_savedpc(def, pc);
// Call luaF_close
CreateCall2(def->builder, def->luaF_closeF, def->L, val);
CreateCall3(def->builder, def->luaF_closeF, def->L, val, def->types->kInt[LUA_OK]);
}
// Do the actual jump
@ -170,4 +172,12 @@ void RaviCodeGenerator::emit_CALL(RaviFunctionDef *def, int A, int B, int C,
def->f->getBasicBlockList().push_back(end_block);
def->builder->SetInsertPoint(end_block);
}
void RaviCodeGenerator::emit_DEFER(RaviFunctionDef *def, int A, int pc) {
emit_debug_trace(def, OP_RAVI_DEFER, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
CreateCall2(def->builder, def->raviV_op_deferF, def->L, ra);
}
}

@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
* Copyright (C) 2015-2020 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -980,34 +980,59 @@ void RaviCodeGenerator::emit_raise_lua_error(RaviFunctionDef *def,
}
void RaviCodeGenerator::debug_printf(RaviFunctionDef *def, const char *str) {
#if LLVM_VERSION_MAJOR >= 9
CreateCall1(def->builder, def->printfFunc.getCallee(),
def->builder->CreateGlobalStringPtr(str));
#else
CreateCall1(def->builder, def->printfFunc,
def->builder->CreateGlobalStringPtr(str));
#endif
}
void RaviCodeGenerator::debug_printf1(RaviFunctionDef *def, const char *str,
llvm::Value *arg1) {
CreateCall2(def->builder, def->printfFunc,
#if LLVM_VERSION_MAJOR >= 9
CreateCall2(def->builder, def->printfFunc.getCallee(),
def->builder->CreateGlobalStringPtr(str), arg1);
#else
CreateCall2(def->builder, def->printfFunc,
def->builder->CreateGlobalStringPtr(str), arg1);
#endif
}
void RaviCodeGenerator::debug_printf2(RaviFunctionDef *def, const char *str,
llvm::Value *arg1, llvm::Value *arg2) {
CreateCall3(def->builder, def->printfFunc,
#if LLVM_VERSION_MAJOR >= 9
CreateCall3(def->builder, def->printfFunc.getCallee(),
def->builder->CreateGlobalStringPtr(str), arg1, arg2);
#else
CreateCall3(def->builder, def->printfFunc,
def->builder->CreateGlobalStringPtr(str), arg1, arg2);
#endif
}
void RaviCodeGenerator::debug_printf3(RaviFunctionDef *def, const char *str,
llvm::Value *arg1, llvm::Value *arg2,
llvm::Value *arg3) {
CreateCall4(def->builder, def->printfFunc,
#if LLVM_VERSION_MAJOR >= 9
CreateCall4(def->builder, def->printfFunc.getCallee(),
def->builder->CreateGlobalStringPtr(str), arg1, arg2, arg3);
#else
CreateCall4(def->builder, def->printfFunc,
def->builder->CreateGlobalStringPtr(str), arg1, arg2, arg3);
#endif
}
void RaviCodeGenerator::debug_printf4(RaviFunctionDef *def, const char *str,
llvm::Value *arg1, llvm::Value *arg2,
llvm::Value *arg3, llvm::Value *arg4) {
CreateCall5(def->builder, def->printfFunc,
#if LLVM_VERSION_MAJOR >= 9
CreateCall5(def->builder, def->printfFunc.getCallee(),
def->builder->CreateGlobalStringPtr(str), arg1, arg2, arg3, arg4);
#else
CreateCall5(def->builder, def->printfFunc,
def->builder->CreateGlobalStringPtr(str), arg1, arg2, arg3, arg4);
#endif
}
void RaviCodeGenerator::emit_extern_declarations(RaviFunctionDef *def) {
@ -1177,6 +1202,9 @@ void RaviCodeGenerator::emit_extern_declarations(RaviFunctionDef *def) {
def->raviV_op_totypeF = def->raviF->addExternFunction(
def->types->raviV_op_totypeT, reinterpret_cast<void *>(&raviV_op_totype),
"raviV_op_totype");
def->raviV_op_deferF = def->raviF->addExternFunction(
def->types->raviV_op_deferT, reinterpret_cast<void *>(&raviV_op_defer),
"raviV_op_defer");
def->ravi_dump_valueF = def->raviF->addExternFunction(
def->types->ravi_dump_valueT, reinterpret_cast<void *>(&ravi_dump_value),
@ -1304,7 +1332,7 @@ llvm::Value *RaviCodeGenerator::emit_gep_upval_v(RaviFunctionDef *def,
// Get &upval->value -> result is TValue *
llvm::Value *RaviCodeGenerator::emit_gep_upval_value(
RaviFunctionDef *def, llvm::Instruction *pupval) {
return emit_gep(def, "value", pupval, 0, 2);
return emit_gep(def, "value", pupval, 0, 3);
}
// Alternative code generator uses dmrC based C front-end
@ -1989,7 +2017,9 @@ bool RaviCodeGenerator::compile(lua_State *L, Proto *p,
int B = GETARG_B(i);
emit_UNM(def, A, B, pc);
} break;
case OP_RAVI_DEFER: {
emit_DEFER(def, A, pc);
} break;
default: {
fprintf(stderr, "Unexpected bytecode %d\n", op);
abort();

@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
* Copyright (C) 2015-2020 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -131,9 +131,10 @@ void RaviCodeGenerator::emit_EQ(RaviFunctionDef *def, int A, int B, int C,
// base + a - 1
llvm::Value *val = emit_gep_register(def, jA - 1);
if (!traced)
emit_update_savedpc(def, pc);
// Call luaF_close
CreateCall2(def->builder, def->luaF_closeF, def->L, val);
CreateCall3(def->builder, def->luaF_closeF, def->L, val, def->types->kInt[LUA_OK]);
}
// Do the jump
def->builder->CreateBr(def->jmp_targets[j].jmp1);
@ -211,7 +212,7 @@ void RaviCodeGenerator::emit_TEST(RaviFunctionDef *def, int A, int B, int C,
// donextjump(ci);
// } break;
emit_debug_trace(def, OP_TEST, pc);
bool traced = emit_debug_trace(def, OP_TEST, pc);
// Load pointer to base
emit_load_base(def);
@ -237,9 +238,10 @@ void RaviCodeGenerator::emit_TEST(RaviFunctionDef *def, int A, int B, int C,
// base + a - 1
llvm::Value *val = emit_gep_register(def, jA - 1);
if (!traced)
emit_update_savedpc(def, pc);
// Call luaF_close
CreateCall2(def->builder, def->luaF_closeF, def->L, val);
CreateCall3(def->builder, def->luaF_closeF, def->L, val, def->types->kInt[LUA_OK]);
}
// Do the jump
def->builder->CreateBr(def->jmp_targets[j].jmp1);
@ -279,7 +281,7 @@ void RaviCodeGenerator::emit_TESTSET(RaviFunctionDef *def, int A, int B, int C,
// }
// } break;
emit_debug_trace(def, OP_TESTSET, pc);
bool traced = emit_debug_trace(def, OP_TESTSET, pc);
// Load pointer to base
emit_load_base(def);
@ -309,9 +311,10 @@ void RaviCodeGenerator::emit_TESTSET(RaviFunctionDef *def, int A, int B, int C,
// base + a - 1
llvm::Value *val = emit_gep_register(def, jA - 1);
if (!traced)
emit_update_savedpc(def, pc);
// Call luaF_close
CreateCall2(def->builder, def->luaF_closeF, def->L, val);
CreateCall3(def->builder, def->luaF_closeF, def->L, val, def->types->kInt[LUA_OK]);
}
// Do the jump
def->builder->CreateBr(def->jmp_targets[j].jmp1);

@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
* Copyright (C) 2015-2020 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the

@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
* Copyright (C) 2015-2020 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the

@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
* Copyright (C) 2015-2020 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -222,8 +222,11 @@ RaviJITState::RaviJITState()
DL = llvm::make_unique<llvm::DataLayout>(std::move(dataLayout));
Mangle = llvm::make_unique<llvm::orc::MangleAndInterner>(*ES, *this->DL);
Ctx = llvm::make_unique<llvm::orc::ThreadSafeContext>(llvm::make_unique<llvm::LLVMContext>());
ES->getMainJITDylib().setGenerator(cantFail(llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(*DL)));
#if LLVM_VERSION_MAJOR >= 9
ES->getMainJITDylib().setGenerator(llvm::cantFail(llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(DL->getGlobalPrefix())));
#else
ES->getMainJITDylib().setGenerator(llvm::cantFail(llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(*DL)));
#endif
types_ = llvm::make_unique<LuaLLVMTypes>(*Ctx->getContext());
#else

@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
* Copyright (C) 2015-2020 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the

@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
* Copyright (C) 2015-2020 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the

@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
* Copyright (C) 2015-2020 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the

@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
* Copyright (C) 2015-2020 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -54,13 +54,7 @@ void RaviCodeGenerator::emit_RETURN(RaviFunctionDef *def, int A, int B,
def->builder->SetInsertPoint(return_block);
}
emit_debug_trace(def, OP_RETURN, pc);
// Load pointer to base
emit_load_base(def);
// Get pointer to register A
llvm::Value *ra_ptr = emit_gep_register(def, A);
bool traced = emit_debug_trace(def, OP_RETURN, pc);
// if (cl->p->sizep > 0) luaF_close(L, base);
// Get pointer to Proto->sizep
@ -70,19 +64,28 @@ void RaviCodeGenerator::emit_RETURN(RaviFunctionDef *def, int A, int B,
llvm::Value *psize_gt_0 =
def->builder->CreateICmpSGT(psize, def->types->kInt[0]);
llvm::BasicBlock *then_block = llvm::BasicBlock::Create(
def->jitState->context(), "OP_RETURN_if_close", def->f);
def->jitState->context(), "OP_RETURN_if_closing", def->f);
llvm::BasicBlock *else_block = llvm::BasicBlock::Create(
def->jitState->context(), "OP_RETURN_else_close");
def->jitState->context(), "OP_RETURN_else_closing");
def->builder->CreateCondBr(psize_gt_0, then_block, else_block);
def->builder->SetInsertPoint(then_block);
// Load pointer to base
emit_load_base(def);
// Get pointer to register A
llvm::Value *ra_ptr = emit_gep_register(def, A);
if (!traced)
emit_update_savedpc(def, pc);
// Call luaF_close
CreateCall2(def->builder, def->luaF_closeF, def->L, def->base_ptr);
CreateCall3(def->builder, def->luaF_closeF, def->L, def->base_ptr, def->types->kInt[LUA_OK]);
def->builder->CreateBr(else_block);
def->f->getBasicBlockList().push_back(else_block);
def->builder->SetInsertPoint(else_block);
emit_load_base(def); // As luaF_close() may have changed the stack
ra_ptr = emit_gep_register(def, A); // load RA
//* b = luaD_poscall(L, ra, (b != 0 ? b - 1 : L->top - ra));
llvm::Value *nresults = NULL;
if (B != 0)

@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
* Copyright (C) 2015-2020 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the

@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
* Copyright (C) 2015-2020 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the

@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (C) 2015 Dibyendu Majumdar
* Copyright (C) 2015-2020 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -694,7 +694,8 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
// struct UpVal {
// struct TValue *v; /* points to stack or to its own value */
// unsigned long long refcount; /* reference counter */
// unsigned int refcount; /* reference counter */
// unsigned int flags; /* Used to mark deferred values */
// union {
// struct { /* (when open) */
// struct UpVal *next; /* linked list */
@ -705,7 +706,8 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
//};
elements.clear();
elements.push_back(pTValueT);
elements.push_back(C_size_t);
elements.push_back(C_intT);
elements.push_back(C_intT);
elements.push_back(TValueT);
UpValT->setBody(elements);
@ -745,17 +747,22 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
elements.push_back(plua_StateT);
luaV_executeT = llvm::FunctionType::get(C_intT, elements, false);
// void luaF_close (lua_State *L, StkId level)
// int luaF_close (lua_State *L, StkId level, int status)
elements.clear();
elements.push_back(plua_StateT);
elements.push_back(StkIdT);
elements.push_back(C_intT);
luaF_closeT =
llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false);
llvm::FunctionType::get(C_intT, elements, false);
// int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2)
elements.clear();
elements.push_back(plua_StateT);
elements.push_back(pTValueT);
// void raviV_op_defer(lua_State *L, TValue *ra);
raviV_op_deferT = llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false);
elements.push_back(pTValueT);
luaV_equalobjT = llvm::FunctionType::get(C_intT, elements, false);
@ -1256,10 +1263,12 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
nodes.clear();
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_pointerT, 0));
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_longlongT, 8));
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_intT, 4));
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_intT, 4));
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_TValueT, 16));
tbaa_UpValT = mdbuilder.createTBAAStructTypeNode("UpVal", nodes);
tbaa_UpVal_vT =
mdbuilder.createTBAAStructTagNode(tbaa_UpValT, tbaa_pointerT, 0);
// RaviArray

@ -1,3 +1,7 @@
/*
Copyright (C) 2018-2020 Dibyendu Majumdar
*/
#include <ravi_membuf.h>
#include <assert.h>

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

Loading…
Cancel
Save