diff --git a/.travis.yml b/.travis.yml index c54efea..88e74aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ os: - linux arch: - amd64 + - arm64 compiler: - gcc cache: ccache @@ -10,16 +11,9 @@ dist: bionic addons: apt: packages: - - g++ - gcc - ccache -install: - - curl https://releases.llvm.org/6.0.1/clang+llvm-6.0.1-x86_64-linux-gnu-ubuntu-16.04.tar.xz | tar -xJf - script: - - mkdir $TRAVIS_BUILD_DIR/build - - cd $TRAVIS_BUILD_DIR/build && 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/tests && sh ./run_tests.sh $TRAVIS_BUILD_DIR/build/ravi - mkdir $TRAVIS_BUILD_DIR/buildmir - cd $TRAVIS_BUILD_DIR/buildmir && cmake -DCMAKE_BUILD_TYPE=Debug -DLTESTS=ON -DMIR_JIT=ON -G "Unix Makefiles" .. - cd $TRAVIS_BUILD_DIR/buildmir && make diff --git a/CMakeLists.txt b/CMakeLists.txt index ee7506a..aeb5fbf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,12 +1,9 @@ cmake_minimum_required(VERSION 3.12) -project(Ravi VERSION 1.0.4 LANGUAGES C CXX) +project(Ravi VERSION 1.0.4 LANGUAGES C) -# By default on platforms where MIR is supported (right now Linux X86_64) -# MIR JIT backend is automatically enabled. To disable user must specify +# By default MIR JIT backend is automatically enabled. To disable user must specify # NO_JIT=ON -# LLVM has to be explicitly specified using LLVM_JIT=ON -option(LLVM_JIT "Controls whether LLVM JIT compilation will be enabled, default is OFF" OFF) option(NO_JIT "Controls whether JIT should be disabled, 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) @@ -16,14 +13,12 @@ option(RAVICOMP "Controls whether to link in RaviComp" OFF) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") -# By default on non-Windows platforms we enable MIR JIT -if (NOT LLVM_JIT - AND NOT NO_JIT) +# By we enable MIR JIT +if (NOT NO_JIT) set(MIR_JIT ON) endif () if (MIR_JIT) - set(LLVM_JIT OFF) set(STATIC_BUILD OFF) # Because we need to expose the symbols in the library endif () @@ -51,12 +46,6 @@ set(LUA_CORE_SRCS src/lapi.c src/lcode.c src/lctype.c src/ldebug.c src/ldo.c src 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) set(LUA_HEADERS include/lua.h include/luaconf.h include/lualib.h include/lauxlib.h) -# LLVM code gen -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) set(MIR_HEADERS mir/mir.h mir/mir-gen.h mir/mir-varr.h mir/mir-dlist.h mir/mir-htab.h mir/mir-hash.h mir/mir-bitmap.h) set(MIR_SRCS mir/mir.c mir/mir-gen.c) @@ -89,56 +78,26 @@ if (ASAN) 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}") - - message(STATUS "LLVM Definitions ${LLVM_DEFINITIONS}") - message(STATUS "LLVMJIT enabled") - - set(JIT_SRCS ${LLVM_JIT_SRCS}) +if (MIR_JIT) + message(STATUS "MIRJIT enabled") + set(JIT_SRCS ${MIR_SRCS} ${C2MIR_SRCS} ${MIR_JIT_SRCS}) + set(ALL_MIR_SRCS ${MIR_SRCS} ${C2MIR_SRCS}) if (NOT MSVC) - set_source_files_properties(${LLVM_JIT_SRCS} PROPERTIES - COMPILE_FLAGS "-fno-rtti -fno-exceptions ${LLVM_DEFINITIONS}") + set_source_files_properties(${ALL_MIR_SRCS} PROPERTIES + COMPILE_FLAGS "-fsigned-char") endif () - set_property( - SOURCE ${LLVM_JIT_SRCS} + set_property(SOURCE ${MIR_SRCS} ${C2MIR_SRCS} ${MIR_JIT_SRCS} APPEND - PROPERTY INCLUDE_DIRECTORIES ${LLVM_INCLUDE_DIRS} - ) - # FIXME get rid of this dependency - set_property( - SOURCE ${LUA_CMD_SRCS} + PROPERTY INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/mir;${CMAKE_SOURCE_DIR}/mir/c2mir") + set_property(SOURCE ${MIR_SRCS} ${C2MIR_SRCS} ${MIR_JIT_SRCS} APPEND - PROPERTY INCLUDE_DIRECTORIES ${LLVM_INCLUDE_DIRS}) - + PROPERTY COMPILE_DEFINITIONS "MIR_NO_IO=0;MIR_NO_SCAN=1;MIR_NO_INTERP=1") if ($ENV{CLION_IDE}) # CLion seems unable to handle include paths set on sources - include_directories(${LLVM_INCLUDE_DIRS}) + include_directories("${CMAKE_SOURCE_DIR}/mir;${CMAKE_SOURCE_DIR}/mir/c2mir") endif () else () - if (MIR_JIT) - message(STATUS "MIRJIT enabled") - set(JIT_SRCS ${MIR_SRCS} ${C2MIR_SRCS} ${MIR_JIT_SRCS}) - set(ALL_MIR_SRCS ${MIR_SRCS} ${C2MIR_SRCS}) - if (NOT MSVC) - set_source_files_properties(${ALL_MIR_SRCS} PROPERTIES - COMPILE_FLAGS "-fsigned-char") - endif () - set_property(SOURCE ${MIR_SRCS} ${C2MIR_SRCS} ${MIR_JIT_SRCS} - APPEND - PROPERTY INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/mir;${CMAKE_SOURCE_DIR}/mir/c2mir") - set_property(SOURCE ${MIR_SRCS} ${C2MIR_SRCS} ${MIR_JIT_SRCS} - APPEND - PROPERTY COMPILE_DEFINITIONS "MIR_NO_IO=0;MIR_NO_SCAN=1;MIR_NO_INTERP=1") - if ($ENV{CLION_IDE}) - # CLion seems unable to handle include paths set on sources - include_directories("${CMAKE_SOURCE_DIR}/mir;${CMAKE_SOURCE_DIR}/mir/c2mir") - endif () - else () - set(JIT_SRCS ${NO_JIT_SRCS}) - endif () + set(JIT_SRCS ${NO_JIT_SRCS}) endif () if (RAVICOMP) @@ -177,64 +136,6 @@ elseif (NOT WIN32) set(EXTRA_LIBRARIES m dl readline) endif () -# Enable minimal required LLVM components so that the -# the size of the resulting binary is manageable -if (LLVM_JIT) - if (${LLVM_PACKAGE_VERSION} VERSION_LESS "3.8") - set(LLVM_EXTRA_LIBS ipa) - endif () - if (NOT ${LLVM_PACKAGE_VERSION} VERSION_LESS "5.0.0") - set(LLVM_EXTRA_LIBS orcjit) - endif () - message(STATUS "SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR}") - if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") - set(LLVM_LIBS_PROCESSOR - 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 () - llvm_map_components_to_libnames(LLVM_LIBS - Analysis - AsmParser - AsmPrinter - BitReader - Core - CodeGen - ExecutionEngine - InstCombine - ${LLVM_EXTRA_LIBS} - ipo - MC - MCJIT - MCParser - Object - RuntimeDyld - ScalarOpts - Support - Target - TransformUtils - ${LLVM_LIBS_PROCESSOR} - ) - message(STATUS "LLVM_LIBS ${LLVM_LIBS}") -endif () - - set(LIBRAVI_NAME libravi) #Main library @@ -244,7 +145,7 @@ add_library(${LIBRAVI_NAME} ${LIBRAVI_BUILD_TYPE} ${LUA_CORE_SRCS} ${JIT_SRCS} ${ADDON_SRCS}) -target_link_libraries(${LIBRAVI_NAME} ${EXTRA_LIBRARIES} ${LLVM_LIBS} ${MIRJIT_LIBRARIES} ${RAVICOMP_LIBRARIES}) +target_link_libraries(${LIBRAVI_NAME} ${EXTRA_LIBRARIES} ${MIRJIT_LIBRARIES} ${RAVICOMP_LIBRARIES}) # Main Ravi executable add_executable(ravi ${LUA_CMD_SRCS}) @@ -281,13 +182,7 @@ if (NOT LTESTS) PROPERTY COMPILE_DEFINITIONS NO_LUA_DEBUG) set(NO_LUA_DEBUG 1) endif () -if (LLVM_JIT) - set_property( - TARGET ${LIBRAVI_NAME} ravi - APPEND - PROPERTY COMPILE_DEFINITIONS "USE_LLVM=1") - set(USE_LLVM 1) -elseif (MIR_JIT) +if (MIR_JIT) set_property( TARGET ${LIBRAVI_NAME} ravi APPEND @@ -325,8 +220,6 @@ elseif (UNIX) APPEND PROPERTY COMPILE_DEFINITIONS "LUA_USE_LINUX=1") endif () -set_property(TARGET ${LIBRAVI_NAME} PROPERTY CXX_STANDARD 14) -set_property(TARGET ${LIBRAVI_NAME} PROPERTY CXX_EXTENSIONS OFF) include(GNUInstallDirs) configure_file(ravi-config.h.in ravi-config.h @ONLY) diff --git a/README.rst b/README.rst index 39c1681..9fd15ec 100644 --- a/README.rst +++ b/README.rst @@ -5,7 +5,7 @@ Ravi Programming Language :target: https://travis-ci.org/dibyendumajumdar/ravi Ravi is a dialect of `Lua `_ with limited optional static typing and -features `MIR `_ and `LLVM `_ powered JIT compilers. +features `MIR `_ powered JIT compilers. The name Ravi comes from the Sanskrit word for the Sun. Interestingly a precursor to Lua was `Sol `_ which had support for static types; Sol means the Sun in Portugese. @@ -35,8 +35,7 @@ Features * Compatibility with Lua 5.3 (see Compatibility section below) * Generational GC from Lua 5.4 * ``defer`` statement for releasing resources -* Compact JIT backend `MIR `_; only Linux and x86-64 supported for now. -* `LLVM `_ supported as alternative JIT backend. +* Compact JIT backend `MIR `_. * A `distribution with batteries `_. * A `Visual Studio Code debugger extension `_ - interpreted mode debugger. @@ -44,7 +43,6 @@ Documentation ============= * For the Lua extensions in Ravi see the `Reference Manual `_. * `MIR JIT Build instructions `_. -* `LLVM JIT Build instructions `_. * Also see `Ravi Documentation `_. * and the slides I presented at the `Lua 2015 Workshop `_. @@ -99,6 +97,7 @@ When JIT compilation is enabled there are following additional constraints: * Ravi will only execute JITed code from the main Lua thread; any secondary threads (coroutines) execute in interpreter mode. * In JITed code tailcalls are implemented as regular calls so unlike the interpreter VM which supports infinite tail recursion JIT compiled code only supports tail recursion to a depth of about 110 (issue #17) +* Debug api and hooks are not supported in JIT mode History ======= @@ -115,11 +114,13 @@ History - Created `Ravi with batteries `_. * 2019 - New language feature - `defer` statement - - New JIT backend `MIR `_. - -* 2020 (Plan) - - `New optimizing byte code generator based on new parser / type checker `_ + - New JIT backend `MIR `_. +* 2020 + - `New parser / type checker / compiler `_ - Generational GC back-ported from Lua 5.4 + - Support for `LLVM backend `_ archived +* 2021 (Plan) + - Integrated AOT and JIT compilation support - Ravi 1.0 release License diff --git a/build-utils/README.rst b/build-utils/README.rst index 794cd60..e09c1b8 100644 --- a/build-utils/README.rst +++ b/build-utils/README.rst @@ -5,4 +5,4 @@ The scripts here are unsupported - these are just my personal build scripts. -The unix LLVM debug builds enable 'ltests' and address sanitizer. +The debug builds enable 'ltests' and address sanitizer. diff --git a/build-utils/buildllvm10.sh b/build-utils/buildllvm10.sh deleted file mode 100644 index dbbcbfa..0000000 --- a/build-utils/buildllvm10.sh +++ /dev/null @@ -1,16 +0,0 @@ -# Run this on LLVM 10 source dir - -mkdir build -cd build - -cmake3 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$HOME/Software/llvm10 \ - -DLLVM_TARGETS_TO_BUILD="X86" \ - -DLLVM_BUILD_TOOLS=OFF \ - -DLLVM_INCLUDE_TOOLS=OFF \ - -DLLVM_BUILD_EXAMPLES=OFF \ - -DLLVM_INCLUDE_EXAMPLES=OFF \ - -DLLVM_BUILD_TESTS=OFF \ - -DLLVM_INCLUDE_TESTS=OFF \ - -DLLVM_OPTIMIZED_TABLEGEN=ON \ - .. -make install \ No newline at end of file diff --git a/build-utils/cmake-32bit-llvm-shared.bat b/build-utils/cmake-32bit-llvm-shared.bat deleted file mode 100644 index 44a493d..0000000 --- a/build-utils/cmake-32bit-llvm-shared.bat +++ /dev/null @@ -1,5 +0,0 @@ -mkdir llvm32 -cd llvm32 -rem cmake -DCMAKE_INSTALL_PREFIX=\d\ravi32 -G "Visual Studio 14" -DLLVM_JIT=ON -DLLVM_DIR=\d\LLVM37_32\share\llvm\cmake -DBUILD_STATIC=OFF .. -cmake -DCMAKE_INSTALL_PREFIX=\d\ravi32 -G "Visual Studio 14" -DLLVM_JIT=ON -DLLVM_DIR=\d\LLVM39_32\lib\cmake\llvm -DSTATIC_BUILD=OFF .. -cd .. \ No newline at end of file diff --git a/build-utils/cmake-32bit-llvm.bat b/build-utils/cmake-32bit-llvm.bat deleted file mode 100644 index e267338..0000000 --- a/build-utils/cmake-32bit-llvm.bat +++ /dev/null @@ -1,5 +0,0 @@ -mkdir llvm32 -cd llvm32 -rem cmake -DCMAKE_INSTALL_PREFIX=\d\ravi32 -G "Visual Studio 14" -DLLVM_JIT=ON -DLLVM_DIR=\d\LLVM37_32\share\llvm\cmake .. -cmake -DCMAKE_INSTALL_PREFIX=\d\ravi32 -G "Visual Studio 14" -DLLVM_JIT=ON -DLLVM_DIR=\d\LLVM39\lib\cmake\llvm -DSTATIC_BUILD=ON .. -cd .. \ No newline at end of file diff --git a/build-utils/cmake-32bit-llvmd.bat b/build-utils/cmake-32bit-llvmd.bat deleted file mode 100644 index 8d744a7..0000000 --- a/build-utils/cmake-32bit-llvmd.bat +++ /dev/null @@ -1,5 +0,0 @@ -mkdir llvm32d -cd llvm32d -rem cmake -DCMAKE_INSTALL_PREFIX=\d\ravi32 -G "Visual Studio 14" -DLLVM_JIT=ON -DLLVM_DIR=\d\LLVM37_32\share\llvm\cmake .. -cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=\d\ravi32 -G "Visual Studio 14" -DLLVM_JIT=ON -DLLVM_DIR=\d\LLVM39D_32\lib\cmake\llvm -DSTATIC_BUILD=ON .. -cd .. \ No newline at end of file diff --git a/build-utils/cmake-64bit-llvm-debug.bat b/build-utils/cmake-64bit-llvm-debug.bat deleted file mode 100644 index 0bd4653..0000000 --- a/build-utils/cmake-64bit-llvm-debug.bat +++ /dev/null @@ -1,6 +0,0 @@ -mkdir llvm64d -cd llvm64d -rem cmake -DCMAKE_INSTALL_PREFIX=c:\ravi64llvmd -G "Visual Studio 14 Win64" -DLLVM_JIT=ON -DLLVM_DIR=c:\LLVM37debug\share\llvm\cmake .. -rem cmake -DSTATIC_BUILD=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=c:\d\ravi64llvmd -G "Visual Studio 15 2017 Win64" -DLLVM_JIT=ON -DEMBEDDED_DMRC=ON -DLLVM_DIR=c:\d\LLVM39D64\lib\cmake\llvm .. -cmake -DCMAKE_INSTALL_PREFIX=c:\Software\ravi -G "Visual Studio 15 2017 Win64" -DCMAKE_BUILD_TYPE=Debug -DLLVM_JIT=ON -DLLVM_DIR=c:\Software\llvm501d\lib\cmake\llvm .. -cd .. \ No newline at end of file diff --git a/build-utils/cmake-64bit-llvm.bat b/build-utils/cmake-64bit-llvm.bat deleted file mode 100644 index 4d9cb12..0000000 --- a/build-utils/cmake-64bit-llvm.bat +++ /dev/null @@ -1,7 +0,0 @@ -mkdir llvm64 -cd llvm64 -rem pre LLVM 3.9 -rem cmake -DCMAKE_INSTALL_PREFIX=c:\ravi -G "Visual Studio 14 Win64" -DLLVM_JIT=ON -DLLVM_DIR=c:\LLVM37\share\llvm\cmake .. -rem cmake -DCMAKE_INSTALL_PREFIX=c:\ravi -G "Visual Studio 15 2017 Win64" -DLLVM_JIT=ON -DLLVM_DIR=c:\d\LLVM40_64\lib\cmake\llvm .. -cmake -DCMAKE_INSTALL_PREFIX=c:\Software\ravi -G "Visual Studio 15 2017 Win64" -DSTATIC_BUILD=ON -DLLVM_JIT=ON -DLLVM_DIR=c:\Software\llvm601r\lib\cmake\llvm .. -cd .. \ No newline at end of file diff --git a/build-utils/cmake-64bit-llvm8.bat b/build-utils/cmake-64bit-llvm8.bat deleted file mode 100644 index 4294d54..0000000 --- a/build-utils/cmake-64bit-llvm8.bat +++ /dev/null @@ -1,5 +0,0 @@ -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 .. \ No newline at end of file diff --git a/build-utils/cmake-64bit-llvm9d.bat b/build-utils/cmake-64bit-llvm9d.bat deleted file mode 100644 index 4cc753e..0000000 --- a/build-utils/cmake-64bit-llvm9d.bat +++ /dev/null @@ -1,5 +0,0 @@ -rmdir /s llvm10d -mkdir llvm10d -cd llvm10d -cmake -DCMAKE_INSTALL_PREFIX=c:\Software\ravi -G "Visual Studio 16 2019" -DLLVM_JIT=ON -DLLVM_DIR=c:\Software\llvm10d\lib\cmake\llvm .. -cd .. \ No newline at end of file diff --git a/build-utils/cmake-64bit-llvm9r.bat b/build-utils/cmake-64bit-llvm9r.bat deleted file mode 100644 index 2d3feaa..0000000 --- a/build-utils/cmake-64bit-llvm9r.bat +++ /dev/null @@ -1,6 +0,0 @@ -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 .. \ No newline at end of file diff --git a/build-utils/cmake-64bit-omrjit-debug.bat b/build-utils/cmake-64bit-omrjit-debug.bat deleted file mode 100644 index f9d44a4..0000000 --- a/build-utils/cmake-64bit-omrjit-debug.bat +++ /dev/null @@ -1,4 +0,0 @@ -mkdir omrjit -cd omrjit -cmake -DCMAKE_INSTALL_PREFIX=c:\Software\ravi -G "Visual Studio 15 2017 Win64" -DCMAKE_BUILD_TYPE=Debug -DOMR_JIT=ON .. -cd .. \ No newline at end of file diff --git a/build-utils/cmake-64bit-osx-xcode-llvm-debug.sh b/build-utils/cmake-64bit-osx-xcode-llvm-debug.sh deleted file mode 100644 index dda2aa2..0000000 --- a/build-utils/cmake-64bit-osx-xcode-llvm-debug.sh +++ /dev/null @@ -1,4 +0,0 @@ -mkdir xcodellvm -cd xcodellvm -#cmake -DCMAKE_BUILD_TYPE=Debug -G Xcode -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM/share/llvm/cmake .. -cmake -DCMAKE_BUILD_TYPE=Debug -G Xcode -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM5/lib/cmake/llvm .. diff --git a/build-utils/cmake-64bit-unix-llvm-debug.sh b/build-utils/cmake-64bit-unix-llvm-debug.sh deleted file mode 100644 index ce2c375..0000000 --- a/build-utils/cmake-64bit-unix-llvm-debug.sh +++ /dev/null @@ -1,5 +0,0 @@ -mkdir buildllvmd -cd buildllvmd -#cmake -DCMAKE_BUILD_TYPE=Debug -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM/share/llvm/cmake .. -#cmake -DCMAKE_BUILD_TYPE=Debug -DLLVM_JIT=ON -DLTESTS=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DLLVM_DIR=$HOME/LLVM5/lib/cmake/llvm .. -cmake -DCMAKE_BUILD_TYPE=Debug -DLLVM_JIT=ON -DLTESTS=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravillvm -DLLVM_DIR=$HOME/Software/llvm600/lib/cmake/llvm .. diff --git a/build-utils/cmake-64bit-unix-llvm-release.sh b/build-utils/cmake-64bit-unix-llvm-release.sh deleted file mode 100644 index 2f3211a..0000000 --- a/build-utils/cmake-64bit-unix-llvm-release.sh +++ /dev/null @@ -1,7 +0,0 @@ -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 -DSTATIC_BUILD=ON -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/Software/ravi -DLLVM_DIR=$HOME/Software/llvm801/lib/cmake/llvm .. -cmake3 -DCMAKE_BUILD_TYPE=Release -DSTATIC_BUILD=ON -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/Software/ravi -DLLVM_DIR=$HOME/Software/llvm10/lib/cmake/llvm .. diff --git a/build-utils/cmake-64bit-unix-omrjit-release.sh b/build-utils/cmake-64bit-unix-omrjit-release.sh deleted file mode 100644 index 858828c..0000000 --- a/build-utils/cmake-64bit-unix-omrjit-release.sh +++ /dev/null @@ -1,3 +0,0 @@ -mkdir omrjit -cd omrjit -cmake -DCMAKE_BUILD_TYPE=Release -DOMR_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi .. diff --git a/docker/linux-ubuntu/Dockerfile b/docker/linux-ubuntu/Dockerfile index 3dee9e8..7ae0d69 100644 --- a/docker/linux-ubuntu/Dockerfile +++ b/docker/linux-ubuntu/Dockerfile @@ -12,20 +12,15 @@ RUN set -x \ && 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 .. \ + && /Software/cmake-3.14.5-Linux-x86_64/bin/cmake -DCMAKE_INSTALL_PREFIX=/Software/ravi -DCMAKE_BUILD_TYPE=Release .. \ && 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 \ diff --git a/include/ravi_llvm.h b/include/ravi_llvm.h deleted file mode 100644 index b786280..0000000 --- a/include/ravi_llvm.h +++ /dev/null @@ -1,121 +0,0 @@ -/****************************************************************************** -* Copyright (C) 2015 Dibyendu Majumdar -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be -* included in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -******************************************************************************/ -#ifndef RAVI_LLVM_H -#define RAVI_LLVM_H - -#ifdef USE_LLVM - -#include "llvm/Config/llvm-config.h" - -#if (LLVM_VERSION_MAJOR < 3 || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5 || LLVM_VERSION_MAJOR == 7) -#error Unsupported LLVM version -#endif - -#if LLVM_VERSION_MAJOR >= 5 -#define USE_ORC_JIT 1 -#else -#define USE_ORC_JIT 0 -#endif - -#if LLVM_VERSION_MAJOR >= 8 && !defined(_WIN32) -#define USE_ORCv2_JIT 0 -#else -#define USE_ORCv2_JIT 0 -#endif - -#if LLVM_VERSION_MAJOR >= 10 -#undef USE_ORCv2_JIT -#define USE_ORCv2_JIT 1 -#endif - -// In lua.c we include this just to get version numbers -// We cannot have C++ headers in that case -#ifdef __cplusplus - -#include "llvm/ADT/Triple.h" -#include "llvm/Analysis/Passes.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/MCJIT.h" -#include "llvm/ExecutionEngine/SectionMemoryManager.h" -#include "llvm/ExecutionEngine/GenericValue.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Intrinsics.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/MDBuilder.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Verifier.h" -#include "llvm/IR/Metadata.h" -#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7 -#include "llvm/PassManager.h" -#else -#include "llvm/IR/LegacyPassManager.h" -#endif -#include "llvm/Transforms/IPO/PassManagerBuilder.h" -#include "llvm/Transforms/Instrumentation.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/DynamicLibrary.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/Support/FormattedStream.h" - - -#if USE_ORC_JIT || USE_ORCv2_JIT -#include "llvm/ADT/STLExtras.h" -#include "llvm/ExecutionEngine/JITSymbol.h" -#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" -#include "llvm/ExecutionEngine/Orc/CompileUtils.h" -#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" -#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" -#include "llvm/ExecutionEngine/Orc/IRTransformLayer.h" -#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" -#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" -#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h" -#include "llvm/ExecutionEngine/Orc/CompileUtils.h" -#include "llvm/IR/Mangler.h" -#include "llvm/Support/Error.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Transforms/Scalar/GVN.h" - -#if LLVM_VERSION_MAJOR >= 8 -#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" -#include "llvm/ExecutionEngine/Orc/Legacy.h" -#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" -#endif -#endif - -#include -#include -#include -#include -#include -#include -#include - -#endif //__cplusplus - -#endif //USE_LLVM - -#endif diff --git a/include/ravi_llvmcodegen.h b/include/ravi_llvmcodegen.h deleted file mode 100644 index eec6729..0000000 --- a/include/ravi_llvmcodegen.h +++ /dev/null @@ -1,1409 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2015 Dibyendu Majumdar - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ******************************************************************************/ - -#ifndef RAVI_LLVMCODEGEN_H -#define RAVI_LLVMCODEGEN_H - -#ifdef USE_LLVM - -#include "ravi_llvm.h" -#include "ravi_jit.h" - -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -// TODO we probably do not need all the headers -// below - -#define LUA_CORE - -#include "lprefix.h" - -#include -#include -#include -#include - -#include "lua.h" - -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "lobject.h" -#include "lopcodes.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "lvm.h" - -#ifdef __cplusplus -} -#endif - -namespace ravi { - -/* -** Lua typecode have certain bits that are used to -** indicate variants or subtypes, or whether the type -** is collectible. The enumerated values below -** reflect the way these type codes get set within -** Lua values - these are the codes the JIT code must -** use. -*/ -enum LuaTypeCode { - LUA__TNIL = LUA_TNIL, - LUA__TBOOLEAN = LUA_TBOOLEAN, - LUA__TLIGHTUSERDATA = LUA_TLIGHTUSERDATA, - LUA__TNUMBER = LUA_TNUMBER, - LUA__TSTRING = ctb(LUA_TSTRING), - LUA__TTABLE = LUA_TTABLE, - RAVI__TLTABLE = ctb(LUA_TTABLE), - RAVI__TIARRAY = ctb(RAVI_TIARRAY), - RAVI__TFARRAY = ctb(RAVI_TFARRAY), - LUA__TFUNCTION = ctb(LUA_TFUNCTION), - LUA__TUSERDATA = ctb(LUA_TUSERDATA), - LUA__TTHREAD = ctb(LUA_TTHREAD), - LUA__TLCL = ctb(LUA_TLCL), - LUA__TLCF = LUA_TLCF, - LUA__TCCL = ctb(LUA_TCCL), - LUA__TSHRSTR = ctb(LUA_TSHRSTR), - LUA__TLNGSTR = ctb(LUA_TLNGSTR), - LUA__TNUMFLT = LUA_TNUMFLT, - LUA__TNUMINT = LUA_TNUMINT -}; - -// All LLVM definitions for -// Lua types are gathered here -struct LuaLLVMTypes { - LuaLLVMTypes(llvm::LLVMContext &context); - void addCommonGCHeader(std::vector &elements); - void dump(); - - // Following are standard C types - // Must ensure that these types match - // between JIT and the C compiler - llvm::Type *C_voidT; - llvm::Type *C_floatT; - llvm::Type *C_doubleT; - llvm::Type *C_intptr_t; - llvm::Type *C_size_t; - llvm::PointerType *C_psize_t; /* pointer to size_t */ - llvm::Type *C_ptrdiff_t; - llvm::Type *C_int64_t; - llvm::Type *C_shortT; - llvm::Type *C_intT; - llvm::PointerType *C_pintT; /* pointer to int */ - llvm::PointerType *C_pcharT; /* pointer to char */ - - llvm::Type *lua_NumberT; - llvm::PointerType *plua_NumberT; - llvm::PointerType *pplua_NumberT; - - // WARNING: We currently assume that lua_Integer is - // 64-bit - llvm::Type *lua_IntegerT; - llvm::PointerType *plua_IntegerT; - llvm::PointerType *pplua_IntegerT; - - // WARNING: We currently assume that lua_Unsigned is - // 64-bit - llvm::Type *lua_UnsignedT; - - llvm::Type *lua_LuaTypeT; - llvm::Type *lua_KContextT; - - llvm::FunctionType *lua_CFunctionT; - llvm::PointerType *plua_CFunctionT; - - llvm::FunctionType *lua_KFunctionT; - llvm::PointerType *plua_KFunctionT; - - llvm::FunctionType *lua_HookT; - llvm::PointerType *plua_HookT; - - llvm::FunctionType *lua_AllocT; - llvm::PointerType *plua_AllocT; - - llvm::Type *l_memT; - llvm::Type *lu_memT; - - llvm::Type *tmsT; - - llvm::Type *lu_byteT; - llvm::Type *L_UmaxalignT; - - llvm::StructType *lua_StateT; - llvm::PointerType *plua_StateT; - - llvm::StructType *global_StateT; - llvm::PointerType *pglobal_StateT; - - llvm::StructType *ravi_StateT; - llvm::PointerType *pravi_StateT; - - llvm::StructType *GCObjectT; - llvm::PointerType *pGCObjectT; - - llvm::StructType *ValueT; - llvm::StructType *TValueT; - llvm::PointerType *pTValueT; - llvm::StructType *TStringT; - llvm::PointerType *pTStringT; - llvm::PointerType *ppTStringT; - - llvm::StructType *UdataT; - llvm::StructType *RaviArrayT; - llvm::PointerType* pRaviArrayT; - llvm::PointerType* ppRaviArrayT; - llvm::StructType *TableT; - llvm::PointerType *pTableT; - llvm::PointerType *ppTableT; - - llvm::StructType *UpvaldescT; - llvm::PointerType *pUpvaldescT; - - llvm::Type *ravitype_tT; - llvm::StructType *LocVarT; - llvm::PointerType *pLocVarT; - - llvm::Type *InstructionT; - llvm::PointerType *pInstructionT; - llvm::StructType *LClosureT; - llvm::PointerType *pLClosureT; - llvm::PointerType *ppLClosureT; - llvm::PointerType *pppLClosureT; - - llvm::StructType *RaviJITProtoT; - - llvm::StructType *ProtoT; - llvm::PointerType *pProtoT; - llvm::PointerType *ppProtoT; - - llvm::StructType *UpValT; - llvm::PointerType *pUpValT; - - llvm::StructType *CClosureT; - llvm::PointerType *pCClosureT; - - llvm::StructType *TKeyT; - llvm::PointerType *pTKeyT; - - llvm::StructType *NodeT; - llvm::PointerType *pNodeT; - - llvm::StructType *lua_DebugT; - llvm::PointerType *plua_DebugT; - - llvm::StructType *lua_longjumpT; - llvm::PointerType *plua_longjumpT; - - llvm::StructType *MbufferT; - llvm::StructType *stringtableT; - - llvm::PointerType *StkIdT; - - llvm::StructType *CallInfoT; - llvm::StructType *CallInfo_cT; - llvm::StructType *CallInfo_lT; - llvm::PointerType *pCallInfoT; - - llvm::FunctionType *jitFunctionT; - - llvm::FunctionType *luaC_upvalbarrierT; - llvm::FunctionType *luaD_poscallT; - llvm::FunctionType *luaD_precallT; - llvm::FunctionType *luaD_callT; - llvm::FunctionType *luaF_closeT; - llvm::FunctionType *luaG_runerrorT; - llvm::FunctionType *luaH_getintT; - llvm::FunctionType *luaH_setintT; - llvm::FunctionType *luaH_getstrT; - llvm::FunctionType *luaT_trybinTMT; - llvm::FunctionType *luaV_equalobjT; - llvm::FunctionType *luaV_lessthanT; - llvm::FunctionType *luaV_lessequalT; - llvm::FunctionType *luaV_forlimitT; - llvm::FunctionType *luaV_tonumberT; - llvm::FunctionType *luaV_tointegerT; - llvm::FunctionType *luaV_modT; - llvm::FunctionType *luaV_objlenT; - llvm::FunctionType *luaV_idivT; - llvm::FunctionType *luaV_executeT; - llvm::FunctionType *luaV_gettableT; - llvm::FunctionType *luaV_settableT; - llvm::FunctionType *luaV_finishgetT; - - // Following are functions that handle specific bytecodes - // We cheat for these bytecodes by calling the function that - // implements it - llvm::FunctionType *raviV_op_newarrayintT; - llvm::FunctionType *raviV_op_newarrayfloatT; - llvm::FunctionType *raviV_op_setlistT; - llvm::FunctionType *raviV_op_newtableT; - llvm::FunctionType *raviV_op_loadnilT; - llvm::FunctionType *raviV_op_concatT; - llvm::FunctionType *raviV_op_closureT; - llvm::FunctionType *raviV_op_varargT; - llvm::FunctionType *raviV_op_addT; - llvm::FunctionType *raviV_op_subT; - llvm::FunctionType *raviV_op_mulT; - llvm::FunctionType *raviV_op_divT; - llvm::FunctionType *raviV_op_shrT; - llvm::FunctionType *raviV_op_shlT; - llvm::FunctionType *raviV_op_borT; - llvm::FunctionType *raviV_op_bxorT; - llvm::FunctionType *raviV_op_bandT; - llvm::FunctionType *raviV_op_bnotT; - llvm::FunctionType *raviV_op_setupvaliT; - llvm::FunctionType *raviV_op_setupvalfT; - llvm::FunctionType *raviV_op_setupvalaiT; - llvm::FunctionType *raviV_op_setupvalafT; - llvm::FunctionType *raviV_op_setupvaltT; - llvm::FunctionType *raviV_gettable_sskeyT; - llvm::FunctionType *raviV_settable_sskeyT; - llvm::FunctionType *raviV_gettable_iT; - llvm::FunctionType *raviV_settable_iT; - llvm::FunctionType *raviV_op_totypeT; -#ifdef RAVI_DEFER_STATEMENT - llvm::FunctionType *raviV_op_deferT; -#endif - - llvm::FunctionType *raviH_set_intT; - llvm::FunctionType *raviH_set_floatT; - -#if 0 - llvm::FunctionType *ravi_dump_valueT; - llvm::FunctionType *ravi_dump_stackT; - llvm::FunctionType *ravi_dump_stacktopT; -#endif - llvm::FunctionType *ravi_debug_traceT; - - std::array kInt; - std::array kluaInteger; - - llvm::Constant *kFalse; - - // To allow better optimization we need to decorate the - // LLVM Load/Store instructions with type information. - // For this we need to construct tbaa metadata - llvm::MDBuilder mdbuilder; - llvm::MDNode *tbaa_root; - llvm::MDNode *tbaa_charT; - llvm::MDNode *tbaa_pcharT; - llvm::MDNode *tbaa_shortT; - llvm::MDNode *tbaa_pshortT; - llvm::MDNode *tbaa_intT; - llvm::MDNode *tbaa_pintT; - llvm::MDNode *tbaa_longlongT; - llvm::MDNode *tbaa_plonglongT; - llvm::MDNode *tbaa_doubleT; - llvm::MDNode *tbaa_pdoubleT; - llvm::MDNode *tbaa_pointerT; - llvm::MDNode *tbaa_ppointerT; - llvm::MDNode *tbaa_CallInfo_lT; - llvm::MDNode *tbaa_CallInfoT; - llvm::MDNode *tbaa_luaStateT; - llvm::MDNode *tbaa_luaState_ciT; - llvm::MDNode *tbaa_luaState_ci_baseT; - llvm::MDNode *tbaa_CallInfo_funcT; - llvm::MDNode *tbaa_CallInfo_func_LClosureT; - llvm::MDNode *tbaa_CallInfo_topT; - llvm::MDNode *tbaa_CallInfo_jitstatusT; - llvm::MDNode *tbaa_CallInfo_callstatusT; - llvm::MDNode *tbaa_CallInfo_savedpcT; - llvm::MDNode *tbaa_LClosureT; - llvm::MDNode *tbaa_LClosure_pT; - llvm::MDNode *tbaa_LClosure_upvalsT; - llvm::MDNode *tbaa_ProtoT; - llvm::MDNode *tbaa_Proto_kT; - llvm::MDNode *tbaa_Proto_sizepT; - llvm::MDNode *tbaa_Proto_codeT; - llvm::MDNode *tbaa_TValueT; - llvm::MDNode *tbaa_TValue_nT; - llvm::MDNode *tbaa_TValue_hT; - llvm::MDNode *tbaa_TValue_ttT; - llvm::MDNode *tbaa_luaState_topT; - llvm::MDNode *tbaa_UpValT; - llvm::MDNode *tbaa_UpVal_vT; - llvm::MDNode *tbaa_RaviArrayT; - llvm::MDNode *tbaa_TableT; - llvm::MDNode *tbaa_RaviArray_typeT; - llvm::MDNode *tbaa_RaviArray_dataT; - llvm::MDNode *tbaa_RaviArray_lenT; - llvm::MDNode *tbaa_TString_hash; - llvm::MDNode *tbaa_Table_lsizenode; - llvm::MDNode *tbaa_Table_node; - llvm::MDNode *tbaa_Table_sizearray; - llvm::MDNode *tbaa_Table_array; - llvm::MDNode *tbaa_Table_flags; - llvm::MDNode *tbaa_Table_metatable; -#if RAVI_USE_NEWHASH - llvm::MDNode *tbaa_Table_hmask; -#endif -}; - -// The hierarchy of objects -// used to represent LLVM artifacts is as -// follows - -// RaviJITState - Root, held in Lua state; wraps llvm::Context -// +- RaviJITModule - wraps llvm::Module -// +- RaviJITFunction - wraps llvm::Function - -// The RaviJITFunction is held within the -// Lua Proto structure - and garbage collected along -// with the Lua function. Each RaviJITFunction -// holds a reference to the owning RaviJITModule -// via a shared_ptr. This ensures that RaviJITModule gets -// released when no longer referenced. - -class RaviJITState; -class RaviJITModule; -class RaviJITFunction; - -class RaviJITStateFactory { - public: - static std::unique_ptr newJITState(); -}; - -// Ravi's LLVM JIT State -// All of the JIT information is held here -class RaviJITState { - friend class RaviJITModule; - -#if USE_ORCv2_JIT - - std::unique_ptr ES; - std::unique_ptr ObjectLayer; - std::unique_ptr CompileLayer; - std::unique_ptr OptimizeLayer; - - std::unique_ptr DL; - std::unique_ptr Mangle; - std::unique_ptr Ctx; - std::unique_ptr TM; - -#if LLVM_VERSION_MAJOR >= 10 - llvm::orc::JITDylib *MainJD; -#endif - -#elif USE_ORC_JIT - - // The LLVM Context - std::unique_ptr context_; - - // From LLVM version5 onwards we use the new ORC apis - // The main benefit is that memory management is tighter, - // all the IR in modules get released after compilation - // MCJIT is also likely to be removed at some time in - // future so we needed to migrate anyway - // We don't use ORC apis in earlier versions because - // the apis have changed over the releases so it - // is simpler to use them in 5.0 and above. - // The ORC usage here is heavily based upon the kaleidoscope - // sample, with some adjustments. - -#if LLVM_VERSION_MAJOR >= 8 - using ObjectLayerT = llvm::orc::LegacyRTDyldObjectLinkingLayer; - using CompileLayerT = llvm::orc::LegacyIRCompileLayer; - using OptimizeFunction = std::function(std::unique_ptr)>; - using OptimizerLayerT = llvm::orc::LegacyIRTransformLayer; - using ModuleHandle = llvm::orc::VModuleKey; - using CODLayerT = llvm::orc::LegacyCompileOnDemandLayer; -#else - using ObjectLayerT = llvm::orc::RTDyldObjectLinkingLayer; - using CompileLayerT = llvm::orc::IRCompileLayer; - using OptimizeFunction = std::function(std::shared_ptr)>; - using OptimizerLayerT = llvm::orc::IRTransformLayer; - using ModuleHandle = OptimizerLayerT::ModuleHandleT; -#endif - - std::unique_ptr TM; - std::unique_ptr DL; - std::unique_ptr ObjectLayer; - std::unique_ptr CompileLayer; - std::unique_ptr OptimizeLayer; -#if LLVM_VERSION_MAJOR >= 8 - std::map > Resolvers; - std::shared_ptr StringPool; - std::unique_ptr ES; - std::unique_ptr CompileCallbackManager; - std::unique_ptr CompileOnDemandLayer; -#endif - -#else - - // Not ORC_JIT - // The LLVM Context - std::unique_ptr context_; - -#endif // USE_ORCv2_JIT - - // The triple represents the host target - std::string triple_; - - // Lua type definitions - std::unique_ptr types_; - - // Should we auto compile what we can? - unsigned int auto_ : 1; - - // Is JIT enabled - unsigned int enabled_ : 1; - - // Optimizer level (LLVM PassManagerBuilder) - unsigned int opt_level_ : 2; - - // Size level (LLVM PassManagerBuilder) - unsigned int size_level_ : 2; - - // Verbosity - unsigned int verbosity_ : 3; - - // enable calls to luaG_traceexec() at every bytecode - // instruction; this is expensive! - unsigned int tracehook_enabled_ : 1; - - // Enable extra validation such as IR verification - // May slow down compilation - unsigned int validation_ : 1; - - // min code size for compilation - int min_code_size_; - - // min execution count for compilation - int min_exec_count_; - - // Count of modules allocated - // Used to debug module deallocation - size_t allocated_modules_; - - // flag to help avoid recursion - int compiling_; - - public: - RaviJITState(); - ~RaviJITState(); - -#if USE_ORCv2_JIT - - llvm::LLVMContext &context() { return *Ctx->getContext(); } - - llvm::Expected optimizeModule(llvm::orc::ThreadSafeModule TSM, - const llvm::orc::MaterializationResponsibility &R); - - llvm::Error addModule(std::unique_ptr M); - - llvm::Expected findSymbol(llvm::StringRef Name) { -#if LLVM_VERSION_MAJOR >= 10 - return ES->lookup({MainJD}, (*Mangle)(Name.str())); -#else - return ES->lookup({&ES->getMainJITDylib()}, (*Mangle)(Name.str())); -#endif - } - - const llvm::DataLayout &getDataLayout() const { return *DL; } - -#elif USE_ORC_JIT - -#if LLVM_VERSION_MAJOR >= 8 - std::unique_ptr optimizeModule(std::unique_ptr M); -#else - std::shared_ptr optimizeModule(std::shared_ptr M); -#endif - - llvm::TargetMachine &getTargetMachine() { return *TM; } - - ModuleHandle addModule(std::unique_ptr M); - - llvm::JITSymbol findSymbol(const std::string &Name); - - void removeModule(ModuleHandle H); - - llvm::LLVMContext &context() { return *context_; } - -#else - - // Not ORC JIT - llvm::LLVMContext &context() { return *context_; } - -#endif - - void addGlobalSymbol(const std::string &name, void *address); - - void dump(); - LuaLLVMTypes *types() const { return types_.get(); } - const std::string &triple() const { return triple_; } - bool is_auto() const { return auto_; } - void set_auto(bool value) { auto_ = value; } - bool is_enabled() const { return enabled_; } - void set_enabled(bool value) { enabled_ = value; } - int get_optlevel() const { return opt_level_; } - void set_optlevel(int value) { - if (value >= 0 && value <= 3) - opt_level_ = value; - } - int get_sizelevel() const { return size_level_; } - void set_sizelevel(int value) { - if (value >= 0 && value <= 2) - size_level_ = value; - } - int get_verbosity() const { return verbosity_; } - void set_verbosity(int value) { - if (value >= 0 && value <= 3) - verbosity_ = value; - } - int get_mincodesize() const { return min_code_size_; } - void set_mincodesize(int value) { min_code_size_ = value > 0 ? value : min_code_size_; } - int get_minexeccount() const { return min_exec_count_; } - void set_minexeccount(int value) { min_exec_count_ = value > 0 ? value : min_exec_count_; } - int get_validation() const { return validation_; } - void set_validation(bool value) { validation_ = value; } - bool is_tracehook_enabled() const { return tracehook_enabled_; } - void set_tracehook_enabled(bool value) { tracehook_enabled_ = value; } - void incr_allocated_modules() { allocated_modules_++; } - void decr_allocated_modules() { allocated_modules_--; } - size_t allocated_modules() const { return allocated_modules_; } - int get_compiling_flag() const { return compiling_ > 0; } - void set_compiling_flag(bool value) { - if (value) - compiling_++; - else - compiling_--; - } -}; - -// A wrapper for LLVM Module -// Maintains a dedicated ExecutionEngine for the module -class RaviJITModule { - // The Context that owns this module - RaviJITState *owner_; - -#if USE_ORCv2_JIT - - // The LLVM Module within which the functions will be defined - std::unique_ptr module_; - -#elif USE_ORC_JIT - - // The LLVM Module within which the functions will be defined - std::unique_ptr module_; - - // With ORC, once a module is compiled (added to the JIT) - // then a handle is used to refer to it rather than the - // module, as the module may have been deleted by then - RaviJITState::ModuleHandle module_handle_; - -#else - - // The LLVM Module within which the functions will be defined - llvm::Module *module_; - - // The execution engine responsible for compiling the - // module - llvm::ExecutionEngine *engine_; - -#endif - - // List of JIT functions in this module - // We need this so that we can update the functions - // post compilation - std::vector functions_; - - // Keep track of external symbols added - std::map external_symbols_; - - public: - RaviJITModule(RaviJITState *owner); - ~RaviJITModule(); - -#if !USE_ORC_JIT && !USE_ORCv2_JIT - llvm::Module *module() const { return module_; } - llvm::ExecutionEngine *engine() const { return engine_; } -#else - // Note that this can return nullptr - llvm::Module *module() const { return module_.get(); } -#endif - - RaviJITState *owner() const { return owner_; } - void dump(); - void dumpAssembly(); - - // Add the function to this module, the function will be - // saved in the functions_ array. The location of the - // function is returned which must be returned by - // f->getId() - int addFunction(RaviJITFunction *f); - // Remove a function from the array - // This calls f->getId() to get the - // functions location in the array - void removeFunction(RaviJITFunction *f); - - // Runs LLVM code generation and optimization passes - // The reason for separting this from the - // finalization is that this method is also - // used to dump the generated assembly code - void runpasses(bool dumpAsm = false); - // finalize the module, and assign each function - // its function pointer - void finalize(bool doDump = false); - - // Add declaration for an extern function that is not - // loaded dynamically - i.e., is part of the the executable - // and therefore not visible at runtime by name - llvm::Function *addExternFunction(llvm::FunctionType *type, void *address, const std::string &name); -}; - -// Represents a JITed or JITable function -// This object is stored in the Lua Proto structure -// and gets destroyed when the Lua function is -// garbage collected -class RaviJITFunction { - // The Module in which this function lives - // We hold a shared_ptr to the module so that - // the module will be destroyed when the - // last associated RaviJITFunction is collected - std::shared_ptr module_; - - // Unique name for the function - std::string name_; - - // ID allocated by the module to this function - // This must be returned via getId() - int id_; - - // The llvm Function definition - llvm::Function *function_; - - // Pointer to compiled function - void *ptr_; - - // A location provided by the caller where the - // compiled function will be saved - lua_CFunction *func_ptrptr_; - - public: - RaviJITFunction(lua_CFunction *p, const std::shared_ptr &module, llvm::FunctionType *type, - llvm::GlobalValue::LinkageTypes linkage, const std::string &name); - RaviJITFunction(lua_CFunction *p, const std::shared_ptr &module, const std::string &name); - - ~RaviJITFunction(); - - const std::string &name() const { return name_; } - llvm::Function *function() const { return function_; } - // Note that this can return nullptr - llvm::Module *module() const { return module_->module(); } - std::shared_ptr raviModule() const { return module_; } -#if !USE_ORC_JIT && !USE_ORCv2_JIT - llvm::ExecutionEngine *engine() const { return module_->engine(); } -#endif - RaviJITState *owner() const { return module_->owner(); } - // This method retrieves the JITed function from the - // execution engine and sets ptr_ member - // It must be called after the module has run the - // code generation and optimization passes - void setFunctionPtr(); - void dump() { module_->dump(); } - void dumpAssembly() { module_->dumpAssembly(); } - int getId() const { return id_; } - void setId(int id) { id_ = id; } - llvm::Function *addExternFunction(llvm::FunctionType *type, void *address, const std::string &name) { - return module_->addExternFunction(type, address, name); - } -}; - -// To optimise fornum loops -// i.e. OP_FORPREP and OP_FORLOOP instructions -// we use computed gotos to specialised -// jmp labels. Hence the 4 jmp targets. -// For other instructions only the first jump -// target is used -struct RaviBranchDef { - // this field is used for all branches - // forloop int step > 0 - llvm::BasicBlock *jmp1; - // forloop int step < 0 - llvm::BasicBlock *jmp2; - // forloop float step > 0 - llvm::BasicBlock *jmp3; - // forlook float step < 0 - llvm::BasicBlock *jmp4; - - // These are local variables for a fornum - // loop - llvm::Value *ilimit; - llvm::Value *istep; - llvm::Value *iidx; - llvm::Value *flimit; - llvm::Value *fstep; - llvm::Value *fidx; - - // This holds the branch to which the - // loop body will jump to using a - // IndirectBr instruction - llvm::Value *forloop_branch; - - RaviBranchDef(); -}; - -// This structure holds stuff we need when compiling a single -// function -struct RaviFunctionDef { - RaviJITState *jitState; - RaviJITFunction *raviF; - llvm::Function *f; - llvm::BasicBlock *entry; - llvm::Value *L; - LuaLLVMTypes *types; - llvm::IRBuilder<> *builder; - Proto *p; - - // Lua function declarations - llvm::Function *luaD_poscallF; - llvm::Function *luaD_precallF; - llvm::Function *luaD_callF; - llvm::Function *luaF_closeF; - llvm::Function *luaG_runerrorF; - llvm::Function *luaT_trybinTMF; - llvm::Function *luaV_equalobjF; - llvm::Function *luaV_lessthanF; - llvm::Function *luaV_lessequalF; - llvm::Function *luaV_forlimitF; - llvm::Function *luaV_tonumberF; - llvm::Function *luaV_tointegerF; - llvm::Function *luaV_executeF; - llvm::Function *luaV_gettableF; - llvm::Function *luaV_settableF; - llvm::Function *luaV_modF; - llvm::Function *luaV_idivF; - llvm::Function *luaV_objlenF; - llvm::Function *luaC_upvalbarrierF; - llvm::Function *luaH_getstrF; - llvm::Function *luaH_getintF; - llvm::Function *luaH_setintF; - llvm::Function *luaV_finishgetF; - - // Some cheats - these correspond to OPCODEs that - // are not inlined as of now - llvm::Function *raviV_op_newarrayintF; - llvm::Function *raviV_op_newarrayfloatF; - llvm::Function *raviV_op_setlistF; - llvm::Function *raviV_op_newtableF; - llvm::Function *raviV_op_loadnilF; - llvm::Function *raviV_op_concatF; - llvm::Function *raviV_op_closureF; - llvm::Function *raviV_op_varargF; - llvm::Function *raviV_op_addF; - llvm::Function *raviV_op_subF; - llvm::Function *raviV_op_mulF; - llvm::Function *raviV_op_divF; - llvm::Function *raviV_op_shrF; - llvm::Function *raviV_op_shlF; - llvm::Function *raviV_op_borF; - llvm::Function *raviV_op_bxorF; - llvm::Function *raviV_op_bandF; - llvm::Function *raviV_op_bnotF; - llvm::Function *raviV_op_setupvaliF; - llvm::Function *raviV_op_setupvalfF; - llvm::Function *raviV_op_setupvalaiF; - llvm::Function *raviV_op_setupvalafF; - llvm::Function *raviV_op_setupvaltF; - llvm::Function *raviV_gettable_sskeyF; - llvm::Function *raviV_settable_sskeyF; - llvm::Function *raviV_gettable_iF; - llvm::Function *raviV_settable_iF; - llvm::Function *raviV_op_totypeF; -#ifdef RAVI_DEFER_STATEMENT - llvm::Function *raviV_op_deferF; -#endif - - // array setters - llvm::Function *raviH_set_intF; - llvm::Function *raviH_set_floatF; - -#if 0 - // DEBUG routines - llvm::Function *ravi_dump_valueF; - llvm::Function *ravi_dump_stackF; - llvm::Function *ravi_dump_stacktopF; -#endif - 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 jmp_targets; - - // Load pointer to proto - llvm::Value *proto; // gep - llvm::Instruction *proto_ptr; - - // Obtain pointer to Proto->k - llvm::Value *proto_k; - // Load pointer to Proto->k; this does not change - llvm::Instruction *k_ptr; - - // Load L->ci - llvm::Value *L_ci; // This is the GEP for L->ci - llvm::Instruction *ci_val; - - // Pointer to ci->u.l.base - llvm::Value *Ci_base; // This is the GEP for ci->u.l.base - llvm::Instruction *base_ptr; - - // Pointer to LClosure - llvm::Value *p_LClosure; -}; - -// This class is responsible for compiling Lua byte code -// to LLVM IR -class RaviCodeGenerator { - public: - RaviCodeGenerator(RaviJITState *jitState); - - // Compile given function if possible - // The p->ravi_jit structure will be updated - // Note that if a function fails to compile then - // a flag is set so that it doesn't get compiled again - bool compile(lua_State *L, Proto *p, std::shared_ptr module, ravi_compile_options_t *options); - - // We can only compile a subset of op codes - // and not all features are supported - bool canCompile(Proto *p); - - // Create a unique function name in the context - // of this generator - const char *unique_function_name(); - - // Create the prologue of the JIT function - // Argument will be named L - // Initial BasicBlock will be created - // int func(lua_State *L) { - std::unique_ptr create_function(Proto *p, std::shared_ptr module, - llvm::IRBuilder<> &builder, RaviFunctionDef *def); - - // Save proto->code[pc] into savedpc - void emit_update_savedpc(RaviFunctionDef *def, int pc); - - llvm::CallInst *CreateCall1(llvm::IRBuilder<> *builder, llvm::Value *func, llvm::Value *arg1); - llvm::CallInst *CreateCall2(llvm::IRBuilder<> *builder, llvm::Value *func, llvm::Value *arg1, llvm::Value *arg2); - llvm::CallInst *CreateCall3(llvm::IRBuilder<> *builder, llvm::Value *func, llvm::Value *arg1, llvm::Value *arg2, - llvm::Value *arg3); - llvm::CallInst *CreateCall4(llvm::IRBuilder<> *builder, llvm::Value *func, llvm::Value *arg1, llvm::Value *arg2, - llvm::Value *arg3, llvm::Value *arg4); - llvm::CallInst *CreateCall5(llvm::IRBuilder<> *builder, llvm::Value *func, llvm::Value *arg1, llvm::Value *arg2, - llvm::Value *arg3, llvm::Value *arg4, llvm::Value *arg5); - - void attach_branch_weights(RaviFunctionDef *def, llvm::Instruction *ins, uint32_t true_branch, uint32_t false_branch); - - void emit_raise_lua_error(RaviFunctionDef *def, const char *str); - - // Add extern declarations for Lua functions we need to call - void emit_extern_declarations(RaviFunctionDef *def); - - // Retrieve the proto->sizep - llvm::Instruction *emit_load_proto_sizep(RaviFunctionDef *def); - - // Store lua_Number or lua_Integer - llvm::Instruction *emit_store_local_n(RaviFunctionDef *def, llvm::Value *src, llvm::Value *dest); - - // Load lua_Number or lua_Integer - llvm::Instruction *emit_load_local_n(RaviFunctionDef *def, llvm::Value *src); - - // Store int - llvm::Instruction *emit_store_local_int(RaviFunctionDef *def, llvm::Value *src, llvm::Value *dest); - - // Load int - llvm::Instruction *emit_load_local_int(RaviFunctionDef *def, llvm::Value *src); - - // Test if value type is of specific Lua type - // Value_type should have been obtained by emit_load_type() - // The Lua typecode to check must be in lua_typecode - // The return value is a boolean type as a result of - // integer comparison result which is i1 in LLVM - llvm::Value *emit_is_value_of_type(RaviFunctionDef *def, llvm::Value *value_type, LuaTypeCode lua_typecode, - const char *varname = "value.typeof"); - - // Test if value type is NOT of specific Lua type - // Value_type should have been obtained by emit_load_type() - // The Lua typecode to check must be in lua_typecode - // The return value is a boolean type as a result of - // integer comparison result which is i1 in LLVM - llvm::Value *emit_is_not_value_of_type(RaviFunctionDef *def, llvm::Value *value_type, LuaTypeCode lua_typecode, - const char *varname = "value.not.typeof"); - - // Test if value type is NOT of specific Lua type class - // i.e. variants are ignore - // Value_type should have been obtained by emit_load_type() - // The Lua typecode to check must be in lua_typecode - // The return value is a boolean type as a result of - // integer comparison result which is i1 in LLVM - llvm::Value *emit_is_not_value_of_type_class(RaviFunctionDef *def, llvm::Value *value_type, int lua_typecode, - const char *varname = "value.not.typeof"); - - // emit code for LClosure *cl = clLvalue(ci->func) - // this is same as: - // emit code for (LClosure *)ci->func->value_.gc - llvm::Instruction *emit_gep_ci_func_value_gc_asLClosure(RaviFunctionDef *def); - - llvm::Value *emit_gep(RaviFunctionDef *def, const char *name, llvm::Value *s, int arg1); - llvm::Value *emit_gep(RaviFunctionDef *def, const char *name, llvm::Value *s, int arg1, int arg2); - llvm::Value *emit_gep(RaviFunctionDef *def, const char *name, llvm::Value *s, int arg1, int arg2, int arg3); - llvm::Value *emit_gep(RaviFunctionDef *def, const char *name, llvm::Value *ptr, llvm::Value *arg1, int arg2, - int arg3); - llvm::Value *emit_gep(RaviFunctionDef *def, const char *name, llvm::Value *ptr, llvm::Value *arg1, int arg2); - - // emit code for &ptr[offset] - llvm::Value *emit_array_get(RaviFunctionDef *def, llvm::Value *ptr, int offset); - - // emit code to load pointer L->ci->u.l.base - void emit_load_base(RaviFunctionDef *def); - - llvm::Value *emit_load_ci(RaviFunctionDef *def); - - // emit code to obtain address of register at location A - llvm::Value *emit_gep_register(RaviFunctionDef *def, int A); - - // emit code to obtain address of register or constant at location B - llvm::Value *emit_gep_register_or_constant(RaviFunctionDef *def, int B); - - // emit code to obtain address of constant at locatiion B - llvm::Value *emit_gep_constant(RaviFunctionDef *def, int B); - -#if 0 - llvm::Value *emit_is_jit_call(RaviFunctionDef *def, llvm::Value *ci); - llvm::Value *emit_ci_is_Lua(RaviFunctionDef *def, llvm::Value *ci); -#endif - - // obtain address of L->top - llvm::Value *emit_gep_L_top(RaviFunctionDef *def); - - // (int)(L->top - ra) - llvm::Value *emit_num_stack_elements(RaviFunctionDef *def, llvm::Value *ra); - - // Load a register or constant - if constant is int then return a direct LLVM - // constant - llvm::Value *emit_load_register_or_constant_i(RaviFunctionDef *def, int K); - - // Load a register or constant - if constant is int then return a direct LLVM - // constant - llvm::Value *emit_load_register_or_constant_n(RaviFunctionDef *def, int K); - - // emit code to load the lua_Number value from register - llvm::Instruction *emit_load_reg_n(RaviFunctionDef *def, llvm::Value *ra); - - // emit code to load the lua_Integer value from register - llvm::Instruction *emit_load_reg_i(RaviFunctionDef *def, llvm::Value *rb); - - // emit code to load the boolean value from register - llvm::Instruction *emit_load_reg_b(RaviFunctionDef *def, llvm::Value *ra); - - // emit code to load the table value from register - llvm::Instruction *emit_load_reg_h(RaviFunctionDef *def, llvm::Value *ra); - - // emit code to load the RaviArray value from register - llvm::Instruction* emit_load_reg_arr(RaviFunctionDef* def, llvm::Value* ra); - - // Gets the size of the hash table - // This is the sizenode() macro in lobject.h - llvm::Value *emit_table_get_hashsize(RaviFunctionDef *def, llvm::Value *table); - - // Gets the location of the hash node for given string key - // return value is the offset into the node array - llvm::Value *emit_table_get_hashstr(RaviFunctionDef *def, llvm::Value *table, TString *key); - - // Gets access to the Table's node array (t->node) - llvm::Value *emit_table_get_nodearray(RaviFunctionDef *def, llvm::Value *table); - - // Given a pointer to table's node array (node = t->node) and - // the location of the hashed key (index), this method retrieves the - // type of the value stored at the node - return value is of type int - // and is the type information stored in TValue->tt field. - llvm::Value *emit_table_get_keytype(RaviFunctionDef *def, llvm::Value *node, llvm::Value *index); - - // Given a pointer to table's node array (node = t->node) and - // the location of the hashed key (index), this method retrieves the - // the string value stored at the node - return value is of type TString* - llvm::Value *emit_table_get_strkey(RaviFunctionDef *def, llvm::Value *node, llvm::Value *index); - - // Given a pointer to table's node array (node = t->node) and - // the location of the hashed key (index), this method retrieves the - // the pointer to value stored at the node - return value is of type TValue* - llvm::Value *emit_table_get_value(RaviFunctionDef *def, llvm::Value *node, llvm::Value *index); - - // Gets the size of the table's array part - llvm::Value *emit_table_get_arraysize(RaviFunctionDef *def, llvm::Value *table); - - llvm::Value *emit_table_get_array(RaviFunctionDef *def, llvm::Value *table); - - llvm::Value *emit_table_no_metamethod(RaviFunctionDef *def, llvm::Value *table, TMS event); - - llvm::Instruction *emit_load_reg_s(RaviFunctionDef *def, llvm::Value *rb); - - // emit code to load pointer to int array - llvm::Instruction *emit_load_reg_h_intarray(RaviFunctionDef *def, llvm::Instruction *ra); - - // emit code to load pointer to double array - llvm::Instruction *emit_load_reg_h_floatarray(RaviFunctionDef *def, llvm::Instruction *ra); - - // emit code to store lua_Number value into register - void emit_store_reg_n(RaviFunctionDef *def, llvm::Value *value, llvm::Value *dest_ptr); - void emit_store_reg_n_withtype(RaviFunctionDef *def, llvm::Value *value, llvm::Value *dest_ptr); - - // emit code to store lua_Integer value into register - void emit_store_reg_i(RaviFunctionDef *def, llvm::Value *value, llvm::Value *dest_ptr); - void emit_store_reg_i_withtype(RaviFunctionDef *def, llvm::Value *value, llvm::Value *dest_ptr); - - // emit code to store bool value into register - void emit_store_reg_b(RaviFunctionDef *def, llvm::Value *value, llvm::Value *dest_ptr); - void emit_store_reg_b_withtype(RaviFunctionDef *def, llvm::Value *value, llvm::Value *dest_ptr); - - // emit code to set the type in the register - void emit_store_type_(RaviFunctionDef *def, llvm::Value *value, int type); - - // emit code to load the type from a register - llvm::Instruction *emit_load_type(RaviFunctionDef *def, llvm::Value *value); - - // emit code to load the array type - // Disabled as it is now broken - //llvm::Instruction *emit_load_ravi_arraytype(RaviFunctionDef *def, llvm::Value *value); - - // emit code to load the array length - llvm::Instruction *emit_load_ravi_arraylength(RaviFunctionDef *def, llvm::Value *value); - - // TValue assign - void emit_assign(RaviFunctionDef *def, llvm::Value *ra, llvm::Value *rb); - - // Get &upvals[offset] from LClosure - llvm::Value *emit_gep_upvals(RaviFunctionDef *def, int offset); - - // Load the &upvals[offset] -> result is UpVal* - llvm::Instruction *emit_load_pupval(RaviFunctionDef *def, llvm::Value *ppupval); - - // Get &upval->v - llvm::Value *emit_gep_upval_v(RaviFunctionDef *def, llvm::Instruction *pupval); - - // Load upval->v - llvm::Instruction *emit_load_upval_v(RaviFunctionDef *def, llvm::Instruction *pupval); - - // Get &upval->value -> result is TValue * - llvm::Value *emit_gep_upval_value(RaviFunctionDef *def, llvm::Instruction *pupval); - - // isnil(reg) || isboolean(reg) && reg.value == 0 - // !(isnil(reg) || isboolean(reg) && reg.value == 0) - llvm::Value *emit_boolean_testfalse(RaviFunctionDef *def, llvm::Value *reg, bool donot); - - llvm::Instruction *emit_tointeger(RaviFunctionDef *def, llvm::Value *reg); - - llvm::Instruction *emit_tofloat(RaviFunctionDef *def, llvm::Value *reg); - - // L->top = ci->top - // ci is passed as the def->ci_val may be stale - void emit_refresh_L_top(RaviFunctionDef *def, llvm::Value *ci); - - // L->top = R(B) - void emit_set_L_top_toreg(RaviFunctionDef *def, int B); - - void debug_printf(RaviFunctionDef *def, const char *str); - - void debug_printf1(RaviFunctionDef *def, const char *str, llvm::Value *arg1); - - void debug_printf2(RaviFunctionDef *def, const char *str, llvm::Value *arg1, llvm::Value *arg2); - - void debug_printf3(RaviFunctionDef *def, const char *str, llvm::Value *arg1, llvm::Value *arg2, llvm::Value *arg3); - - void debug_printf4(RaviFunctionDef *def, const char *str, llvm::Value *arg1, llvm::Value *arg2, llvm::Value *arg3, - llvm::Value *arg4); - -#if 0 - void emit_dump_stack(RaviFunctionDef *def, const char *str); - void emit_dump_stacktop(RaviFunctionDef *def, const char *str); -#endif - bool emit_debug_trace(RaviFunctionDef *def, int opCode, int pc); - - // Look for Lua bytecodes that are jump targets and allocate - // a BasicBlock for each such target in def->jump_targets. - // The BasicBlocks are not inserted into the function until later - // but having them created allows rest of the code to insert - // branch instructions - void scan_jump_targets(RaviFunctionDef *def, Proto *p); - - // Should be called before processing a Lua OpCode - // This function checks if a new block should be started - // and links in the new block - void link_block(RaviFunctionDef *def, int pc); - - void emit_CONCAT(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_CLOSURE(RaviFunctionDef *def, int A, int Bx, int pc); - - void emit_VARARG(RaviFunctionDef *def, int A, int B, int pc); - - void emit_LOADNIL(RaviFunctionDef *def, int A, int B, int pc); - - void emit_LOADFZ(RaviFunctionDef *def, int A, int pc); - - void emit_LOADIZ(RaviFunctionDef *def, int A, int pc); - - void emit_LOADBOOL(RaviFunctionDef *def, int A, int B, int C, int j, int pc); - - // Code size priority so go via function calls - void emit_ARITH_calls(RaviFunctionDef *def, int A, int B, int C, OpCode op, TMS tms, int pc); - - // integer arith priority over floating - void emit_ARITH_intpriority(RaviFunctionDef *def, int A, int B, int C, OpCode op, TMS tms, int pc); - - // floating arith priority over integer - void emit_ARITH_floatpriority(RaviFunctionDef *def, int A, int B, int C, OpCode op, TMS tms, int pc); - - inline void emit_ARITH(RaviFunctionDef *def, int A, int B, int C, OpCode op, TMS tms, int pc) { -#if RAVI_USE_LLVM_ARITH_FLOATPRIORITY - emit_ARITH_floatpriority(def, A, B, C, op, tms, pc); -#else - emit_ARITH_intpriority(def, A, B, C, op, tms, pc); -#endif - } - - void emit_MOD(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_IDIV(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_POW(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_UNM(RaviFunctionDef *def, int A, int B, int pc); - - void emit_UNMF(RaviFunctionDef *def, int A, int B, int pc); - - void emit_UNMI(RaviFunctionDef *def, int A, int B, int pc); - - void emit_ADDFF(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_ADDFI(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_ADDII(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_SUBFF(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_SUBFI(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_SUBIF(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_SUBII(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_MULFF(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_MULFI(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_MULII(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_DIVFF(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_DIVFI(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_DIVIF(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_DIVII(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_LOADK(RaviFunctionDef *def, int A, int Bx, int pc); - - void emit_RETURN(RaviFunctionDef *def, int A, int B, int pc); - - void emit_CALL(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_JMP(RaviFunctionDef *def, int A, int j, int pc); - - void emit_iFORPREP(RaviFunctionDef *def, int A, int sBx, int step_one, int pc); - - void emit_iFORLOOP(RaviFunctionDef *def, int A, int sBx, RaviBranchDef &b, int step_one, int pc); - - void emit_FORPREP(RaviFunctionDef *def, int A, int sBx, int pc); - - void emit_FORLOOP(RaviFunctionDef *def, int A, int sBx, int pc); - - void emit_FORPREP2(RaviFunctionDef *def, int A, int sBx, int pc); - - void emit_FORLOOP2(RaviFunctionDef *def, int A, int sBx, RaviBranchDef &b, int pc); - - void emit_MOVE(RaviFunctionDef *def, int A, int B, int pc); - - void emit_MOVEI(RaviFunctionDef *def, int A, int B, int pc); - - void emit_MOVEF(RaviFunctionDef *def, int A, int B, int pc); - - void emit_TOINT(RaviFunctionDef *def, int A, int pc); - - void emit_TOFLT(RaviFunctionDef *def, int A, int pc); - - void emit_TOSTRING(RaviFunctionDef *def, int A, int pc); - - void emit_TOCLOSURE(RaviFunctionDef *def, int A, int pc); - - void emit_TOTYPE(RaviFunctionDef *def, int A, int Bx, int pc); - - void emit_LEN(RaviFunctionDef *def, int A, int B, int pc); - - void emit_SETTABLE(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_SETI(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_SETFIELD(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_GETTABLE(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_GETTABLE_S(RaviFunctionDef *def, int A, int B, int C, int pc, TString *key); - - void emit_GETFIELD(RaviFunctionDef *def, int A, int B, int C, int pc, TString *key); - - void emit_GETI(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_finish_GETTABLE(RaviFunctionDef *def, llvm::Value *phi, llvm::Value *t, llvm::Value *ra, llvm::Value *rb, - llvm::Value *rc); - - void emit_SELF(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_TABLE_SELF_SK(RaviFunctionDef *def, int A, int B, int C, int pc, TString *key); - void emit_SELF_SK(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_common_GETTABLE_S(RaviFunctionDef *def, int A, int B, int C, TString *key); - - void emit_common_GETTABLE_S_(RaviFunctionDef *def, int A, llvm::Value *rb, int C, TString *key); - - void emit_GETUPVAL(RaviFunctionDef *def, int A, int B, int pc); - - void emit_SETUPVAL(RaviFunctionDef *def, int A, int B, int pc); - - void emit_SETUPVAL_Specific(RaviFunctionDef *def, int A, int B, int pc, OpCode op, llvm::Function *f); - - void emit_GETTABUP(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_GETTABUP_SK(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_SETTABUP(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_SETTABUP_SK(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_NEWARRAYINT(RaviFunctionDef *def, int A, int pc); - - void emit_NEWARRAYFLOAT(RaviFunctionDef *def, int A, int pc); - - void emit_NEWTABLE(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_SETLIST(RaviFunctionDef *def, int A, int B, int C, int pc); - - void emit_NOT(RaviFunctionDef *def, int A, int B, int pc); - - // Emit code for OP_EQ, OP_LT and OP_LE - // The callee parameter should be luaV_equalobj, luaV_lessthan and - // luaV_lessequal - // respectively - // A, B, C must be operands of the OP_EQ/OP_LT/OP_LE instructions - // j must be the jump target (offset of the code to which we need to jump to) - // jA must be the A operand of the jump instruction - void emit_EQ(RaviFunctionDef *def, int A, int B, int C, int j, int jA, llvm::Constant *callee, OpCode opCode, int pc); - - // OP_TEST is followed by a OP_JMP instruction - both are handled - // together - // A, B, C must be operands of the OP_TEST instruction - // j must be the jump target (offset of the code to which we need to jump to) - // jA must be the A operand of the jump instruction - void emit_TEST(RaviFunctionDef *def, int A, int B, int C, int j, int jA, int pc); - - // OP_TESTSET is followed by a OP_JMP instruction - both are handled - // together - // A, B, C must be operands of the OP_TESTSET instruction - // j must be the jump target (offset of the code to which we need to jump to) - // jA must be the A operand of the jump instruction - void emit_TESTSET(RaviFunctionDef *def, int A, int B, int C, int j, int jA, int pc); - - void emit_TFORCALL(RaviFunctionDef *def, int A, int B, int C, int j, int jA, int pc); - - void emit_TFORLOOP(RaviFunctionDef *def, int A, int j, int pc); - - void emit_FARRAY_GET(RaviFunctionDef *def, int A, int B, int C, bool omitArrayGetRangeCheck, int pc); - - void emit_IARRAY_GET(RaviFunctionDef *def, int A, int B, int C, bool omitArrayGetRangeCheck, int pc); - - void emit_FARRAY_SET(RaviFunctionDef *def, int A, int B, int C, bool known_int, int pc); - - void emit_IARRAY_SET(RaviFunctionDef *def, int A, int B, int C, bool known_float, int pc); - - void emit_MOVEIARRAY(RaviFunctionDef *def, int A, int B, int pc); - - void emit_MOVEFARRAY(RaviFunctionDef *def, int A, int B, int pc); - - void emit_MOVETAB(RaviFunctionDef *def, int A, int B, int pc); - - void emit_TOARRAY(RaviFunctionDef *def, int A, int array_type_expected, const char *errmsg, int pc); - - void emit_BITWISE_BINARY_OP(RaviFunctionDef *def, OpCode op, int A, int B, int C, int pc); - - void emit_BITWISE_SHIFT_OP(RaviFunctionDef *def, OpCode op, int A, int B, int C, int pc); - - void emit_BNOT_I(RaviFunctionDef *def, int A, int B, int pc); - - void emit_BOR_BXOR_BAND(RaviFunctionDef *def, OpCode op, int A, int B, int C, int pc); - - void emit_BNOT(RaviFunctionDef *def, int A, int B, int pc); - -#ifdef RAVI_DEFER_STATEMENT - void emit_DEFER(RaviFunctionDef *def, int A, int pc); -#endif - - void emit_bitwise_shiftl(RaviFunctionDef *def, llvm::Value *ra, int B, lua_Integer y); - - private: - RaviJITState *jitState_; - char temp_[31]; // for name - int id_; // for name -}; -} // namespace ravi - -struct ravi_State { - ravi::RaviJITState *jit; - ravi::RaviCodeGenerator *code_generator; -}; - -#define RaviJIT(L) ((ravi::RaviJITState *)G(L)->ravi_state->jit) - -#define RAVI_CODEGEN_FORPREP2 0 - -#endif - -#endif diff --git a/readthedocs/index.rst b/readthedocs/index.rst index c7044e0..97ac487 100644 --- a/readthedocs/index.rst +++ b/readthedocs/index.rst @@ -14,16 +14,11 @@ Contents: ravi-overview ravi-reference ravi-mir-instructions - ravi-llvm-instructions lua-introduction lua_bytecode_reference lua-parser ravi-internals ravi-jit-compilation-hook - ravi-lua-types - llvm-tbaa - ravi-benchmarks - ravi-jit-status Indices and tables diff --git a/readthedocs/llvm-notes.rst b/readthedocs/llvm-notes.rst deleted file mode 100644 index d1bfa11..0000000 --- a/readthedocs/llvm-notes.rst +++ /dev/null @@ -1,169 +0,0 @@ -LLVM Notes -========== - -The notes below apply to LLVM 3.5.1 unless noted otherwise. All reflect my understanding - so if anything here is incorrect please log an issue and I will correct. - -Structs and Unions ------------------- -LLVM does not support defining union types so we need to basically use a ``struct`` of appropriate size and cast it as we need. The main thing to be careful about is to ensure that the ``struct`` is of the same size as the ``union``. - -An example is:: - - ///* - //** Information about a call. - //** When a thread yields, 'func' is adjusted to pretend that the - //** top function has only the yielded values in its stack; in that - //** case, the actual 'func' value is saved in field 'extra'. - //** When a function calls another with a continuation, 'extra' keeps - //** the function index so that, in case of errors, the continuation - //** function can be called with the correct top. - //*/ - // typedef struct CallInfo { - // StkId func; /* function index in the stack */ - // StkId top; /* top for this function */ - // struct CallInfo *previous, *next; /* dynamic call link */ - // union { - // struct { /* only for Lua functions */ - // StkId base; /* base for this function */ - // const Instruction *savedpc; - // } l; - // struct { /* only for C functions */ - // lua_KFunction k; /* continuation in case of yields */ - // ptrdiff_t old_errfunc; - // lua_KContext ctx; /* context info. in case of yields */ - // } c; - // } u; - // ptrdiff_t extra; - // short nresults; /* expected number of results from this function */ - // lu_byte callstatus; - //} CallInfo; - -Above the union ``u`` has two members of unequal size. To handle this I created the following two sub-types of equal size - note the extra dummy field in the first type:: - - - elements.clear(); - elements.push_back(StkIdT); /* base */ - elements.push_back(pInstructionT); /* savedpc */ - elements.push_back( - C_ptrdiff_t); /* dummy to make this same size as the other member */ - CallInfo_lT = llvm::StructType::create(elements); - - elements.clear(); - elements.push_back(plua_KFunctionT); /* k */ - elements.push_back(C_ptrdiff_t); /* old_errfunc */ - elements.push_back(lua_KContextT); /* ctx */ - CallInfo_cT = llvm::StructType::create(elements); - -Then as I intend to use the ``u.l`` field more often, I used the following definition for ``CallInfo``:: - - CallInfoT = llvm::StructType::create(context, "ravi.CallInfo"); - pCallInfoT = llvm::PointerType::get(CallInfoT, 0); - elements.clear(); - elements.push_back(StkIdT); /* func */ - elements.push_back(StkIdT); /* top */ - elements.push_back(pCallInfoT); /* previous */ - elements.push_back(pCallInfoT); /* next */ - elements.push_back( - CallInfo_lT); /* u.l - as we will typically access the lua call details - */ - elements.push_back(C_ptrdiff_t); /* extra */ - elements.push_back(llvm::Type::getInt16Ty(context)); /* nresults */ - elements.push_back(lu_byteT); /* callstatus */ - CallInfoT->setBody(elements); - -JIT Compilation Error on Windows --------------------------------- -Note: The latest LLVM version from LLVM source repository appears to support COEFF format. So below -applies to version 3.6.x and 3.5.x. - -On Windows when we attempt to JIT compile we get an error saying incompatible object format -Reading posts on mailing lists I found that the issue is that COEFF -format is not supported and therefore we need to set -elf as the object -format:: - - #include "llvm/Support/Host.h" - - /* some code */ - - #ifdef _WIN32 - auto triple = llvm::sys::getProcessTriple(); - module->setTargetTriple(triple + "-elf"); - #endif - -Memory Management ------------------ -It appears that most things in LLVM are owned by the parent object and when the parent object is deleted the children go too. So in my code the main objects I delete are the ``ExecutionEngine`` and ``Module``. Once a module is associated with an engine then only the engine needs to be explicitly deleted is my understanding. - -It doesn't help that the tutorial available does not attempt to delete objects / release memory! - -MCJIT Engines, Modules and Functions ------------------------------------- -Functions live inside Modules but once a Module is finalized (compiled) then no further functions can be added to it. Although an ``MCJIT`` instance (engine) can support multiples modules, the recommendation is to ensure each module is assigned its own engine. The rationale for this is not explained. - -Struct Assign -------------- -My understanding is that to perform assignment of a struct value, one must call the intrinsic ``memcpy`` function. Example of code that does this:: - - llvm::Value *src; - llvm::Value *dest; - - // First get the declaration for the inttrinsic memcpy - llvm::SmallVector vec; - vec.push_back(def->types->C_pcharT); /* i8 */ - vec.push_back(def->types->C_pcharT); /* i8 */ - vec.push_back(def->types->C_intT); - llvm::Function *f = llvm::Intrinsic::getDeclaration( - def->raviF->module(), llvm::Intrinsic::memcpy, vec); - lua_assert(f); - - // Cast src and dest to i8* - llvm::Value *dest_ptr = - def->builder->CreateBitCast(dest, def->types->C_pcharT); - llvm::Value *src_ptr = def->builder->CreateBitCast(src, def->types->C_pcharT); - - // Create call to intrinsic memcpy - values_.clear(); - values_.push_back(dest_ptr); - values_.push_back(src_ptr); - values_.push_back(llvm::ConstantInt::get(def->types->C_intT, sizeof(TValue))); - values_.push_back( - llvm::ConstantInt::get(def->types->C_intT, sizeof(L_Umaxalign))); - values_.push_back(def->types->kFalse); - def->builder->CreateCall(f, values_); - -Note that the call to memcpy supply an alignment. - -Accessing ``extern`` functions from JIT compiled code ------------------------------------------------------ - -If the JITed function needs to access ``extern`` functions that are statically linked and not exported as dynamic symbols (e.g. in Visual C++) then we need some extra steps. -From reading posts on the subject it appears that the way to do this is to add a global mapping in the ``ExecutionEngine`` by calling the -``addGlobalMapping()`` method. However this doesn't work with MCJIT due to a bug! So we need to use a workaround. Apparently there are two -solutions: - -* Create a custom memory manager that resolves the ``extern`` functions. -* Add the symbol to the global symbols by calling ``llvm::sys::DynamicLibrary::AddSymbol()``. - -I am using the latter approach for now. - -GEP instruction ---------------- -The GEP instruction cannot compute addresses of fields in a pointer member - as the pointer needs to be 'loaded' first. This is explained in the `GEP FAQ `_. - -Hooking up Optimization Passes ------------------------------- -The LLVM documentation does not provide guidance on how the optimization passes should be hooked up. There are descriptions of what the passes do, but if you are new to LLVM and trying to work out which passes to use and in what order, then there is not much help available. The `Kaleidoscope Sample `_ shows a small example of how optimization passes may be hooked up. - -Fortunately it seems that there is a `PassManagerBuilder `_ component that allows easy setup of the standard passes for a C like language. Unfortunately there isn't much guidance on how to use this either. The best source of information I found was an example toy compiler by `David Chisnall `_. - -Links ------ -* `Mapping High Level Constructs to LLVM IR `_ -* `IRBuilder Sample `_ -* `Using MCJIT with Kaleidoscope `_ -* `Object format issue on Windows `_ -* `ExecutionEngine::addGlobalMapping() bug in MCJIT `_ -* `LLVM Notes `_ -* `Implementing Domain-Specific Languages with LLVM `_. - - diff --git a/readthedocs/llvm-tbaa.rst b/readthedocs/llvm-tbaa.rst deleted file mode 100644 index 051c738..0000000 --- a/readthedocs/llvm-tbaa.rst +++ /dev/null @@ -1,167 +0,0 @@ -LLVM Type Based Alias Analysis -============================== -When a Lua opcode involves a call to a Lua function, the Lua stack may be reallocated. So then the base pointer which points to the function's -base stack position must be refreshed. - -To keep compilation simple I coded the compiler so that at the beginning of each opcode the base pointer is reloaded. My assumption was that -the LLVM optimizer will realise that the base pointer hasn't changed and so the loads are redundant and can be removed. However to my surprise I found that this -is not the case. - -The main difference between the IR I was generating and that produced by Clang was that Clang generated IR appeared to be decorated -by tbaa metadata. Example:: - - %base2 = getelementptr inbounds %struct.CallInfoLua* %0, i32 0, i32 4, i32 0 - %1 = load %struct.TValue** %base2, align 4, !tbaa !12 - -Here the ``!tbaa !12`` refers to a tbaa metadata entry. - -I won't show the Clang generated tbaa metadata here, but here is how I added similar support in Ravi. The required steps are: - -1. Create tbaa metadata mappings for the types in the system. -2. Annotate Load and Store instructions with tbaa references. - -Creating TBAA Metadata ----------------------- -Firstly you need an MDBuilder instance. So you need to include following headers:: - - #include "llvm/IR/MDBuilder.h" - #include "llvm/IR/Metadata.h" - -We can create an MDBuilder instance like this:: - - llvm::MDBuilder mdbuilder(llvm::getGlobalContext()); - -The TBAA nodes hang off a root node. So we create that next:: - - llvm::MDNode *tbaa_root; - // Do what Clang does - tbaa_root = mdbuilder.createTBAARoot("Simple C / C++ TBAA"); - -Next we need to create some simple scalar types. We only need one type per size, so that means we don't need -``long long`` and ``double`` - either one will do. We create these scalar types as follows:: - - llvm::MDNode *tbaa_charT; - llvm::MDNode *tbaa_shortT; - llvm::MDNode *tbaa_intT; - llvm::MDNode *tbaa_longlongT; - llvm::MDNode *tbaa_pointerT; - - - //!4 = metadata !{metadata !"omnipotent char", metadata !5, i64 0} - tbaa_charT = mdbuilder.createTBAAScalarTypeNode("omnipotent char", tbaa_root, 0); - //!3 = metadata !{metadata !"any pointer", metadata !4, i64 0} - tbaa_pointerT = mdbuilder.createTBAAScalarTypeNode("any pointer", tbaa_charT, 0); - //!10 = metadata !{metadata !"short", metadata !4, i64 0} - tbaa_shortT = mdbuilder.createTBAAScalarTypeNode("short", tbaa_charT, 0); - //!11 = metadata !{metadata !"int", metadata !4, i64 0} - tbaa_intT = mdbuilder.createTBAAScalarTypeNode("int", tbaa_charT, 0); - //!9 = metadata !{metadata !"long long", metadata !4, i64 0} - tbaa_longlongT = mdbuilder.createTBAAScalarTypeNode("long long", tbaa_charT, 0); - - -The second argument to ``createTBAAScalarTypeNode()`` is the parent node. Note the hierarchy here:: - - + root - | - +--+ char - | - +--+-- any pointer - | - +-- short - | - +-- int - | - +-- long long - -This is how Clang has it defined. - -Next we need to define aggregate (struct) types. The API we need for this is ``createTBAAStructTypeNode()``. -This method accepts a vector of ``std::pair`` objects - each element in the vector defines -a field in the struct. The integer parameter needs to be the offset of the field within the struct. Interestingly -Clang generates offsets that indicate pointers are being treated as 32-bit quantities - even though I ran this on -a 64-bit machine. So I guess that as long as we consistently use the size then this doesn't matter. The sizes used -by Clang are: - -* char - 1 byte -* short - 2 bytes -* int - 4 bytes -* pointer - 4 bytes -* long long - 8 bytes - -Another interesting thing is that padding needs to be accounted for. - -So now lets look at how to map following struct:: - - struct CallInfoL { /* only for Lua functions */ - struct TValue *base; /* base for this function */ - const unsigned int *savedpc; - ptrdiff_t dummy; - }; - -We map this as:: - - llvm::MDNode *tbaa_CallInfo_lT; - - //!14 = metadata !{metadata !"CallInfoL", metadata !3, i64 0, metadata !3, i64 4, metadata !9, i64 8} - std::vector > nodes; - nodes.push_back(std::pair(tbaa_pointerT, 0)); - nodes.push_back(std::pair(tbaa_pointerT, 4)); - nodes.push_back(std::pair(tbaa_longlongT, 8)); - tbaa_CallInfo_lT = mdbuilder.createTBAAStructTypeNode("CallInfo_l", nodes); - -To illustrate how a structure is referenced as a field in another lets also look at:: - - - struct CallInfo { - struct TValue *func; /* function index in the stack */ - struct TValue *top; /* top for this function */ - struct CallInfo *previous, *next; /* dynamic call link */ - struct CallInfoL l; - ptrdiff_t extra; - short nresults; /* expected number of results from this function */ - unsigned char callstatus; - }; - -We have a ``CallInfoL`` as the type of a field within the struct. Therefore:: - - llvm::MDNode *tbaa_CallInfoT; - - //!13 = metadata !{metadata !"CallInfo", - // metadata !3, i64 0, metadata !3, i64 4, metadata !3, i64 8, - // metadata !3, i64 12, metadata !14, i64 16, metadata !9, i64 32, - // metadata !10, i64 40, metadata !4, i64 42} - nodes.clear(); - nodes.push_back(std::pair(tbaa_pointerT, 0)); - nodes.push_back(std::pair(tbaa_pointerT, 4)); - nodes.push_back(std::pair(tbaa_pointerT, 8)); - nodes.push_back(std::pair(tbaa_pointerT, 12)); - nodes.push_back(std::pair(tbaa_CallInfo_lT, 16)); - nodes.push_back(std::pair(tbaa_longlongT, 32)); - nodes.push_back(std::pair(tbaa_shortT, 40)); - nodes.push_back(std::pair(tbaa_charT, 42)); - tbaa_CallInfoT = mdbuilder.createTBAAStructTypeNode("CallInfo", nodes); - -Decorating Load and Store instructions --------------------------------------- - -So now we have created TBAA metadata for two struct types. -Next we need to see how we use these in Load and Store instructions. Lets assume we need to load the pointer -stored in ``Callinfo.top``. In order to decorate the Load instruction with tbaa we need to create -a Struct Tag Node - which is like a path node. Here it is:: - - llvm::MDNode *tbaa_CallInfo_topT; - tbaa_CallInfo_topT = mdbuilder.createTBAAStructTagNode(tbaa_CallInfoT, tbaa_pointerT, 4); - -Above is saying that the field ``top`` in struct ``CallInfo`` is a pointer at offset 4. - -Armed with this we can code:: - - llvm::Value *callinfo_top = /* GEP instruction */ - llvm::Instruction *top = Builder.CreateLoad(callinfo_top); - top->setMetadata(llvm::LLVMContext::MD_tbaa, tbaa_CallInfo_topT); - -Links ------ -* `TypeBasedAliasAnalysis code `_. -* `IR documentation on tbaa metadata `_. -* `Embedded metadata `_. \ No newline at end of file diff --git a/readthedocs/ravi-jit-initial.rst b/readthedocs/ravi-jit-initial.rst deleted file mode 100644 index afca345..0000000 --- a/readthedocs/ravi-jit-initial.rst +++ /dev/null @@ -1,222 +0,0 @@ -LLVM First Steps -================ - -Note that the discussion below is for LLVM 3.5.1. - -Although there appears to be a lot of documentation in the LLVM site surprisingly some basic information is hard to find. -The main source of guidance for creating a JIT is in the example toy language -`Kaleidoscope `_. But here too -there are several versions - so you have to pick the right version that is compatible with the LLVM version you -are using. - -A Lua JITed function will execute in the context of Lua. So it needs to be able to access the ``lua_State`` and its various -structures. So I wanted a sample that demonstrates passing a pointer to a structure and accessing it within the JITed -function. - -The initial test program I created is meant to be a "hello world" type test but covering the functionility described above. -The test I want to run is:: - - // Creating a function that takes pointer to struct as argument - // The function gets value from one of the fields in the struct - // And returns it - // The equivalent C program is: - // - // extern int printf(const char *, ...); - // - // struct GCObject { - // struct GCObject *next; - // unsigned char a; - // unsigned char b; - // }; - // - // int testfunc(struct GCObject *obj) { - // printf("value = %d\n", obj->a); - // return obj->a; - // } - -You can view the test program at `test_llvm.cpp `_. -It is also reproduced below. - -I used the new ``MCJIT`` engine in my test. It seems that this engine compiles modules rather than individual -functions - and once compiled a module cannot be modified. So in the Lua context we need to create a new module -everytime we JIT compile a function - or alternatively we JIT compile a whole Lua source file including all its -functions into a single module. - -I found the blog post `Using MCJIT with Kaleidoscope -`_ useful in understanding some -finer points about using ``MCJIT``. - -The Lua GCObject structure in lobject.h we need is:: - - typedef struct RaviGCObject { - struct RaviGCObject *next; - unsigned char b1; - unsigned char b2; - } RaviGCObject; - -Our prototype for the JITted function:: - - typedef int (*myfunc_t)(RaviGCObject *); - -Get global context - not sure what the impact is of sharing:: - - llvm::LLVMContext &context = llvm::getGlobalContext(); - -Module is the translation unit:: - - std::unique_ptr theModule = - std::unique_ptr(new llvm::Module("ravi", context)); - llvm::Module *module = theModule.get(); - llvm::IRBuilder<> builder(context); - -On Windows we get error saying incompatible object format -Reading posts on mailining lists I found that the issue is that COEFF -format is not supported and therefore we need to set -elf as the object -format:: - - #ifdef _WIN32 - auto triple = llvm::sys::getProcessTriple(); - module->setTargetTriple(triple + "-elf"); - #endif - -create a GCObject structure as defined in lobject.h:: - - llvm::StructType *structType = - llvm::StructType::create(context, "RaviGCObject"); - llvm::PointerType *pstructType = - llvm::PointerType::get(structType, 0); // pointer to RaviGCObject - std::vector elements; - elements.push_back(pstructType); - elements.push_back(llvm::Type::getInt8Ty(context)); - elements.push_back(llvm::Type::getInt8Ty(context)); - structType->setBody(elements); - structType->dump(); - -Create printf declaration:: - - std::vector args; - args.push_back(llvm::Type::getInt8PtrTy(context)); - // accepts a char*, is vararg, and returns int - llvm::FunctionType *printfType = - llvm::FunctionType::get(builder.getInt32Ty(), args, true); - llvm::Constant *printfFunc = - module->getOrInsertFunction("printf", printfType); - -Create the testfunc():: - - args.clear(); - args.push_back(pstructType); - llvm::FunctionType *funcType = - llvm::FunctionType::get(builder.getInt32Ty(), args, false); - llvm::Function *mainFunc = llvm::Function::Create( - funcType, llvm::Function::ExternalLinkage, "testfunc", module); - llvm::BasicBlock *entry = - llvm::BasicBlock::Create(context, "entrypoint", mainFunc); - builder.SetInsertPoint(entry); - -The printf format string:: - - llvm::Value *formatStr = builder.CreateGlobalStringPtr("value = %d\n"); - -Get the first argument which is RaviGCObject *:: - - auto argiter = mainFunc->arg_begin(); - llvm::Value *arg1 = argiter++; - arg1->setName("obj"); - -Now we need a GEP for the second field in RaviGCObject:: - - std::vector values; - llvm::APInt zero(32, 0); - llvm::APInt one(32, 1); - // This is the array offset into RaviGCObject* - values.push_back( - llvm::Constant::getIntegerValue(llvm::Type::getInt32Ty(context), zero)); - // This is the field offset - values.push_back( - llvm::Constant::getIntegerValue(llvm::Type::getInt32Ty(context), one)); - -Create the GEP value:: - - llvm::Value *arg1_a = builder.CreateGEP(arg1, values, "ptr"); - -Now retrieve the data from the pointer address:: - - llvm::Value *tmp1 = builder.CreateLoad(arg1_a, "a"); - -As the retrieved value is a byte - convert to int i:: - - llvm::Value *tmp2 = - builder.CreateZExt(tmp1, llvm::Type::getInt32Ty(context), "i"); - -Call the printf function:: - - values.clear(); - values.push_back(formatStr); - values.push_back(tmp2); - builder.CreateCall(printfFunc, values); - -return i:: - - builder.CreateRet(tmp2); - module->dump(); - -Lets create the MCJIT engine:: - - std::string errStr; - auto engine = llvm::EngineBuilder(module) - .setErrorStr(&errStr) - .setEngineKind(llvm::EngineKind::JIT) - .setUseMCJIT(true) - .create(); - if (!engine) { - llvm::errs() << "Failed to construct MCJIT ExecutionEngine: " << errStr - << "\n"; - return 1; - } - -Now lets compile our function into machine code:: - - std::string funcname = "testfunc"; - myfunc_t funcptr = (myfunc_t)engine->getFunctionAddress(funcname); - if (funcptr == nullptr) { - llvm::errs() << "Failed to obtain compiled function\n"; - return 1; - } - -Run the function and test results:: - - RaviGCObject obj = {NULL, 42, 65}; - int ans = funcptr(&obj); - printf("The answer is %d\n", ans); - return ans == 42 ? 0 : 1; - - -Accessing ``extern`` functions from JIT compiled code ------------------------------------------------------ - -The JITed function needs to access ``extern`` Lua functions. We need a way to map these to make these visible to the JITed code. Simply declaring -the functions ``extern`` only appears to work if the functios are available as exported symbols in dynamic libraries, e.g. the call to -``printf`` above. - -From reading posts on the subject it appears that the way to do this is to add a global mapping in the ``ExecutionEngine`` by calling the -``addGlobalMapping()`` method. However this doesn't work with MCJIT due to a bug! So we need to use a workaround. Apparently there are two -solutions: - -* Create a custom memory manager that resolves the ``extern`` functions. -* Add the symbol to the global symbols by calling ``llvm::sys::DynamicLibrary::AddSymbol()``. - -I am using the latter approach for now. - -Memory Management in LLVM -------------------------- -Curiously LLVM docs do not say much about how memory should be managed. I am still trying to figure this out, but in general it seems that there is -hierarchy of ownership. Example: ``ExecutionEngine`` owns the ``Module``. By deleting the parent the 'owned' objects are automatically -deleted. - - -Links ------ -* `Object format issue on Windows `_ -* `ExecutionEngine::addGlobalMapping() bug in MCJIT `_ -* `LLVM Notes `_ diff --git a/readthedocs/ravi-llvm-instructions.rst b/readthedocs/ravi-llvm-instructions.rst deleted file mode 100644 index a2f99ae..0000000 --- a/readthedocs/ravi-llvm-instructions.rst +++ /dev/null @@ -1,160 +0,0 @@ -=================================== -Building Ravi with LLVM JIT backend -=================================== - -.. contents:: Table of Contents - :depth: 2 - :backlinks: top - -Quick build without JIT -======================= -A Makefile is supplied for a simple build without the JIT on Unix platforms. Just run ``make`` and follow instructions. You may need to customize the Makefiles. - -For building Ravi with JIT options please read on. - -Build Dependencies -================== - -* `CMake `_ is required -* On Windows you will need Visual Studio 2017 Community edition -* LLVM versions >= 3.5 - -LLVM JIT Backend -================ -Following versions of LLVM work with Ravi. - -* LLVM 3.7, 3.8, 3.9, 4.0, 5.0, 6.0, 8.0.1, 9.0.1, 10.0 -* LLVM 7.0 was skipped because of unstable ORC api changes -* LLVM 3.5 and 3.6 should also work but have not been recently tested - -Unless otherwise noted the instructions below should work for LLVM 3.9 and later. - -Since LLVM 5.0 Ravi has begun to use the new ORC JIT apis. These apis are more memory efficient -compared to the MCJIT apis because they release the Module IR as early as possible, whereas with -MCJIT the Module IR hangs around as long as the compiled code is held. Because of this significant -improvement, I recommend using the latest version of LLVM. - -Building LLVM on Windows ------------------------- -I built LLVM from source. I used the following sequence from the VS2017 command window:: - - mkdir build - cd build - cmake -DCMAKE_INSTALL_PREFIX=c:\Software\llvm801 -DLLVM_TARGETS_TO_BUILD="X86" -G "Visual Studio 15 2017 Win64" .. - -I then opened the generated solution in VS2017 and performed a INSTALL build from there. Above will build the 64-bit version of LLVM libraries. To build a 32-bit version omit the ``Win64`` parameter. - -.. note:: Note that if you perform a **Release** build of LLVM then you will also need to do a **Release** build of Ravi otherwise you will get link errors. Ditto for **Debug** builds. - -Building LLVM on Ubuntu or Redhat ---------------------------------- -The approach is similar to that described for MAC OS X below. - -Building LLVM on MAC OS X -------------------------- -I am using Max OSX Mojave. Pre-requisites are XCode and CMake. -Ensure cmake is on the path. -Assuming that LLVM source has been extracted to ``$HOME/llvm-8.0.1.src`` I follow these steps:: - - cd $HOME/llvm-8.0.1.src - mkdir build - cd build - cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$HOME/Software//llvm801 -DLLVM_TARGETS_TO_BUILD="X86" .. - make install - -Building Ravi with LLVM JIT backend enabled -------------------------------------------- -I am developing Ravi using Visual Studio 2017 Community Edition on Windows 10 64bit, gcc on Linux 64-bit, and clang/Xcode on MAC OS X. I was also able to successfully build a Ubuntu version on Windows 10 using the newly released Ubuntu/Linux sub-system for Windows 10. - -.. note:: Location of cmake files prior to LLVM 3.9 was ``$LLVM_INSTALL_DIR/share/llvm/cmake``. - -Assuming that LLVM has been installed as described above, then on Windows I invoke the cmake config as follows:: - - cd build - cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=c:\Software\ravi -DLLVM_DIR=c:\Software\llvm801\lib\cmake\llvm -G "Visual Studio 15 2017 Win64" .. - -I then open the solution in VS2017 and do a build from there. - -On Ubuntu I use:: - - cd build - cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/Software/ravi -DLLVM_DIR=$HOME/Software/llvm801/lib/cmake/llvm -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" .. - make install - -Note that on a clean install of Ubuntu 15.10 I had to install following packages: - -* cmake -* git -* libreadline-dev - -On MAC OS X I use:: - - cd build - cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/Software/ravi -DLLVM_DIR=$HOME/Software/llvm801/lib/cmake/llvm -DCMAKE_BUILD_TYPE=Release .. - make install - - -Building without JIT -==================== -You can omit ``-DLLVM_JIT=ON`` options to build Ravi with a null JIT implementation. - -Building Static Libraries -========================= -By default the build generates a shared library for Ravi. You can choose to create a static library and statically linked executables by supplying the argument ``-DSTATIC_BUILD=ON`` to CMake. - -JIT API -------- -auto mode - in this mode the compiler decides when to compile a Lua function. The current implementation is very simple - - any Lua function call is checked to see if the bytecodes contained in it can be compiled. If this is true then - the function is compiled provided either a) function has a fornum loop, or b) it is largish (greater than 150 bytecodes) - or c) it is being executed many times (> 50). Because of the simplistic behaviour performance the benefit of JIT - compilation is only available if the JIT compiled functions will be executed many times so that the cost of JIT - compilation can be amortized. -manual mode - in this mode user must explicitly request compilation. This is the default mode. This mode is suitable for library - developers who can pre compile the functions in library module table. - -A JIT api is available with following functions: - -``ravi.jit([b])`` - returns enabled setting of JIT compiler; also enables/disables the JIT compiler; defaults to true -``ravi.auto([b [, min_size [, min_executions]]])`` - returns setting of auto compilation and compilation thresholds; also sets the new settings if values are supplied; defaults are false, 150, 50. -``ravi.compile(func_or_table[, options])`` - compiles a Lua function (or functions if a table is supplied) if possible, returns ``true`` if compilation was - successful for at least one function. ``options`` is an optional table with compilation options - in particular - ``omitArrayGetRangeCheck`` - which disables range checks in array get operations to improve performance in some cases. - Note that at present if the first argument is a table of functions and has more than 100 functions then only the - first 100 will be compiled. You can invoke compile() repeatedly on the table until it returns false. Each - invocation leads to a new module being created; any functions already compiled are skipped. -``ravi.iscompiled(func)`` - returns the JIT status of a function -``ravi.dumplua(func)`` - dumps the Lua bytecode of the function -``ravi.dumpir(func)`` - dumps the IR of the compiled function (only if function was compiled; only available in LLVM 4.0 and earlier) -``ravi.dumpasm(func)`` - (deprecated) dumps the machine code using the currently set optimization level (only if function was compiled; only available in LLVM version 4.0 and earlier) -``ravi.optlevel([n])`` - sets LLVM optimization level (0, 1, 2, 3); defaults to 2. These levels are handled by reusing LLVMs default pass definitions which are geared towards C/C++ programs, but appear to work well here. If level is set to 0, then an attempt is made to use fast instruction selection to further speed up compilation. -``ravi.sizelevel([n])`` - sets LLVM size level (0, 1, 2); defaults to 0 -``ravi.tracehook([b])`` - Enables support for line hooks via the debug api. Note that enabling this option will result in inefficient JIT as a call to a C function will be inserted at beginning of every Lua bytecode boundary; use this option only when you want to use the debug api to step through code line by line -``ravi.verbosity([b])`` - Controls the amount of verbose messages generated during compilation. - -Performance -=========== -For performance benchmarks please visit the `Ravi Performance Benchmarks `_ page. - -To obtain the best possible performance, types must be annotated so that Ravi's JIT compiler can generate efficient code. -Additionally function calls are expensive - as the JIT compiler cannot inline function calls, all function calls go via the Lua call protocol which has a large overhead. This is true for both Lua functions and C functions. For best performance avoid function calls inside loops. - -Testing -======= -I test the build by running a modified version of Lua 5.3.3 test suite. These tests are located in the ``lua-tests`` folder. Additionally I have ravi specific tests in the ``ravi-tests`` folder. There is a also a travis build that occurs upon commits - this build runs the tests as well. - -.. note:: To thoroughly test changes, you need to invoke CMake with ``-DCMAKE_BUILD_TYPE=Debug`` option. This turns on assertions, memory checking, and also enables an internal module used by Lua tests. - diff --git a/readthedocs/ravi-lua-types.rst b/readthedocs/ravi-lua-types.rst deleted file mode 100644 index baa953a..0000000 --- a/readthedocs/ravi-lua-types.rst +++ /dev/null @@ -1,707 +0,0 @@ -Lua Types in LLVM -================= - -We need to map Lua types to equivalent type definitions in LLVM. In Ravi we do hold all the type definitions in a struct as shown below:: - - struct LuaLLVMTypes { - - llvm::Type *C_intptr_t; - llvm::Type *C_size_t; - llvm::Type *C_ptrdiff_t; - - llvm::Type *lua_NumberT; - llvm::Type *lua_IntegerT; - llvm::Type *lua_UnsignedT; - llvm::Type *lua_KContextT; - - llvm::FunctionType *lua_CFunctionT; - llvm::PointerType *plua_CFunctionT; - - llvm::FunctionType *lua_KFunctionT; - llvm::PointerType *plua_KFunctionT; - - llvm::FunctionType *lua_HookT; - llvm::PointerType *plua_HookT; - - llvm::FunctionType *lua_AllocT; - llvm::PointerType *plua_AllocT; - - llvm::Type *l_memT; - llvm::Type *lu_memT; - - llvm::Type *lu_byteT; - llvm::Type *L_UmaxalignT; - llvm::Type *C_pcharT; - - llvm::Type *C_intT; - - llvm::StructType *lua_StateT; - llvm::PointerType *plua_StateT; - - llvm::StructType *global_StateT; - llvm::PointerType *pglobal_StateT; - - llvm::StructType *ravi_StateT; - llvm::PointerType *pravi_StateT; - - llvm::StructType *GCObjectT; - llvm::PointerType *pGCObjectT; - - llvm::StructType *ValueT; - llvm::StructType *TValueT; - llvm::PointerType *pTValueT; - - llvm::StructType *TStringT; - llvm::PointerType *pTStringT; - llvm::PointerType *ppTStringT; - - llvm::StructType *UdataT; - llvm::StructType *TableT; - llvm::PointerType *pTableT; - - llvm::StructType *UpvaldescT; - llvm::PointerType *pUpvaldescT; - - llvm::Type *ravitype_tT; - llvm::StructType *LocVarT; - llvm::PointerType *pLocVarT; - - llvm::Type *InstructionT; - llvm::PointerType *pInstructionT; - llvm::StructType *LClosureT; - llvm::PointerType *pLClosureT; - llvm::PointerType *ppLClosureT; - llvm::PointerType *pppLClosureT; - - llvm::StructType *RaviJITProtoT; - llvm::PointerType *pRaviJITProtoT; - - llvm::StructType *ProtoT; - llvm::PointerType *pProtoT; - llvm::PointerType *ppProtoT; - - llvm::StructType *UpValT; - llvm::PointerType *pUpValT; - - llvm::StructType *CClosureT; - llvm::PointerType *pCClosureT; - - llvm::StructType *TKeyT; - llvm::PointerType *pTKeyT; - - llvm::StructType *NodeT; - llvm::PointerType *pNodeT; - - llvm::StructType *lua_DebugT; - llvm::PointerType *plua_DebugT; - - llvm::StructType *lua_longjumpT; - llvm::PointerType *plua_longjumpT; - - llvm::StructType *MbufferT; - llvm::StructType *stringtableT; - - llvm::PointerType *StkIdT; - - llvm::StructType *CallInfoT; - llvm::StructType *CallInfo_cT; - llvm::StructType *CallInfo_lT; - llvm::PointerType *pCallInfoT; - - llvm::FunctionType *jitFunctionT; - - llvm::FunctionType *luaD_poscallT; - - }; - -The actual definition of the types above is shown below:: - - static_assert(std::is_floating_point::value && - sizeof(lua_Number) == sizeof(double), - "lua_Number is not a double"); - lua_NumberT = llvm::Type::getDoubleTy(context); - - static_assert(std::is_integral::value, - "lua_Integer is not an integer type"); - lua_IntegerT = llvm::Type::getIntNTy(context, sizeof(lua_Integer) * 8); - - static_assert(sizeof(lua_Integer) == sizeof(lua_Unsigned), - "lua_Integer and lua_Unsigned are of different size"); - lua_UnsignedT = lua_IntegerT; - - C_intptr_t = llvm::Type::getIntNTy(context, sizeof(intptr_t) * 8); - C_size_t = llvm::Type::getIntNTy(context, sizeof(size_t) * 8); - C_ptrdiff_t = llvm::Type::getIntNTy(context, sizeof(ptrdiff_t) * 8); - C_intT = llvm::Type::getIntNTy(context, sizeof(int) * 8); - - static_assert(sizeof(size_t) == sizeof(lu_mem), - "lu_mem size is not same as size_t"); - lu_memT = C_size_t; - - static_assert(sizeof(ptrdiff_t) == sizeof(l_mem), - "l_mem size is not same as ptrdiff_t"); - l_memT = C_ptrdiff_t; - - static_assert(sizeof(L_Umaxalign) == sizeof(double), - "L_Umaxalign is not same size as double"); - L_UmaxalignT = llvm::Type::getDoubleTy(context); - - lu_byteT = llvm::Type::getInt8Ty(context); - C_pcharT = llvm::Type::getInt8PtrTy(context); - - InstructionT = C_intT; - pInstructionT = llvm::PointerType::get(InstructionT, 0); - - lua_StateT = llvm::StructType::create(context, "ravi.lua_State"); - plua_StateT = llvm::PointerType::get(lua_StateT, 0); - - lua_KContextT = C_ptrdiff_t; - - std::vector elements; - elements.push_back(plua_StateT); - lua_CFunctionT = llvm::FunctionType::get(C_intT, elements, false); - plua_CFunctionT = llvm::PointerType::get(lua_CFunctionT, 0); - - jitFunctionT = lua_CFunctionT; - - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(C_intT); - elements.push_back(lua_KContextT); - lua_KFunctionT = llvm::FunctionType::get(C_intT, elements, false); - plua_KFunctionT = llvm::PointerType::get(lua_KFunctionT, 0); - - elements.clear(); - elements.push_back(llvm::Type::getInt8PtrTy(context)); - elements.push_back(llvm::Type::getInt8PtrTy(context)); - elements.push_back(C_size_t); - elements.push_back(C_size_t); - lua_AllocT = llvm::FunctionType::get(llvm::Type::getInt8PtrTy(context), - elements, false); - plua_AllocT = llvm::PointerType::get(lua_AllocT, 0); - - lua_DebugT = llvm::StructType::create(context, "ravi.lua_Debug"); - plua_DebugT = llvm::PointerType::get(lua_DebugT, 0); - - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(plua_DebugT); - lua_HookT = llvm::FunctionType::get(llvm::Type::getInt8PtrTy(context), - elements, false); - plua_HookT = llvm::PointerType::get(lua_HookT, 0); - - // struct GCObject { - // GCObject *next; - // lu_byte tt; - // lu_byte marked - // }; - GCObjectT = llvm::StructType::create(context, "ravi.GCObject"); - pGCObjectT = llvm::PointerType::get(GCObjectT, 0); - elements.clear(); - elements.push_back(pGCObjectT); - elements.push_back(lu_byteT); - elements.push_back(lu_byteT); - GCObjectT->setBody(elements); - - static_assert(sizeof(Value) == sizeof(lua_Number), - "Value type is larger than lua_Number"); - // In LLVM unions should be set to the largest member - // So in the case of a Value this is the double type - // union Value { - // GCObject *gc; /* collectable objects */ - // void *p; /* light userdata */ - // int b; /* booleans */ - // lua_CFunction f; /* light C functions */ - // lua_Integer i; /* integer numbers */ - // lua_Number n; /* float numbers */ - // }; - ValueT = llvm::StructType::create(context, "ravi.Value"); - elements.clear(); - elements.push_back(lua_NumberT); - ValueT->setBody(elements); - - // struct TValue { - // union Value value_; - // int tt_; - // }; - TValueT = llvm::StructType::create(context, "ravi.TValue"); - elements.clear(); - elements.push_back(ValueT); - elements.push_back(C_intT); - TValueT->setBody(elements); - pTValueT = llvm::PointerType::get(TValueT, 0); - - StkIdT = pTValueT; - - ///* - //** Header for string value; string bytes follow the end of this structure - //** (aligned according to 'UTString'; see next). - //*/ - // typedef struct TString { - // GCObject *next; - // lu_byte tt; - // lu_byte marked - // lu_byte extra; /* reserved words for short strings; "has hash" for longs - // */ - // unsigned int hash; - // size_t len; /* number of characters in string */ - // struct TString *hnext; /* linked list for hash table */ - // } TString; - - ///* - //** Ensures that address after this type is always fully aligned. - //*/ - // typedef union UTString { - // L_Umaxalign dummy; /* ensures maximum alignment for strings */ - // TString tsv; - //} UTString; - TStringT = llvm::StructType::create(context, "ravi.TString"); - pTStringT = llvm::PointerType::get(TStringT, 0); - ppTStringT = llvm::PointerType::get(pTStringT, 0); - elements.clear(); - elements.push_back(pGCObjectT); - elements.push_back(lu_byteT); - elements.push_back(lu_byteT); - elements.push_back(lu_byteT); /* extra */ - elements.push_back(C_intT); /* hash */ - elements.push_back(C_size_t); /* len */ - elements.push_back(pTStringT); /* hnext */ - TStringT->setBody(elements); - - // Table - TableT = llvm::StructType::create(context, "ravi.Table"); - pTableT = llvm::PointerType::get(TableT, 0); - - ///* - //** Header for userdata; memory area follows the end of this structure - //** (aligned according to 'UUdata'; see next). - //*/ - // typedef struct Udata { - // GCObject *next; - // lu_byte tt; - // lu_byte marked - // lu_byte ttuv_; /* user value's tag */ - // struct Table *metatable; - // size_t len; /* number of bytes */ - // union Value user_; /* user value */ - //} Udata; - UdataT = llvm::StructType::create(context, "ravi.Udata"); - elements.clear(); - elements.push_back(pGCObjectT); - elements.push_back(lu_byteT); - elements.push_back(lu_byteT); - elements.push_back(lu_byteT); /* ttuv_ */ - elements.push_back(pTableT); /* metatable */ - elements.push_back(C_size_t); /* len */ - elements.push_back(ValueT); /* user_ */ - UdataT->setBody(elements); - - ///* - //** Description of an upvalue for function prototypes - //*/ - // typedef struct Upvaldesc { - // TString *name; /* upvalue name (for debug information) */ - // lu_byte instack; /* whether it is in stack */ - // lu_byte idx; /* index of upvalue (in stack or in outer function's list) - // */ - //}Upvaldesc; - UpvaldescT = llvm::StructType::create(context, "ravi.Upvaldesc"); - elements.clear(); - elements.push_back(pTStringT); - elements.push_back(lu_byteT); - elements.push_back(lu_byteT); - UpvaldescT->setBody(elements); - pUpvaldescT = llvm::PointerType::get(UpvaldescT, 0); - - ///* - //** Description of a local variable for function prototypes - //** (used for debug information) - //*/ - // typedef struct LocVar { - // TString *varname; - // int startpc; /* first point where variable is active */ - // int endpc; /* first point where variable is dead */ - // ravitype_t ravi_type; /* RAVI type of the variable - RAVI_TANY if unknown - // */ - //} LocVar; - ravitype_tT = llvm::Type::getIntNTy(context, sizeof(ravitype_t) * 8); - LocVarT = llvm::StructType::create(context, "ravi.LocVar"); - elements.clear(); - elements.push_back(pTStringT); /* varname */ - elements.push_back(C_intT); /* startpc */ - elements.push_back(C_intT); /* endpc */ - elements.push_back(ravitype_tT); /* ravi_type */ - LocVarT->setBody(elements); - pLocVarT = llvm::PointerType::get(LocVarT, 0); - - LClosureT = llvm::StructType::create(context, "ravi.LClosure"); - pLClosureT = llvm::PointerType::get(LClosureT, 0); - ppLClosureT = llvm::PointerType::get(pLClosureT, 0); - pppLClosureT = llvm::PointerType::get(ppLClosureT, 0); - - RaviJITProtoT = llvm::StructType::create(context, "ravi.RaviJITProto"); - pRaviJITProtoT = llvm::PointerType::get(RaviJITProtoT, 0); - - ///* - //** Function Prototypes - //*/ - // typedef struct Proto { - // CommonHeader; - // lu_byte numparams; /* number of fixed parameters */ - // lu_byte is_vararg; - // lu_byte maxstacksize; /* maximum stack used by this function */ - // int sizeupvalues; /* size of 'upvalues' */ - // int sizek; /* size of 'k' */ - // int sizecode; - // int sizelineinfo; - // int sizep; /* size of 'p' */ - // int sizelocvars; - // int linedefined; - // int lastlinedefined; - // TValue *k; /* constants used by the function */ - // Instruction *code; - // struct Proto **p; /* functions defined inside the function */ - // int *lineinfo; /* map from opcodes to source lines (debug information) */ - // LocVar *locvars; /* information about local variables (debug information) - // */ - // Upvaldesc *upvalues; /* upvalue information */ - // struct LClosure *cache; /* last created closure with this prototype */ - // TString *source; /* used for debug information */ - // GCObject *gclist; - // /* RAVI */ - // RaviJITProto *ravi_jit; - //} Proto; - - ProtoT = llvm::StructType::create(context, "ravi.Proto"); - pProtoT = llvm::PointerType::get(ProtoT, 0); - ppProtoT = llvm::PointerType::get(pProtoT, 0); - elements.clear(); - elements.push_back(pGCObjectT); - elements.push_back(lu_byteT); - elements.push_back(lu_byteT); - elements.push_back(lu_byteT); /* numparams */ - elements.push_back(lu_byteT); /* is_vararg */ - elements.push_back(lu_byteT); /* maxstacksize */ - elements.push_back(C_intT); /* sizeupvalues */ - elements.push_back(C_intT); /* sizek */ - elements.push_back(C_intT); /* sizecode */ - elements.push_back(C_intT); /* sizelineinfo */ - elements.push_back(C_intT); /* sizep */ - elements.push_back(C_intT); /* sizelocvars */ - elements.push_back(C_intT); /* linedefined */ - elements.push_back(C_intT); /* lastlinedefined */ - elements.push_back(pTValueT); /* k */ - elements.push_back(pInstructionT); /* code */ - elements.push_back(ppProtoT); /* p */ - elements.push_back(llvm::PointerType::get(C_intT, 0)); /* lineinfo */ - elements.push_back(pLocVarT); /* locvars */ - elements.push_back(pUpvaldescT); /* upvalues */ - elements.push_back(pLClosureT); /* cache */ - elements.push_back(pTStringT); /* source */ - elements.push_back(pGCObjectT); /* gclist */ - elements.push_back(pRaviJITProtoT); /* ravi_jit */ - ProtoT->setBody(elements); - - ///* - //** Lua Upvalues - //*/ - // typedef struct UpVal UpVal; - UpValT = llvm::StructType::create(context, "ravi.UpVal"); - pUpValT = llvm::PointerType::get(UpValT, 0); - - ///* - //** Closures - //*/ - - //#define ClosureHeader \ - //CommonHeader; lu_byte nupvalues; GCObject *gclist - - // typedef struct CClosure { - // ClosureHeader; - // lua_CFunction f; - // TValue upvalue[1]; /* list of upvalues */ - //} CClosure; - - CClosureT = llvm::StructType::create(context, "ravi.CClosure"); - elements.clear(); - elements.push_back(pGCObjectT); - elements.push_back(lu_byteT); - elements.push_back(lu_byteT); - elements.push_back(lu_byteT); /* nupvalues */ - elements.push_back(pGCObjectT); /* gclist */ - elements.push_back(plua_CFunctionT); /* f */ - elements.push_back(llvm::ArrayType::get(TValueT, 1)); - CClosureT->setBody(elements); - pCClosureT = llvm::PointerType::get(CClosureT, 0); - - // typedef struct LClosure { - // ClosureHeader; - // struct Proto *p; - // UpVal *upvals[1]; /* list of upvalues */ - //} LClosure; - elements.clear(); - elements.push_back(pGCObjectT); - elements.push_back(lu_byteT); - elements.push_back(lu_byteT); - elements.push_back(lu_byteT); /* nupvalues */ - elements.push_back(pGCObjectT); /* gclist */ - elements.push_back(pProtoT); /* p */ - elements.push_back(llvm::ArrayType::get(pUpValT, 1)); - LClosureT->setBody(elements); - - ///* - //** Tables - //*/ - - // typedef union TKey { - // struct { - // TValuefields; - // int next; /* for chaining (offset for next node) */ - // } nk; - // TValue tvk; - //} TKey; - TKeyT = llvm::StructType::create(context, "ravi.TKey"); - elements.clear(); - elements.push_back(ValueT); - elements.push_back(C_intT); - elements.push_back(C_intT); /* next */ - TKeyT->setBody(elements); - pTKeyT = llvm::PointerType::get(TKeyT, 0); - - // typedef struct Node { - // TValue i_val; - // TKey i_key; - //} Node; - NodeT = llvm::StructType::create(context, "ravi.Node"); - elements.clear(); - elements.push_back(TValueT); /* i_val */ - elements.push_back(TKeyT); /* i_key */ - NodeT->setBody(elements); - pNodeT = llvm::PointerType::get(NodeT, 0); - - // typedef struct Table { - // CommonHeader; - // lu_byte flags; /* 1<

setBody(elements); - - // struct lua_longjmp; /* defined in ldo.c */ - lua_longjumpT = llvm::StructType::create(context, "ravi.lua_longjmp"); - plua_longjumpT = llvm::PointerType::get(lua_longjumpT, 0); - - // lzio.h - // typedef struct Mbuffer { - // char *buffer; - // size_t n; - // size_t buffsize; - //} Mbuffer; - MbufferT = llvm::StructType::create(context, "ravi.Mbuffer"); - elements.clear(); - elements.push_back(llvm::Type::getInt8PtrTy(context)); /* buffer */ - elements.push_back(C_size_t); /* n */ - elements.push_back(C_size_t); /* buffsize */ - MbufferT->setBody(elements); - - // typedef struct stringtable { - // TString **hash; - // int nuse; /* number of elements */ - // int size; - //} stringtable; - stringtableT = llvm::StructType::create(context, "ravi.stringtable"); - elements.clear(); - elements.push_back(ppTStringT); /* hash */ - elements.push_back(C_intT); /* nuse */ - elements.push_back(C_intT); /* size */ - stringtableT->setBody(elements); - - ///* - //** Information about a call. - //** When a thread yields, 'func' is adjusted to pretend that the - //** top function has only the yielded values in its stack; in that - //** case, the actual 'func' value is saved in field 'extra'. - //** When a function calls another with a continuation, 'extra' keeps - //** the function index so that, in case of errors, the continuation - //** function can be called with the correct top. - //*/ - // typedef struct CallInfo { - // StkId func; /* function index in the stack */ - // StkId top; /* top for this function */ - // struct CallInfo *previous, *next; /* dynamic call link */ - // union { - // struct { /* only for Lua functions */ - // StkId base; /* base for this function */ - // const Instruction *savedpc; - // } l; - // struct { /* only for C functions */ - // lua_KFunction k; /* continuation in case of yields */ - // ptrdiff_t old_errfunc; - // lua_KContext ctx; /* context info. in case of yields */ - // } c; - // } u; - // ptrdiff_t extra; - // short nresults; /* expected number of results from this function */ - // lu_byte callstatus; - //} CallInfo; - - elements.clear(); - elements.push_back(StkIdT); /* base */ - elements.push_back(pInstructionT); /* savedpc */ - elements.push_back( - C_ptrdiff_t); /* dummy to make this same size as the other member */ - CallInfo_lT = llvm::StructType::create(elements); - - elements.clear(); - elements.push_back(plua_KFunctionT); /* k */ - elements.push_back(C_ptrdiff_t); /* old_errfunc */ - elements.push_back(lua_KContextT); /* ctx */ - CallInfo_cT = llvm::StructType::create(elements); - - CallInfoT = llvm::StructType::create(context, "ravi.CallInfo"); - pCallInfoT = llvm::PointerType::get(CallInfoT, 0); - elements.clear(); - elements.push_back(StkIdT); /* func */ - elements.push_back(StkIdT); /* top */ - elements.push_back(pCallInfoT); /* previous */ - elements.push_back(pCallInfoT); /* next */ - elements.push_back( - CallInfo_lT); /* u.l - as we will typically access the lua call details - */ - elements.push_back(C_ptrdiff_t); /* extra */ - elements.push_back(llvm::Type::getInt16Ty(context)); /* nresults */ - elements.push_back(lu_byteT); /* callstatus */ - CallInfoT->setBody(elements); - - // typedef struct ravi_State ravi_State; - - ravi_StateT = llvm::StructType::create(context, "ravi.ravi_State"); - pravi_StateT = llvm::PointerType::get(ravi_StateT, 0); - - ///* - //** 'global state', shared by all threads of this state - //*/ - // typedef struct global_State { - // lua_Alloc frealloc; /* function to reallocate memory */ - // void *ud; /* auxiliary data to 'frealloc' */ - // lu_mem totalbytes; /* number of bytes currently allocated - GCdebt */ - // l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ - // lu_mem GCmemtrav; /* memory traversed by the GC */ - // lu_mem GCestimate; /* an estimate of the non-garbage memory in use */ - // stringtable strt; /* hash table for strings */ - // TValue l_registry; - // unsigned int seed; /* randomized seed for hashes */ - // lu_byte currentwhite; - // lu_byte gcstate; /* state of garbage collector */ - // lu_byte gckind; /* kind of GC running */ - // lu_byte gcrunning; /* true if GC is running */ - // GCObject *allgc; /* list of all collectable objects */ - // GCObject **sweepgc; /* current position of sweep in list */ - // GCObject *finobj; /* list of collectable objects with finalizers */ - // GCObject *gray; /* list of gray objects */ - // GCObject *grayagain; /* list of objects to be traversed atomically */ - // GCObject *weak; /* list of tables with weak values */ - // GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ - // GCObject *allweak; /* list of all-weak tables */ - // GCObject *tobefnz; /* list of userdata to be GC */ - // GCObject *fixedgc; /* list of objects not to be collected */ - // struct lua_State *twups; /* list of threads with open upvalues */ - // Mbuffer buff; /* temporary buffer for string concatenation */ - // unsigned int gcfinnum; /* number of finalizers to call in each GC step */ - // int gcpause; /* size of pause between successive GCs */ - // int gcstepmul; /* GC 'granularity' */ - // lua_CFunction panic; /* to be called in unprotected errors */ - // struct lua_State *mainthread; - // const lua_Number *version; /* pointer to version number */ - // TString *memerrmsg; /* memory-error message */ - // TString *tmname[TM_N]; /* array with tag-method names */ - // struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */ - // /* RAVI */ - // ravi_State *ravi_state; - //} global_State; - - global_StateT = llvm::StructType::create(context, "ravi.global_State"); - pglobal_StateT = llvm::PointerType::get(global_StateT, 0); - - ///* - //** 'per thread' state - //*/ - // struct lua_State { - // CommonHeader; - // lu_byte status; - // StkId top; /* first free slot in the stack */ - // global_State *l_G; - // CallInfo *ci; /* call info for current function */ - // const Instruction *oldpc; /* last pc traced */ - // StkId stack_last; /* last free slot in the stack */ - // StkId stack; /* stack base */ - // UpVal *openupval; /* list of open upvalues in this stack */ - // GCObject *gclist; - // struct lua_State *twups; /* list of threads with open upvalues */ - // struct lua_longjmp *errorJmp; /* current error recover point */ - // CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ - // lua_Hook hook; - // ptrdiff_t errfunc; /* current error handling function (stack index) */ - // int stacksize; - // int basehookcount; - // int hookcount; - // unsigned short nny; /* number of non-yieldable calls in stack */ - // unsigned short nCcalls; /* number of nested C calls */ - // lu_byte hookmask; - // lu_byte allowhook; - //}; - elements.clear(); - elements.push_back(pGCObjectT); - elements.push_back(lu_byteT); - elements.push_back(lu_byteT); - elements.push_back(lu_byteT); /* status */ - elements.push_back(StkIdT); /* top */ - elements.push_back(pglobal_StateT); /* l_G */ - elements.push_back(pCallInfoT); /* ci */ - elements.push_back(pInstructionT); /* oldpc */ - elements.push_back(StkIdT); /* stack_last */ - elements.push_back(StkIdT); /* stack */ - elements.push_back(pUpValT); /* openupval */ - elements.push_back(pGCObjectT); /* gclist */ - elements.push_back(plua_StateT); /* twups */ - elements.push_back(plua_longjumpT); /* errorJmp */ - elements.push_back(CallInfoT); /* base_ci */ - elements.push_back(plua_HookT); /* hook */ - elements.push_back(C_ptrdiff_t); /* errfunc */ - elements.push_back(C_intT); /* stacksize */ - elements.push_back(C_intT); /* basehookcount */ - elements.push_back(C_intT); /* hookcount */ - elements.push_back(llvm::Type::getInt16Ty(context)); /* nny */ - elements.push_back(llvm::Type::getInt16Ty(context)); /* nCcalls */ - elements.push_back(lu_byteT); /* hookmask */ - elements.push_back(lu_byteT); /* allowhook */ - lua_StateT->setBody(elements); - - // int luaD_poscall (lua_State *L, StkId firstResult) - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(StkIdT); - luaD_poscallT = llvm::FunctionType::get(C_intT, elements, false); - - diff --git a/readthedocs/ravi-mir-instructions.rst b/readthedocs/ravi-mir-instructions.rst index b6dc940..4d8ac43 100644 --- a/readthedocs/ravi-mir-instructions.rst +++ b/readthedocs/ravi-mir-instructions.rst @@ -1,8 +1,6 @@ Instructions for Building With MIR JIT support ============================================== -Please note that currently `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 @@ -11,3 +9,10 @@ Building with MIR support is straightforward as MIR is included in Ravi:: make install That's it. + +For Windows, try this:: + + mkdir buildmir + cd buildmir + cmake -DCMAKE_INSTALL_PREFIX=/Software/ravi -DCMAKE_BUILD_TYPE=Release -DMIR_JIT=ON .. + cmake --build . --config Release diff --git a/readthedocs/ravi-overview.rst b/readthedocs/ravi-overview.rst index 39c1681..9fd15ec 100644 --- a/readthedocs/ravi-overview.rst +++ b/readthedocs/ravi-overview.rst @@ -5,7 +5,7 @@ Ravi Programming Language :target: https://travis-ci.org/dibyendumajumdar/ravi Ravi is a dialect of `Lua `_ with limited optional static typing and -features `MIR `_ and `LLVM `_ powered JIT compilers. +features `MIR `_ powered JIT compilers. The name Ravi comes from the Sanskrit word for the Sun. Interestingly a precursor to Lua was `Sol `_ which had support for static types; Sol means the Sun in Portugese. @@ -35,8 +35,7 @@ Features * Compatibility with Lua 5.3 (see Compatibility section below) * Generational GC from Lua 5.4 * ``defer`` statement for releasing resources -* Compact JIT backend `MIR `_; only Linux and x86-64 supported for now. -* `LLVM `_ supported as alternative JIT backend. +* Compact JIT backend `MIR `_. * A `distribution with batteries `_. * A `Visual Studio Code debugger extension `_ - interpreted mode debugger. @@ -44,7 +43,6 @@ Documentation ============= * For the Lua extensions in Ravi see the `Reference Manual `_. * `MIR JIT Build instructions `_. -* `LLVM JIT Build instructions `_. * Also see `Ravi Documentation `_. * and the slides I presented at the `Lua 2015 Workshop `_. @@ -99,6 +97,7 @@ When JIT compilation is enabled there are following additional constraints: * Ravi will only execute JITed code from the main Lua thread; any secondary threads (coroutines) execute in interpreter mode. * In JITed code tailcalls are implemented as regular calls so unlike the interpreter VM which supports infinite tail recursion JIT compiled code only supports tail recursion to a depth of about 110 (issue #17) +* Debug api and hooks are not supported in JIT mode History ======= @@ -115,11 +114,13 @@ History - Created `Ravi with batteries `_. * 2019 - New language feature - `defer` statement - - New JIT backend `MIR `_. - -* 2020 (Plan) - - `New optimizing byte code generator based on new parser / type checker `_ + - New JIT backend `MIR `_. +* 2020 + - `New parser / type checker / compiler `_ - Generational GC back-ported from Lua 5.4 + - Support for `LLVM backend `_ archived +* 2021 (Plan) + - Integrated AOT and JIT compilation support - Ravi 1.0 release License diff --git a/src/ravi_llvmarith1.cpp b/src/ravi_llvmarith1.cpp deleted file mode 100644 index 8a93546..0000000 --- a/src/ravi_llvmarith1.cpp +++ /dev/null @@ -1,374 +0,0 @@ -/****************************************************************************** -* 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. -******************************************************************************/ -#include "ravi_llvmcodegen.h" - -// This file contains LLVM IR generation for Ravi's arithmetic -// op codes - these are enhanced type specific op codes not part of -// standard Lua - -namespace ravi { - -// R(A) := -R(B), floating point -// NOT yet used -void RaviCodeGenerator::emit_UNMF(RaviFunctionDef *def, int A, int B, int pc) { - (void)pc; - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_register_or_constant(def, B); - llvm::Instruction *lhs = emit_load_reg_n(def, rb); - llvm::Value *result = def->builder->CreateFNeg(lhs); - emit_store_reg_n_withtype(def, result, ra); -} - -// R(A) := -R(B), integer -// NOT yet used -void RaviCodeGenerator::emit_UNMI(RaviFunctionDef *def, int A, int B, int pc) { - (void)pc; - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_register_or_constant(def, B); - llvm::Instruction *lhs = emit_load_reg_i(def, rb); - llvm::Value *result = def->builder->CreateNeg(lhs, "", false, true); - emit_store_reg_i_withtype(def, result, ra); -} - -// R(A) := RK(B) + RK(C), all floating -void RaviCodeGenerator::emit_ADDFF(RaviFunctionDef *def, int A, int B, int C, - int pc) { - emit_debug_trace(def, OP_RAVI_ADDFF, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_load_register_or_constant_n(def, B); - llvm::Value *rc = emit_load_register_or_constant_n(def, C); - llvm::Value *result = def->builder->CreateFAdd(rb, rc); - emit_store_reg_n_withtype(def, result, ra); -} - -// R(A) := RK(B) + RK(C), float+int -void RaviCodeGenerator::emit_ADDFI(RaviFunctionDef *def, int A, int B, int C, - int pc) { - emit_debug_trace(def, OP_RAVI_ADDFI, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_load_register_or_constant_n(def, B); - llvm::Value *rc = emit_load_register_or_constant_i(def, C); - llvm::Value *result = def->builder->CreateFAdd( - rb, def->builder->CreateSIToFP(rc, def->types->lua_NumberT)); - emit_store_reg_n_withtype(def, result, ra); -} - -// R(A) := RK(B) + RK(C), int+int -void RaviCodeGenerator::emit_ADDII(RaviFunctionDef *def, int A, int B, int C, - int pc) { - emit_debug_trace(def, OP_RAVI_ADDII, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_load_register_or_constant_i(def, B); - llvm::Value *rc = emit_load_register_or_constant_i(def, C); - llvm::Value *result = - def->builder->CreateAdd(rb, rc, "OP_RAVI_ADDII_result", false, true); - emit_store_reg_i_withtype(def, result, ra); -} - -// R(A) := RK(B) - RK(C), float-float -void RaviCodeGenerator::emit_SUBFF(RaviFunctionDef *def, int A, int B, int C, - int pc) { - emit_debug_trace(def, OP_RAVI_SUBFF, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_load_register_or_constant_n(def, B); - llvm::Value *rc = emit_load_register_or_constant_n(def, C); - llvm::Value *result = def->builder->CreateFSub(rb, rc); - emit_store_reg_n_withtype(def, result, ra); -} - -// R(A) := RK(B) - RK(C), float-int -void RaviCodeGenerator::emit_SUBFI(RaviFunctionDef *def, int A, int B, int C, - int pc) { - emit_debug_trace(def, OP_RAVI_SUBFI, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_load_register_or_constant_n(def, B); - llvm::Value *rc = emit_load_register_or_constant_i(def, C); - llvm::Value *result = def->builder->CreateFSub( - rb, def->builder->CreateSIToFP(rc, def->types->lua_NumberT)); - emit_store_reg_n_withtype(def, result, ra); -} - -// R(A) := RK(B) - RK(C), int-float -void RaviCodeGenerator::emit_SUBIF(RaviFunctionDef *def, int A, int B, int C, - int pc) { - emit_debug_trace(def, OP_RAVI_SUBIF, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_load_register_or_constant_i(def, B); - llvm::Value *rc = emit_load_register_or_constant_n(def, C); - llvm::Value *result = def->builder->CreateFSub( - def->builder->CreateSIToFP(rb, def->types->lua_NumberT), rc); - emit_store_reg_n_withtype(def, result, ra); -} - -// R(A) := RK(B) - RK(C), int-int -void RaviCodeGenerator::emit_SUBII(RaviFunctionDef *def, int A, int B, int C, - int pc) { - emit_debug_trace(def, OP_RAVI_SUBII, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_load_register_or_constant_i(def, B); - llvm::Value *rc = emit_load_register_or_constant_i(def, C); - llvm::Value *result = - def->builder->CreateSub(rb, rc, "OP_RAVI_SUBII_result", false, true); - emit_store_reg_i_withtype(def, result, ra); -} - -// R(A) := RK(B) * RK(C), float*float -void RaviCodeGenerator::emit_MULFF(RaviFunctionDef *def, int A, int B, int C, - int pc) { - emit_debug_trace(def, OP_RAVI_MULFF, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_load_register_or_constant_n(def, B); - llvm::Value *rc = emit_load_register_or_constant_n(def, C); - llvm::Value *result = def->builder->CreateFMul(rb, rc); - emit_store_reg_n_withtype(def, result, ra); -} - -// R(A) := RK(B) * RK(C), float*int -void RaviCodeGenerator::emit_MULFI(RaviFunctionDef *def, int A, int B, int C, - int pc) { - emit_debug_trace(def, OP_RAVI_MULFI, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_load_register_or_constant_n(def, B); - llvm::Value *rc = emit_load_register_or_constant_i(def, C); - llvm::Value *result = def->builder->CreateFMul( - rb, def->builder->CreateSIToFP(rc, def->types->lua_NumberT)); - emit_store_reg_n_withtype(def, result, ra); -} - -// R(A) := RK(B) * RK(C), int*int -void RaviCodeGenerator::emit_MULII(RaviFunctionDef *def, int A, int B, int C, - int pc) { - emit_debug_trace(def, OP_RAVI_MULII, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_load_register_or_constant_i(def, B); - llvm::Value *rc = emit_load_register_or_constant_i(def, C); - llvm::Value *result = - def->builder->CreateMul(rb, rc, "OP_RAVI_MULII_result", false, true); - emit_store_reg_i_withtype(def, result, ra); -} - -// R(A) := RK(B) / RK(C), float/float -void RaviCodeGenerator::emit_DIVFF(RaviFunctionDef *def, int A, int B, int C, - int pc) { - emit_debug_trace(def, OP_RAVI_DIVFF, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_load_register_or_constant_n(def, B); - llvm::Value *rc = emit_load_register_or_constant_n(def, C); - llvm::Value *result = def->builder->CreateFDiv(rb, rc); - emit_store_reg_n_withtype(def, result, ra); -} - -// R(A) := RK(B) / RK(C), float/int -void RaviCodeGenerator::emit_DIVFI(RaviFunctionDef *def, int A, int B, int C, - int pc) { - emit_debug_trace(def, OP_RAVI_DIVFI, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_load_register_or_constant_n(def, B); - llvm::Value *rc = emit_load_register_or_constant_i(def, C); - llvm::Value *result = def->builder->CreateFDiv( - rb, def->builder->CreateSIToFP(rc, def->types->lua_NumberT)); - emit_store_reg_n_withtype(def, result, ra); -} - -// R(A) := RK(B) / RK(C), int/float -void RaviCodeGenerator::emit_DIVIF(RaviFunctionDef *def, int A, int B, int C, - int pc) { - emit_debug_trace(def, OP_RAVI_DIVIF, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_load_register_or_constant_i(def, B); - llvm::Value *rc = emit_load_register_or_constant_n(def, C); - llvm::Value *result = def->builder->CreateFDiv( - def->builder->CreateSIToFP(rb, def->types->lua_NumberT), rc); - emit_store_reg_n_withtype(def, result, ra); -} - -// R(A) := RK(B) / RK(C), int/int but result is float -void RaviCodeGenerator::emit_DIVII(RaviFunctionDef *def, int A, int B, int C, - int pc) { - emit_debug_trace(def, OP_RAVI_DIVII, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_load_register_or_constant_i(def, B); - llvm::Value *rc = emit_load_register_or_constant_i(def, C); - llvm::Value *result = def->builder->CreateFDiv( - def->builder->CreateSIToFP(rb, def->types->lua_NumberT), - def->builder->CreateSIToFP(rc, def->types->lua_NumberT)); - emit_store_reg_n_withtype(def, result, ra); -} - -// Bitwise AND, OR and XOR when both operands are known to be -// integers -void RaviCodeGenerator::emit_BITWISE_BINARY_OP(RaviFunctionDef *def, OpCode op, - int A, int B, int C, int pc) { - emit_debug_trace(def, op, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - - llvm::Value *lhs = emit_load_register_or_constant_i(def, B); - llvm::Value *rhs = emit_load_register_or_constant_i(def, C); - - llvm::Value *result = NULL; - - switch (op) { - case OP_RAVI_BAND_II: - result = def->builder->CreateAnd(lhs, rhs, "OP_RAVI_BAND_II_result"); - break; - case OP_RAVI_BOR_II: - result = def->builder->CreateOr(lhs, rhs, "OP_RAVI_BOR_II_result"); - break; - case OP_RAVI_BXOR_II: - result = def->builder->CreateXor(lhs, rhs, "OP_RAVI_BXOR_II_result"); - break; - default: - fprintf(stderr, "unexpected value of opcode %d\n", (int)op); - abort(); - } - emit_store_reg_i_withtype(def, result, ra); -} - -/* number of bits in an integer */ -#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT) - -// Handle the case when we have a constant RHS and the LHS is an integer -void RaviCodeGenerator::emit_bitwise_shiftl(RaviFunctionDef *def, - llvm::Value *ra, int B, - lua_Integer y) { - if (y < 0) { /* shift right? */ - if (y <= -NBITS) - emit_store_reg_i_withtype( - def, llvm::ConstantInt::get(def->types->lua_IntegerT, 0), ra); - else { - llvm::Value *rb = emit_load_register_or_constant_i(def, B); - llvm::Value *result = def->builder->CreateLShr( - rb, llvm::ConstantInt::get(def->types->lua_IntegerT, -y)); - emit_store_reg_i_withtype(def, result, ra); - } - } - else { - if (y >= NBITS) - emit_store_reg_i_withtype( - def, llvm::ConstantInt::get(def->types->lua_IntegerT, 0), ra); - else { - llvm::Value *rb = emit_load_register_or_constant_i(def, B); - llvm::Value *result = def->builder->CreateShl( - rb, llvm::ConstantInt::get(def->types->lua_IntegerT, y)); - emit_store_reg_i_withtype(def, result, ra); - } - } -} - -void RaviCodeGenerator::emit_BITWISE_SHIFT_OP(RaviFunctionDef *def, OpCode op, - int A, int B, int C, int pc) { - bool traced = emit_debug_trace(def, op, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - - // If the RHS is a constant and we know that LHS is - // and integer then we can optimize the code generation - if (op == OP_RAVI_SHL_II && ISK(C)) { - lua_Integer y = def->p->k[INDEXK(C)].value_.i; - emit_bitwise_shiftl(def, ra, B, y); - } - else if (op == OP_RAVI_SHR_II && ISK(C)) { - lua_Integer y = def->p->k[INDEXK(C)].value_.i; - emit_bitwise_shiftl(def, ra, B, -y); - } - else { - // RHS is not a constant - llvm::Value *rc = emit_gep_register_or_constant(def, C); - llvm::Value *rb = emit_gep_register_or_constant(def, B); - - // Since the Lua OP_SHL and OP_SHR bytecodes - // could invoke metamethods we need to set - // 'savedpc' - switch (op) { - case OP_SHL: - if (!traced) emit_update_savedpc(def, pc); - case OP_RAVI_SHL_II: - CreateCall4(def->builder, def->raviV_op_shlF, def->L, ra, rb, rc); - break; - case OP_SHR: - if (!traced) emit_update_savedpc(def, pc); - case OP_RAVI_SHR_II: - CreateCall4(def->builder, def->raviV_op_shrF, def->L, ra, rb, rc); - break; - default: - fprintf(stderr, "unexpected value of opcode %d\n", (int)op); - abort(); - } - } -} - -// R(A) := ~R(B); known integer operand -void RaviCodeGenerator::emit_BNOT_I(RaviFunctionDef *def, int A, int B, - int pc) { - emit_debug_trace(def, OP_RAVI_BNOT_I, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *lhs = emit_load_register_or_constant_i(def, B); - llvm::Value *rhs = llvm::ConstantInt::get(def->types->lua_IntegerT, -1); - llvm::Value *result = def->builder->CreateXor(lhs, rhs, ""); - emit_store_reg_i_withtype(def, result, ra); -} - -void RaviCodeGenerator::emit_BOR_BXOR_BAND(RaviFunctionDef *def, OpCode op, - int A, int B, int C, int pc) { - bool traced = emit_debug_trace(def, op, pc); - // Below may invoke metamethod so we set savedpc - if (!traced) emit_update_savedpc(def, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_register_or_constant(def, B); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - CreateCall4(def->builder, - op == OP_BOR - ? def->raviV_op_borF - : (op == OP_BAND ? def->raviV_op_bandF : def->raviV_op_bxorF), - def->L, ra, rb, rc); -} - -void RaviCodeGenerator::emit_BNOT(RaviFunctionDef *def, int A, int B, int pc) { - bool traced = emit_debug_trace(def, OP_BNOT, pc); - // Below may invoke metamethod so we set savedpc - if (!traced) emit_update_savedpc(def, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_register(def, B); - CreateCall3(def->builder, def->raviV_op_bnotF, def->L, ra, rb); -} -} \ No newline at end of file diff --git a/src/ravi_llvmarith2.cpp b/src/ravi_llvmarith2.cpp deleted file mode 100644 index 130d0db..0000000 --- a/src/ravi_llvmarith2.cpp +++ /dev/null @@ -1,1145 +0,0 @@ -/****************************************************************************** -* 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. -******************************************************************************/ -#include "ravi_llvmcodegen.h" - -// This file contains LLVM IR generation for standard Lua arithmetic op codes - -namespace ravi { - -// OP_ADD, OP_SUB, OP_MUL and OP_DIV -// Code size priority so go via function calls -void RaviCodeGenerator::emit_ARITH_calls(RaviFunctionDef *def, int A, int B, - int C, OpCode op, TMS tms, int pc) { - emit_debug_trace(def, op, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_register_or_constant(def, B); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - switch (op) { - case OP_ADD: - CreateCall4(def->builder, def->raviV_op_addF, def->L, ra, rb, rc); - break; - case OP_SUB: - CreateCall4(def->builder, def->raviV_op_subF, def->L, ra, rb, rc); - break; - case OP_MUL: - CreateCall4(def->builder, def->raviV_op_mulF, def->L, ra, rb, rc); - break; - case OP_DIV: - CreateCall4(def->builder, def->raviV_op_divF, def->L, ra, rb, rc); - break; - default: lua_assert(0); - } -} - -// OP_ADD, OP_SUB, OP_MUL and OP_DIV -void RaviCodeGenerator::emit_ARITH_intpriority(RaviFunctionDef *def, int A, - int B, int C, OpCode op, TMS tms, - int pc) { - // TValue *rb = RKB(i); - // TValue *rc = RKC(i); - // lua_Number nb; lua_Number nc; - // if (ttisinteger(rb) && ttisinteger(rc)) { - // lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - // setivalue(ra, intop(+, ib, ic)); - //} - // else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - // setfltvalue(ra, luai_numadd(L, nb, nc)); - //} - // else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD)); } - - llvm::IRBuilder<> TmpB(def->entry, def->entry->begin()); - llvm::Value *nb = TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "nb"); - llvm::Value *nc = TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "nc"); - - bool traced = emit_debug_trace(def, op, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_register_or_constant(def, B); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - - llvm::Value *rb_type = emit_load_type(def, rb); - llvm::Value *rc_type = emit_load_type(def, rc); - - llvm::BasicBlock *float_op = - llvm::BasicBlock::Create(def->jitState->context(), "float.op"); - llvm::BasicBlock *try_meta = - llvm::BasicBlock::Create(def->jitState->context(), "try_meta"); - llvm::BasicBlock *done_block = - llvm::BasicBlock::Create(def->jitState->context(), "done"); - - if (op != OP_DIV) { - llvm::Value *cmp1 = - emit_is_value_of_type(def, rb_type, LUA__TNUMINT, "rb.is.integer"); - llvm::Value *cmp2 = - emit_is_value_of_type(def, rc_type, LUA__TNUMINT, "rc.is.integer"); - - llvm::Value *andvalue = def->builder->CreateAnd(cmp1, cmp2); - - // Check if both RB and RC are integers - llvm::BasicBlock *then_block = llvm::BasicBlock::Create( - def->jitState->context(), "if.integer", def->f); - llvm::BasicBlock *else_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.not.integer"); - def->builder->CreateCondBr(andvalue, then_block, else_block); - def->builder->SetInsertPoint(then_block); - - // Both are integers - llvm::Instruction *lhs = emit_load_reg_i(def, rb); - llvm::Instruction *rhs = emit_load_reg_i(def, rc); - - llvm::Value *result = nullptr; - switch (op) { - case OP_ADD: - result = def->builder->CreateAdd(lhs, rhs, "", false, true); - break; - case OP_SUB: - result = def->builder->CreateSub(lhs, rhs, "", false, true); - break; - case OP_MUL: - result = def->builder->CreateMul(lhs, rhs, "", false, true); - break; - default: lua_assert(0); - } - - emit_store_reg_i_withtype(def, result, ra); - - def->builder->CreateBr(done_block); - - // Not integer - def->f->getBasicBlockList().push_back(else_block); - def->builder->SetInsertPoint(else_block); - } - - // Is RB a float? - llvm::Value *cmp1 = - emit_is_value_of_type(def, rb_type, LUA__TNUMFLT, "rb.is.float"); - - llvm::BasicBlock *convert_rb = - llvm::BasicBlock::Create(def->jitState->context(), "convert.rb"); - llvm::BasicBlock *test_rc = - llvm::BasicBlock::Create(def->jitState->context(), "test.rc"); - llvm::BasicBlock *load_rb = - llvm::BasicBlock::Create(def->jitState->context(), "load.rb"); - - // If RB is floating then load RB, else convert RB - auto brinst1 = def->builder->CreateCondBr(cmp1, load_rb, convert_rb); - attach_branch_weights(def, brinst1, 100, 0); - - // Convert RB - def->f->getBasicBlockList().push_back(convert_rb); - def->builder->SetInsertPoint(convert_rb); - - // Call luaV_tonumber_() - llvm::Value *rb_isnum = - CreateCall2(def->builder, def->luaV_tonumberF, rb, nb); - cmp1 = - def->builder->CreateICmpEQ(rb_isnum, def->types->kInt[1], "rb.float.ok"); - - // If not number then go to meta block - // Else proceed to test RC - def->builder->CreateCondBr(cmp1, test_rc, try_meta); - - def->f->getBasicBlockList().push_back(load_rb); - def->builder->SetInsertPoint(load_rb); - - // Copy RB to local nb - auto src = emit_load_reg_n(def, rb); - emit_store_local_n(def, src, nb); - - def->builder->CreateBr(test_rc); - - def->f->getBasicBlockList().push_back(test_rc); - def->builder->SetInsertPoint(test_rc); - - // Is RC a float? - cmp1 = emit_is_value_of_type(def, rc_type, LUA__TNUMFLT, "rc.is.float"); - - llvm::BasicBlock *convert_rc = - llvm::BasicBlock::Create(def->jitState->context(), "convert.rc"); - llvm::BasicBlock *load_rc = - llvm::BasicBlock::Create(def->jitState->context(), "load.rc"); - - // If RC is float load RC - // else try to convert RC - auto brinst2 = def->builder->CreateCondBr(cmp1, load_rc, convert_rc); - attach_branch_weights(def, brinst2, 100, 0); - - def->f->getBasicBlockList().push_back(convert_rc); - def->builder->SetInsertPoint(convert_rc); - - // Call luaV_tonumber_() - llvm::Value *rc_isnum = - CreateCall2(def->builder, def->luaV_tonumberF, rc, nc); - cmp1 = - def->builder->CreateICmpEQ(rc_isnum, def->types->kInt[1], "rc.float.ok"); - - // If not number then go to meta block - // else both RB and RC float so go to op - def->builder->CreateCondBr(cmp1, float_op, try_meta); - - def->f->getBasicBlockList().push_back(load_rc); - def->builder->SetInsertPoint(load_rc); - - // Copy RC to local; - src = emit_load_reg_n(def, rc); - emit_store_local_n(def, src, nc); - - def->builder->CreateBr(float_op); - - def->f->getBasicBlockList().push_back(float_op); - def->builder->SetInsertPoint(float_op); - - llvm::Instruction *lhs = emit_load_local_n(def, nb); - llvm::Instruction *rhs = emit_load_local_n(def, nc); - - llvm::Value *result = nullptr; - // Add and set RA - switch (op) { - case OP_ADD: result = def->builder->CreateFAdd(lhs, rhs); break; - case OP_SUB: result = def->builder->CreateFSub(lhs, rhs); break; - case OP_MUL: result = def->builder->CreateFMul(lhs, rhs); break; - case OP_DIV: result = def->builder->CreateFDiv(lhs, rhs); break; - default: lua_assert(0); - } - - emit_store_reg_n_withtype(def, result, ra); - - def->builder->CreateBr(done_block); - - // Neither integer nor float so try meta - def->f->getBasicBlockList().push_back(try_meta); - def->builder->SetInsertPoint(try_meta); - - // Before invoking metamethod set savedpc - if (!traced) emit_update_savedpc(def, pc); - CreateCall5(def->builder, def->luaT_trybinTMF, def->L, rb, rc, ra, - def->types->kInt[tms]); - def->builder->CreateBr(done_block); - - def->f->getBasicBlockList().push_back(done_block); - def->builder->SetInsertPoint(done_block); -} - -// OP_ADD, OP_SUB, OP_MUL and OP_DIV -// This version prioritizes floating point arith over integer arith -// Also slow path is slower as it goes via function calls -void RaviCodeGenerator::emit_ARITH_floatpriority(RaviFunctionDef *def, int A, - int B, int C, OpCode op, - TMS tms, int pc) { - // TValue *rb = RKB(i); - // TValue *rc = RKC(i); - // lua_Number nb; lua_Number nc; - // if (ttisfloat(rb)) { - // if (ttisfloat(rc)) { - // nb = fltvalue(rb); nc = fltvalue(rc); - // setfltvalue(ra, luai_numadd(L, nb, nc)); - // } - // else if (ttisinteger(rc)) { - // nb = fltvalue(rb); nc = cast_num(ivalue(rc)); - // setfltvalue(ra, luai_numadd(L, nb, nc)); - // } - // else slowpath - //} - // else if (ttisinteger(rb)) { - // if (ttisfloat(rc)) { - // nb = cast_num(ivalue(rb)); nc = fltvalue(rc); - // setfltvalue(ra, luai_numadd(L, nb, nc)); - // } - // else if (ttisinteger(rc)) { - // lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - // setivalue(ra, intop(+, ib, ic)); - // } - // else slowpath - // else slowpath - - bool traced = emit_debug_trace(def, op, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_register_or_constant(def, B); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - - llvm::Value *rb_type = emit_load_type(def, rb); - llvm::Value *rc_type = emit_load_type(def, rc); - - // PART A - Is RB floating? - - llvm::Value *rb_is_float = - emit_is_value_of_type(def, rb_type, LUA__TNUMFLT, "rb.is.float"); - - llvm::BasicBlock *done = - llvm::BasicBlock::Create(def->jitState->context(), "done"); - llvm::BasicBlock *slowpath = - llvm::BasicBlock::Create(def->jitState->context(), "slowpath"); - - llvm::BasicBlock *check_rc_is_float = - llvm::BasicBlock::Create(def->jitState->context(), "check.rc.is.float"); - llvm::BasicBlock *check_rb_is_int = - llvm::BasicBlock::Create(def->jitState->context(), "check.rb.is.int"); - - // If RB is floating, check RC else check RB is int - auto brinst1 = def->builder->CreateCondBr(rb_is_float, check_rc_is_float, - check_rb_is_int); - attach_branch_weights(def, brinst1, 5, 2); - - // Check if rc is float - def->f->getBasicBlockList().push_back(check_rc_is_float); - def->builder->SetInsertPoint(check_rc_is_float); - - llvm::Value *rc_is_float = - emit_is_value_of_type(def, rc_type, LUA__TNUMFLT, "rb.float.is.rc.float"); - - llvm::BasicBlock *float_op = - llvm::BasicBlock::Create(def->jitState->context(), "float.op"); - llvm::BasicBlock *rb_float_check_rc_is_int = llvm::BasicBlock::Create( - def->jitState->context(), "rb.float.check.rc.int"); - - // RB is floating - so check if RC is floating - auto brinst2 = def->builder->CreateCondBr(rc_is_float, float_op, - rb_float_check_rc_is_int); - attach_branch_weights(def, brinst2, 10, 3); - - // Both rb and rc are floats - def->f->getBasicBlockList().push_back(float_op); - def->builder->SetInsertPoint(float_op); - - llvm::Instruction *lhs = emit_load_reg_n(def, rb); - llvm::Instruction *rhs = emit_load_reg_n(def, rc); - - llvm::Value *result = nullptr; - // Add and set RA - switch (op) { - case OP_ADD: result = def->builder->CreateFAdd(lhs, rhs); break; - case OP_SUB: result = def->builder->CreateFSub(lhs, rhs); break; - case OP_MUL: result = def->builder->CreateFMul(lhs, rhs); break; - case OP_DIV: result = def->builder->CreateFDiv(lhs, rhs); break; - default: lua_assert(0); - } - emit_store_reg_n_withtype(def, result, ra); - - // We are done - def->builder->CreateBr(done); - - // RB is float - but RC is not, so check if RC is int - def->f->getBasicBlockList().push_back(rb_float_check_rc_is_int); - def->builder->SetInsertPoint(rb_float_check_rc_is_int); - - llvm::Value *rb_float_is_rc_int = - emit_is_value_of_type(def, rc_type, LUA__TNUMINT, "rb.float.is.rc.int"); - - llvm::BasicBlock *float_int_op = - llvm::BasicBlock::Create(def->jitState->context(), "float.int.op"); - - // RB is floating, check if RC in int - auto brinst3 = - def->builder->CreateCondBr(rb_float_is_rc_int, float_int_op, slowpath); - attach_branch_weights(def, brinst3, 100, 0); - - // RB is float - but RC is int - def->f->getBasicBlockList().push_back(float_int_op); - def->builder->SetInsertPoint(float_int_op); - - lhs = emit_load_reg_n(def, rb); - rhs = emit_load_reg_i(def, rc); - - result = nullptr; - // Add and set RA - switch (op) { - case OP_ADD: - result = def->builder->CreateFAdd( - lhs, def->builder->CreateSIToFP(rhs, def->types->lua_NumberT)); - break; - case OP_SUB: - result = def->builder->CreateFSub( - lhs, def->builder->CreateSIToFP(rhs, def->types->lua_NumberT)); - break; - case OP_MUL: - result = def->builder->CreateFMul( - lhs, def->builder->CreateSIToFP(rhs, def->types->lua_NumberT)); - break; - case OP_DIV: - result = def->builder->CreateFDiv( - lhs, def->builder->CreateSIToFP(rhs, def->types->lua_NumberT)); - break; - default: lua_assert(0); - } - emit_store_reg_n_withtype(def, result, ra); - - // We are done - def->builder->CreateBr(done); - - // PART B - This section starts by checking whether RB is integer - - def->f->getBasicBlockList().push_back(check_rb_is_int); - def->builder->SetInsertPoint(check_rb_is_int); - - llvm::Value *rb_is_int = - emit_is_value_of_type(def, rb_type, LUA__TNUMINT, "rb.is.integer"); - - llvm::BasicBlock *rb_int_check_rc_int = - llvm::BasicBlock::Create(def->jitState->context(), "rb.int.check.rc.int"); - llvm::BasicBlock *rb_int_check_rc_float = llvm::BasicBlock::Create( - def->jitState->context(), "rb.int.check.rc.float"); - - // Check if RB is INT - auto brinst4 = - def->builder->CreateCondBr(rb_is_int, rb_int_check_rc_int, slowpath); - attach_branch_weights(def, brinst4, 100, 0); - - // RB is int, check if RC is also int - def->f->getBasicBlockList().push_back(rb_int_check_rc_int); - def->builder->SetInsertPoint(rb_int_check_rc_int); - - llvm::Value *rb_int_is_rc_int = - emit_is_value_of_type(def, rc_type, LUA__TNUMINT, "rb.int.is.rc.int"); - - llvm::BasicBlock *int_int_op = - llvm::BasicBlock::Create(def->jitState->context(), "int.int.op"); - - // Check if RC is INT - auto brinst5 = def->builder->CreateCondBr(rb_int_is_rc_int, int_int_op, - rb_int_check_rc_float); - attach_branch_weights(def, brinst5, 10, 3); - - // RB is int, RC int - def->f->getBasicBlockList().push_back(int_int_op); - def->builder->SetInsertPoint(int_int_op); - - // Both are integers - lhs = emit_load_reg_i(def, rb); - rhs = emit_load_reg_i(def, rc); - - result = nullptr; - switch (op) { - case OP_ADD: - result = def->builder->CreateAdd(lhs, rhs, "", false, true); - break; - case OP_SUB: - result = def->builder->CreateSub(lhs, rhs, "", false, true); - break; - case OP_MUL: - result = def->builder->CreateMul(lhs, rhs, "", false, true); - break; - case OP_DIV: - result = def->builder->CreateFDiv( - def->builder->CreateSIToFP(lhs, def->types->lua_NumberT), - def->builder->CreateSIToFP(rhs, def->types->lua_NumberT)); - break; - default: lua_assert(0); - } - - if (op != OP_DIV) - emit_store_reg_i_withtype(def, result, ra); - else - emit_store_reg_n_withtype(def, result, ra); - - def->builder->CreateBr(done); - - // RB is int, check if RC is float - def->f->getBasicBlockList().push_back(rb_int_check_rc_float); - def->builder->SetInsertPoint(rb_int_check_rc_float); - - llvm::Value *rb_int_is_rc_float = - emit_is_value_of_type(def, rc_type, LUA__TNUMFLT, "rb.int.is.rc.float"); - - llvm::BasicBlock *int_float_op = - llvm::BasicBlock::Create(def->jitState->context(), "int.float.op"); - - // RB is int, check if RC is float - auto brinst6 = - def->builder->CreateCondBr(rb_int_is_rc_float, int_float_op, slowpath); - attach_branch_weights(def, brinst6, 100, 0); - - // RB is int, RC is float - def->f->getBasicBlockList().push_back(int_float_op); - def->builder->SetInsertPoint(int_float_op); - - lhs = emit_load_reg_i(def, rb); - rhs = emit_load_reg_n(def, rc); - - result = nullptr; - // Add and set RA - switch (op) { - case OP_ADD: - result = def->builder->CreateFAdd( - def->builder->CreateSIToFP(lhs, def->types->lua_NumberT), rhs); - break; - case OP_SUB: - result = def->builder->CreateFSub( - def->builder->CreateSIToFP(lhs, def->types->lua_NumberT), rhs); - break; - case OP_MUL: - result = def->builder->CreateFMul( - def->builder->CreateSIToFP(lhs, def->types->lua_NumberT), rhs); - break; - case OP_DIV: - result = def->builder->CreateFDiv( - def->builder->CreateSIToFP(lhs, def->types->lua_NumberT), rhs); - break; - default: lua_assert(0); - } - emit_store_reg_n_withtype(def, result, ra); - - // We are done - def->builder->CreateBr(done); - - def->f->getBasicBlockList().push_back(slowpath); - def->builder->SetInsertPoint(slowpath); - - // Set savedpc as following may invoke metamethod - if (!traced) emit_update_savedpc(def, pc); - - switch (op) { - case OP_ADD: - CreateCall4(def->builder, def->raviV_op_addF, def->L, ra, rb, rc); - break; - case OP_SUB: - CreateCall4(def->builder, def->raviV_op_subF, def->L, ra, rb, rc); - break; - case OP_MUL: - CreateCall4(def->builder, def->raviV_op_mulF, def->L, ra, rb, rc); - break; - case OP_DIV: - CreateCall4(def->builder, def->raviV_op_divF, def->L, ra, rb, rc); - break; - default: lua_assert(0); - } - - def->builder->CreateBr(done); - - def->f->getBasicBlockList().push_back(done); - def->builder->SetInsertPoint(done); -} - -// OP_MOD -void RaviCodeGenerator::emit_MOD(RaviFunctionDef *def, int A, int B, int C, - int pc) { - // TValue *rb = RKB(i); - // TValue *rc = RKC(i); - // lua_Number nb; lua_Number nc; - // if (ttisinteger(rb) && ttisinteger(rc)) { - // lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - // setivalue(ra, luaV_mod(L, ib, ic)); - //} - // else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - // lua_Number m; - // luai_nummod(L, nb, nc, m); - // setfltvalue(ra, m); - //} - // else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MOD)); } - - llvm::IRBuilder<> TmpB(def->entry, def->entry->begin()); - llvm::Value *nb = TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "nb"); - llvm::Value *nc = TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "nc"); - - bool traced = emit_debug_trace(def, OP_MOD, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_register_or_constant(def, B); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - - llvm::Value *rb_type = emit_load_type(def, rb); - llvm::Value *rc_type = emit_load_type(def, rc); - - llvm::BasicBlock *float_op = - llvm::BasicBlock::Create(def->jitState->context(), "float.op"); - llvm::BasicBlock *try_meta = - llvm::BasicBlock::Create(def->jitState->context(), "try_meta"); - llvm::BasicBlock *done_block = - llvm::BasicBlock::Create(def->jitState->context(), "done"); - - llvm::Value *cmp1 = - emit_is_value_of_type(def, rb_type, LUA__TNUMINT, "rb.is.integer"); - llvm::Value *cmp2 = - emit_is_value_of_type(def, rc_type, LUA__TNUMINT, "rc.is.integer"); - - llvm::Value *andvalue = def->builder->CreateAnd(cmp1, cmp2); - - // Check if both RB and RC are integers - llvm::BasicBlock *then_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.integer", def->f); - llvm::BasicBlock *else_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.not.integer"); - def->builder->CreateCondBr(andvalue, then_block, else_block); - def->builder->SetInsertPoint(then_block); - - // Both are integers - llvm::Instruction *lhs = emit_load_reg_i(def, rb); - llvm::Instruction *rhs = emit_load_reg_i(def, rc); - - llvm::Value *result = - CreateCall3(def->builder, def->luaV_modF, def->L, lhs, rhs); - emit_store_reg_i_withtype(def, result, ra); - - def->builder->CreateBr(done_block); - - // Not integer - def->f->getBasicBlockList().push_back(else_block); - def->builder->SetInsertPoint(else_block); - - // Is RB a float? - cmp1 = emit_is_value_of_type(def, rb_type, LUA__TNUMFLT, "rb.is.float"); - - llvm::BasicBlock *convert_rb = - llvm::BasicBlock::Create(def->jitState->context(), "convert.rb"); - llvm::BasicBlock *test_rc = - llvm::BasicBlock::Create(def->jitState->context(), "test.rc"); - llvm::BasicBlock *load_rb = - llvm::BasicBlock::Create(def->jitState->context(), "load.rb"); - - // If RB is floating then load RB, else convert RB - def->builder->CreateCondBr(cmp1, load_rb, convert_rb); - - // Convert RB - def->f->getBasicBlockList().push_back(convert_rb); - def->builder->SetInsertPoint(convert_rb); - - // Call luaV_tonumber_() - llvm::Value *rb_isnum = - CreateCall2(def->builder, def->luaV_tonumberF, rb, nb); - cmp1 = - def->builder->CreateICmpEQ(rb_isnum, def->types->kInt[1], "rb.float.ok"); - - // If not number then go to meta block - // Else proceed to test RC - def->builder->CreateCondBr(cmp1, test_rc, try_meta); - - def->f->getBasicBlockList().push_back(load_rb); - def->builder->SetInsertPoint(load_rb); - - // Copy RB to local nb - auto src = emit_load_reg_n(def, rb); - emit_store_local_n(def, src, nb); - - def->builder->CreateBr(test_rc); - - def->f->getBasicBlockList().push_back(test_rc); - def->builder->SetInsertPoint(test_rc); - - // Is RC a float? - cmp1 = emit_is_value_of_type(def, rc_type, LUA__TNUMFLT, "rc.is.float"); - - llvm::BasicBlock *convert_rc = - llvm::BasicBlock::Create(def->jitState->context(), "convert.rc"); - llvm::BasicBlock *load_rc = - llvm::BasicBlock::Create(def->jitState->context(), "load.rc"); - - // If RC is float load RC - // else try to convert RC - def->builder->CreateCondBr(cmp1, load_rc, convert_rc); - - def->f->getBasicBlockList().push_back(convert_rc); - def->builder->SetInsertPoint(convert_rc); - - // Call luaV_tonumber_() - llvm::Value *rc_isnum = - CreateCall2(def->builder, def->luaV_tonumberF, rc, nc); - cmp1 = - def->builder->CreateICmpEQ(rc_isnum, def->types->kInt[1], "rc.float.ok"); - - // If not number then go to meta block - // else both RB and RC float so go to op - def->builder->CreateCondBr(cmp1, float_op, try_meta); - - def->f->getBasicBlockList().push_back(load_rc); - def->builder->SetInsertPoint(load_rc); - - // Copy RC to local; - src = emit_load_reg_n(def, rc); - emit_store_local_n(def, src, nc); - - def->builder->CreateBr(float_op); - - def->f->getBasicBlockList().push_back(float_op); - def->builder->SetInsertPoint(float_op); - - 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); - - // If m*b < 0 - cmp1 = def->builder->CreateFCmpOLT( - mb, llvm::ConstantFP::get(def->types->lua_NumberT, 0.0)); - llvm::BasicBlock *mb_lt0_then = - llvm::BasicBlock::Create(def->jitState->context(), "mb.lt.zero", def->f); - llvm::BasicBlock *mb_lt0_else = - llvm::BasicBlock::Create(def->jitState->context(), "mb.not.lt.zero"); - llvm::BasicBlock *mb_lt0_done = - llvm::BasicBlock::Create(def->jitState->context(), "mb.not.lt.end"); - - def->builder->CreateCondBr(cmp1, mb_lt0_then, mb_lt0_else); - def->builder->SetInsertPoint(mb_lt0_then); - - result = def->builder->CreateFAdd(fmod_result, rhs); - emit_store_local_n(def, result, nb); - def->builder->CreateBr(mb_lt0_done); - - def->f->getBasicBlockList().push_back(mb_lt0_else); - def->builder->SetInsertPoint(mb_lt0_else); - - emit_store_local_n(def, fmod_result, nb); - def->builder->CreateBr(mb_lt0_done); - - def->f->getBasicBlockList().push_back(mb_lt0_done); - def->builder->SetInsertPoint(mb_lt0_done); - - lhs = emit_load_local_n(def, nb); - - emit_store_reg_n_withtype(def, lhs, ra); - - def->builder->CreateBr(done_block); - - // Neither integer nor float so try meta - def->f->getBasicBlockList().push_back(try_meta); - def->builder->SetInsertPoint(try_meta); - - // before invoking metamethod set savedpc - if (!traced) emit_update_savedpc(def, pc); - CreateCall5(def->builder, def->luaT_trybinTMF, def->L, rb, rc, ra, - def->types->kInt[TM_MOD]); - def->builder->CreateBr(done_block); - - def->f->getBasicBlockList().push_back(done_block); - def->builder->SetInsertPoint(done_block); -} - -// OP_IDIV -void RaviCodeGenerator::emit_IDIV(RaviFunctionDef *def, int A, int B, int C, - int pc) { - // TValue *rb = RKB(i); - // TValue *rc = RKC(i); - // lua_Number nb; lua_Number nc; - // if (ttisinteger(rb) && ttisinteger(rc)) { - // lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - // setivalue(ra, luaV_idiv(L, ib, ic)); - //} - // else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - // setfltvalue(ra, luai_numidiv(L, nb, nc)); - //} - // else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); } - - llvm::IRBuilder<> TmpB(def->entry, def->entry->begin()); - llvm::Value *nb = TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "nb"); - llvm::Value *nc = TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "nc"); - - bool traced = emit_debug_trace(def, OP_IDIV, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_register_or_constant(def, B); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - - llvm::Value *rb_type = emit_load_type(def, rb); - llvm::Value *rc_type = emit_load_type(def, rc); - - llvm::BasicBlock *float_op = - llvm::BasicBlock::Create(def->jitState->context(), "float.op"); - llvm::BasicBlock *try_meta = - llvm::BasicBlock::Create(def->jitState->context(), "try_meta"); - llvm::BasicBlock *done_block = - llvm::BasicBlock::Create(def->jitState->context(), "done"); - - llvm::Value *cmp1 = - emit_is_value_of_type(def, rb_type, LUA__TNUMINT, "rb.is.integer"); - llvm::Value *cmp2 = - emit_is_value_of_type(def, rc_type, LUA__TNUMINT, "rc.is.integer"); - - llvm::Value *andvalue = def->builder->CreateAnd(cmp1, cmp2); - - // Check if both RB and RC are integers - llvm::BasicBlock *then_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.integer", def->f); - llvm::BasicBlock *else_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.not.integer"); - def->builder->CreateCondBr(andvalue, then_block, else_block); - def->builder->SetInsertPoint(then_block); - - // Both are integers - llvm::Instruction *lhs = emit_load_reg_i(def, rb); - llvm::Instruction *rhs = emit_load_reg_i(def, rc); - - llvm::Value *result = - CreateCall3(def->builder, def->luaV_idivF, def->L, lhs, rhs); - emit_store_reg_i_withtype(def, result, ra); - - def->builder->CreateBr(done_block); - - // Not integer - def->f->getBasicBlockList().push_back(else_block); - def->builder->SetInsertPoint(else_block); - - // Is RB a float? - cmp1 = emit_is_value_of_type(def, rb_type, LUA__TNUMFLT, "rb.is.float"); - - llvm::BasicBlock *convert_rb = - llvm::BasicBlock::Create(def->jitState->context(), "convert.rb"); - llvm::BasicBlock *test_rc = - llvm::BasicBlock::Create(def->jitState->context(), "test.rc"); - llvm::BasicBlock *load_rb = - llvm::BasicBlock::Create(def->jitState->context(), "load.rb"); - - // If RB is floating then load RB, else convert RB - def->builder->CreateCondBr(cmp1, load_rb, convert_rb); - - // Convert RB - def->f->getBasicBlockList().push_back(convert_rb); - def->builder->SetInsertPoint(convert_rb); - - // Call luaV_tonumber_() - llvm::Value *rb_isnum = - CreateCall2(def->builder, def->luaV_tonumberF, rb, nb); - cmp1 = - def->builder->CreateICmpEQ(rb_isnum, def->types->kInt[1], "rb.float.ok"); - - // If not number then go to meta block - // Else proceed to test RC - def->builder->CreateCondBr(cmp1, test_rc, try_meta); - - def->f->getBasicBlockList().push_back(load_rb); - def->builder->SetInsertPoint(load_rb); - - // Copy RB to local nb - auto src = emit_load_reg_n(def, rb); - emit_store_local_n(def, src, nb); - - def->builder->CreateBr(test_rc); - - def->f->getBasicBlockList().push_back(test_rc); - def->builder->SetInsertPoint(test_rc); - - // Is RC a float? - cmp1 = emit_is_value_of_type(def, rc_type, LUA__TNUMFLT, "rc.is.float"); - - llvm::BasicBlock *convert_rc = - llvm::BasicBlock::Create(def->jitState->context(), "convert.rc"); - llvm::BasicBlock *load_rc = - llvm::BasicBlock::Create(def->jitState->context(), "load.rc"); - - // If RC is float load RC - // else try to convert RC - def->builder->CreateCondBr(cmp1, load_rc, convert_rc); - - def->f->getBasicBlockList().push_back(convert_rc); - def->builder->SetInsertPoint(convert_rc); - - // Call luaV_tonumber_() - llvm::Value *rc_isnum = - CreateCall2(def->builder, def->luaV_tonumberF, rc, nc); - cmp1 = - def->builder->CreateICmpEQ(rc_isnum, def->types->kInt[1], "rc.float.ok"); - - // If not number then go to meta block - // else both RB and RC float so go to op - def->builder->CreateCondBr(cmp1, float_op, try_meta); - - def->f->getBasicBlockList().push_back(load_rc); - def->builder->SetInsertPoint(load_rc); - - // Copy RC to local; - src = emit_load_reg_n(def, rc); - emit_store_local_n(def, src, nc); - - def->builder->CreateBr(float_op); - - def->f->getBasicBlockList().push_back(float_op); - def->builder->SetInsertPoint(float_op); - - lhs = emit_load_local_n(def, nb); - rhs = emit_load_local_n(def, nc); - - result = def->builder->CreateFDiv(lhs, rhs); - llvm::Value *floor_result = def->builder->CreateCall(def->floorFunc, result); - - emit_store_reg_n_withtype(def, floor_result, ra); - - def->builder->CreateBr(done_block); - - // Neither integer nor float so try meta - def->f->getBasicBlockList().push_back(try_meta); - def->builder->SetInsertPoint(try_meta); - - // before invoking metamethod set savedpc - if (!traced) emit_update_savedpc(def, pc); - CreateCall5(def->builder, def->luaT_trybinTMF, def->L, rb, rc, ra, - def->types->kInt[TM_IDIV]); - def->builder->CreateBr(done_block); - - def->f->getBasicBlockList().push_back(done_block); - def->builder->SetInsertPoint(done_block); -} - -// OP_POW -void RaviCodeGenerator::emit_POW(RaviFunctionDef *def, int A, int B, int C, - int pc) { - // TValue *rb = RKB(i); - // TValue *rc = RKC(i); - // lua_Number nb; lua_Number nc; - // if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - // setfltvalue(ra, luai_numpow(L, nb, nc)); - //} - // else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_POW)); } - - llvm::IRBuilder<> TmpB(def->entry, def->entry->begin()); - llvm::Value *nb = TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "nb"); - llvm::Value *nc = TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "nc"); - - bool traced = emit_debug_trace(def, OP_POW, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_register_or_constant(def, B); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - - llvm::Value *rb_type = emit_load_type(def, rb); - llvm::Value *rc_type = emit_load_type(def, rc); - - llvm::BasicBlock *float_op = - llvm::BasicBlock::Create(def->jitState->context(), "float.op"); - llvm::BasicBlock *try_meta = - llvm::BasicBlock::Create(def->jitState->context(), "try_meta"); - llvm::BasicBlock *done_block = - llvm::BasicBlock::Create(def->jitState->context(), "done"); - - // Is RB a float? - llvm::Value *cmp1 = - emit_is_value_of_type(def, rb_type, LUA__TNUMFLT, "rb.is.float"); - - llvm::BasicBlock *convert_rb = - llvm::BasicBlock::Create(def->jitState->context(), "convert.rb"); - llvm::BasicBlock *test_rc = - llvm::BasicBlock::Create(def->jitState->context(), "test.rc"); - llvm::BasicBlock *load_rb = - llvm::BasicBlock::Create(def->jitState->context(), "load.rb"); - - // If RB is floating then load RB, else convert RB - def->builder->CreateCondBr(cmp1, load_rb, convert_rb); - - // Convert RB - def->f->getBasicBlockList().push_back(convert_rb); - def->builder->SetInsertPoint(convert_rb); - - // Call luaV_tonumber_() - llvm::Value *rb_isnum = - CreateCall2(def->builder, def->luaV_tonumberF, rb, nb); - cmp1 = - def->builder->CreateICmpEQ(rb_isnum, def->types->kInt[1], "rb.float.ok"); - - // If not number then go to meta block - // Else proceed to test RC - def->builder->CreateCondBr(cmp1, test_rc, try_meta); - - def->f->getBasicBlockList().push_back(load_rb); - def->builder->SetInsertPoint(load_rb); - - // Copy RB to local nb - auto src = emit_load_reg_n(def, rb); - emit_store_local_n(def, src, nb); - - def->builder->CreateBr(test_rc); - - def->f->getBasicBlockList().push_back(test_rc); - def->builder->SetInsertPoint(test_rc); - - // Is RC a float? - cmp1 = emit_is_value_of_type(def, rc_type, LUA__TNUMFLT, "rc.is.float"); - - llvm::BasicBlock *convert_rc = - llvm::BasicBlock::Create(def->jitState->context(), "convert.rc"); - llvm::BasicBlock *load_rc = - llvm::BasicBlock::Create(def->jitState->context(), "load.rc"); - - // If RC is float load RC - // else try to convert RC - def->builder->CreateCondBr(cmp1, load_rc, convert_rc); - - def->f->getBasicBlockList().push_back(convert_rc); - def->builder->SetInsertPoint(convert_rc); - - // Call luaV_tonumber_() - llvm::Value *rc_isnum = - CreateCall2(def->builder, def->luaV_tonumberF, rc, nc); - cmp1 = - def->builder->CreateICmpEQ(rc_isnum, def->types->kInt[1], "rc.float.ok"); - - // If not number then go to meta block - // else both RB and RC float so go to op - def->builder->CreateCondBr(cmp1, float_op, try_meta); - - def->f->getBasicBlockList().push_back(load_rc); - def->builder->SetInsertPoint(load_rc); - - // Copy RC to local; - src = emit_load_reg_n(def, rc); - emit_store_local_n(def, src, nc); - - def->builder->CreateBr(float_op); - - def->f->getBasicBlockList().push_back(float_op); - def->builder->SetInsertPoint(float_op); - - 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); - - def->builder->CreateBr(done_block); - - // Neither integer nor float so try meta - def->f->getBasicBlockList().push_back(try_meta); - def->builder->SetInsertPoint(try_meta); - - // Before invoking metamethod set savedpc - if (!traced) emit_update_savedpc(def, pc); - CreateCall5(def->builder, def->luaT_trybinTMF, def->L, rb, rc, ra, - def->types->kInt[TM_POW]); - def->builder->CreateBr(done_block); - - def->f->getBasicBlockList().push_back(done_block); - def->builder->SetInsertPoint(done_block); -} - -void RaviCodeGenerator::emit_UNM(RaviFunctionDef *def, int A, int B, int pc) { - // TValue *rb = RB(i); - // lua_Number nb; - // if (ttisinteger(rb)) { - // lua_Integer ib = ivalue(rb); - // setivalue(ra, intop(-, 0, ib)); - //} - // else if (tonumber(rb, &nb)) { - // setfltvalue(ra, luai_numunm(L, nb)); - //} - // else { - // Protect(luaT_trybinTM(L, rb, rb, ra, TM_UNM)); - //} - - llvm::IRBuilder<> TmpB(def->entry, def->entry->begin()); - llvm::Value *nb = TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "nb"); - - bool traced = emit_debug_trace(def, OP_UNM, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_register_or_constant(def, B); - - llvm::Value *rb_type = emit_load_type(def, rb); - - llvm::BasicBlock *float_op = - llvm::BasicBlock::Create(def->jitState->context(), "float.op"); - llvm::BasicBlock *try_meta = - llvm::BasicBlock::Create(def->jitState->context(), "try_meta"); - llvm::BasicBlock *done_block = - llvm::BasicBlock::Create(def->jitState->context(), "done"); - - llvm::Value *cmp1 = - emit_is_value_of_type(def, rb_type, LUA__TNUMINT, "rb.is.integer"); - - // Check if both RB and RC are integers - llvm::BasicBlock *then_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.integer", def->f); - llvm::BasicBlock *else_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.not.integer"); - def->builder->CreateCondBr(cmp1, then_block, else_block); - def->builder->SetInsertPoint(then_block); - - // Both are integers - llvm::Instruction *lhs = emit_load_reg_i(def, rb); - llvm::Value *result = def->builder->CreateNeg(lhs, "", false, true); - - emit_store_reg_i_withtype(def, result, ra); - - def->builder->CreateBr(done_block); - - // Not integer - def->f->getBasicBlockList().push_back(else_block); - def->builder->SetInsertPoint(else_block); - - // Is RB a float? - cmp1 = emit_is_value_of_type(def, rb_type, LUA__TNUMFLT, "rb.is.float"); - - llvm::BasicBlock *convert_rb = - llvm::BasicBlock::Create(def->jitState->context(), "convert.rb"); - llvm::BasicBlock *load_rb = - llvm::BasicBlock::Create(def->jitState->context(), "load.rb"); - - // If RB is floating then load RB, else convert RB - def->builder->CreateCondBr(cmp1, load_rb, convert_rb); - - // Convert RB - def->f->getBasicBlockList().push_back(convert_rb); - def->builder->SetInsertPoint(convert_rb); - - // Call luaV_tonumber_() - llvm::Value *rb_isnum = - CreateCall2(def->builder, def->luaV_tonumberF, rb, nb); - cmp1 = - def->builder->CreateICmpEQ(rb_isnum, def->types->kInt[1], "rb.float.ok"); - - // If not number then go to meta block - // Else proceed to test RC - def->builder->CreateCondBr(cmp1, float_op, try_meta); - - def->f->getBasicBlockList().push_back(load_rb); - def->builder->SetInsertPoint(load_rb); - - // Copy RB to local nb - auto src = emit_load_reg_n(def, rb); - emit_store_local_n(def, src, nb); - - def->builder->CreateBr(float_op); - - def->f->getBasicBlockList().push_back(float_op); - def->builder->SetInsertPoint(float_op); - - lhs = emit_load_local_n(def, nb); - - result = def->builder->CreateFNeg(lhs); - - emit_store_reg_n_withtype(def, result, ra); - - def->builder->CreateBr(done_block); - - // Neither integer nor float so try meta - def->f->getBasicBlockList().push_back(try_meta); - def->builder->SetInsertPoint(try_meta); - - // before invoking metamethod set savedpc - if (!traced) emit_update_savedpc(def, pc); - CreateCall5(def->builder, def->luaT_trybinTMF, def->L, rb, rb, ra, - def->types->kInt[TM_UNM]); - def->builder->CreateBr(done_block); - - def->f->getBasicBlockList().push_back(done_block); - def->builder->SetInsertPoint(done_block); -} -} \ No newline at end of file diff --git a/src/ravi_llvmcall.cpp b/src/ravi_llvmcall.cpp deleted file mode 100644 index aa52b50..0000000 --- a/src/ravi_llvmcall.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/****************************************************************************** -* 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. -******************************************************************************/ -#include "ravi_llvmcodegen.h" - -namespace ravi { - -// OP_JMP -void RaviCodeGenerator::emit_JMP(RaviFunctionDef *def, int A, int sBx, int pc) { - - //#define dojump(ci,i,e) - // { int a = GETARG_A(i); - // if (a > 0) luaF_close(L, ci->u.l.base + a - 1); - // ci->u.l.savedpc += GETARG_sBx(i) + e; } - // - // dojump(ci, i, 0); - - assert(def->jmp_targets[sBx].jmp1); - - // If the current block is already terminated we - // need to create a new block - if (def->builder->GetInsertBlock()->getTerminator()) { - llvm::BasicBlock *jmp_block = llvm::BasicBlock::Create( - def->jitState->context(), "OP_JMP_bridge", def->f); - def->builder->SetInsertPoint(jmp_block); - } - - 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); -#ifdef RAVI_DEFER_STATEMENT - if (!traced) - emit_update_savedpc(def, pc); - // Call luaF_close - CreateCall3(def->builder, def->luaF_closeF, def->L, val, def->types->kInt[LUA_OK]); -#else - CreateCall2(def->builder, def->luaF_closeF, def->L, val); -#endif - } - - // Do the actual jump - def->builder->CreateBr(def->jmp_targets[sBx].jmp1); - - // Start new block - llvm::BasicBlock *block = llvm::BasicBlock::Create(def->jitState->context(), - "OP_JMP_postjmp", def->f); - def->builder->SetInsertPoint(block); -} - -// Handle OP_CALL -// Note that Lua assumes that functions called via OP_CALL -// are Lua functions and secondly that once OP_CALL completes the -// current function will continue within the same luaV_execute() -// call. However in a JIT case each JIT function is a different call -// so we need to take care of the behaviour differences between -// OP_CALL and external calls -void RaviCodeGenerator::emit_CALL(RaviFunctionDef *def, int A, int B, int C, - int pc) { - - // int nresults = c - 1; - // if (b != 0) - // L->top = ra + b; /* else previous instruction set top */ - // int c = luaD_precall(L, ra, nresults, 1); /* C or JITed function? */ - // if (c) { - // if (c == 1 && nresults >= 0) - // L->top = ci->top; /* adjust results if C function */ - // } - // else { /* Lua function */ - // int b = luaV_execute(L); - // if (b) L->top = ci->top; - // } - bool traced = emit_debug_trace(def, OP_CALL, pc); - // Set savedpc before the call - if (!traced) emit_update_savedpc(def, pc); - emit_load_base(def); - - // int nresults = c - 1; - int nresults = C - 1; - - // if (b != 0) - if (B != 0) { - // L->top = ra + b; /* else previous instruction set top */ - emit_set_L_top_toreg(def, A + B); - } - - // luaD_precall() returns following - // 1 - C function called, results to be adjusted - // 2 - JITed Lua function called, no action - // 0 - Run interpreter on Lua function, if returns != 0 then update L->top - - // int c = luaD_precall(L, ra, nresults, op_call); /* C or JITed function? */ - // The last parameter to luaD_precall() tells it that - // this is an OP_CALL - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *precall_result = - CreateCall4(def->builder, def->luaD_precallF, def->L, ra, - llvm::ConstantInt::get(def->types->C_intT, nresults), - def->types->kInt[1]); - - // If luaD_precall() returns 0 then we need to interpret the - // Lua function - llvm::Value *do_Lua_interp = - def->builder->CreateICmpEQ(precall_result, def->types->kInt[0]); - - llvm::BasicBlock *then_block = llvm::BasicBlock::Create( - def->jitState->context(), "OP_CALL_if_Lua_interp_function", def->f); - llvm::BasicBlock *else_block = llvm::BasicBlock::Create( - def->jitState->context(), "OP_CALL_if_not_Lua_interp_function"); - llvm::BasicBlock *end_block = - llvm::BasicBlock::Create(def->jitState->context(), "OP_CALL_done"); - def->builder->CreateCondBr(do_Lua_interp, then_block, else_block); - def->builder->SetInsertPoint(then_block); - - // Lua function, not compiled, so call luaV_execute - llvm::Value *b = def->builder->CreateCall(def->luaV_executeF, def->L); - - // If the return value is non zero then we need to refresh L->top = ci->top - llvm::Value *b_not_zero = def->builder->CreateICmpNE(b, def->types->kInt[0]); - - llvm::BasicBlock *if_b_block = llvm::BasicBlock::Create( - def->jitState->context(), "OP_CALL_if_need_reset_L_top", def->f); - def->builder->CreateCondBr(b_not_zero, if_b_block, end_block); - def->builder->SetInsertPoint(if_b_block); - - // Set L->top = ci->top - emit_refresh_L_top(def, def->ci_val); - - // We are done - def->builder->CreateBr(end_block); - - // Handle the C function or JIT case - // function already executed by luaD_precall() - def->f->getBasicBlockList().push_back(else_block); - def->builder->SetInsertPoint(else_block); - - if (nresults >= 0) { - // In case the precall returned 1 then a C function was - // called so we need to update L->top - // if (c == 1 && nresults >= 0) - // L->top = ci->top; /* adjust results if C function */ - llvm::Value *precall_C = - def->builder->CreateICmpEQ(precall_result, def->types->kInt[1]); - - llvm::BasicBlock *then1_block = llvm::BasicBlock::Create( - def->jitState->context(), "OP_CALL_if_C_function_returned_values", - def->f); - def->builder->CreateCondBr(precall_C, then1_block, end_block); - def->builder->SetInsertPoint(then1_block); - - emit_refresh_L_top(def, def->ci_val); - } - def->builder->CreateBr(end_block); - def->f->getBasicBlockList().push_back(end_block); - def->builder->SetInsertPoint(end_block); -} - -#ifdef RAVI_DEFER_STATEMENT -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); -} -#endif - -} \ No newline at end of file diff --git a/src/ravi_llvmcodegen.cpp b/src/ravi_llvmcodegen.cpp deleted file mode 100644 index 4bf6a68..0000000 --- a/src/ravi_llvmcodegen.cpp +++ /dev/null @@ -1,2084 +0,0 @@ -/****************************************************************************** - * 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. - ******************************************************************************/ -#include -#include -#include - -namespace ravi { - -RaviBranchDef::RaviBranchDef() - : jmp1(nullptr), - jmp2(nullptr), - jmp3(nullptr), - jmp4(nullptr), - ilimit(nullptr), - istep(nullptr), - iidx(nullptr), - flimit(nullptr), - fstep(nullptr), - fidx(nullptr) {} - -RaviCodeGenerator::RaviCodeGenerator(RaviJITState *jitState) - : jitState_(jitState), id_(1) { - temp_[0] = 0; -} - -const char *RaviCodeGenerator::unique_function_name() { - // Create unique name for the compiled function - // Lua functions are nameless so a compiled function has no name - // as far as Lua is concerned - snprintf(temp_, sizeof temp_, "ravif%d", id_++); - return temp_; -} - -llvm::CallInst *RaviCodeGenerator::CreateCall1(llvm::IRBuilder<> *builder, - llvm::Value *func, - llvm::Value *arg1) { - llvm::SmallVector values; - values.push_back(arg1); - return builder->CreateCall(func, values); -} - -llvm::CallInst *RaviCodeGenerator::CreateCall2(llvm::IRBuilder<> *builder, - llvm::Value *func, - llvm::Value *arg1, - llvm::Value *arg2) { - llvm::SmallVector values; - values.push_back(arg1); - values.push_back(arg2); - return builder->CreateCall(func, values); -} - -llvm::CallInst *RaviCodeGenerator::CreateCall3(llvm::IRBuilder<> *builder, - llvm::Value *func, - llvm::Value *arg1, - llvm::Value *arg2, - llvm::Value *arg3) { - llvm::SmallVector values; - values.push_back(arg1); - values.push_back(arg2); - values.push_back(arg3); - return builder->CreateCall(func, values); -} - -llvm::CallInst *RaviCodeGenerator::CreateCall4( - llvm::IRBuilder<> *builder, llvm::Value *func, llvm::Value *arg1, - llvm::Value *arg2, llvm::Value *arg3, llvm::Value *arg4) { - llvm::SmallVector values; - values.push_back(arg1); - values.push_back(arg2); - values.push_back(arg3); - values.push_back(arg4); - return builder->CreateCall(func, values); -} - -llvm::CallInst *RaviCodeGenerator::CreateCall5( - llvm::IRBuilder<> *builder, llvm::Value *func, llvm::Value *arg1, - llvm::Value *arg2, llvm::Value *arg3, llvm::Value *arg4, - llvm::Value *arg5) { - llvm::SmallVector values; - values.push_back(arg1); - values.push_back(arg2); - values.push_back(arg3); - values.push_back(arg4); - values.push_back(arg5); - return builder->CreateCall(func, values); -} - -void RaviCodeGenerator::attach_branch_weights(RaviFunctionDef *def, - llvm::Instruction *ins, - uint32_t true_branch, - uint32_t false_branch) { -#if RAVI_USE_LLVM_BRANCH_WEIGHTS - ins->setMetadata(llvm::LLVMContext::MD_prof, - def->jitState->types()->mdbuilder.createBranchWeights( - true_branch, false_branch)); -#else - (void)def; - (void)ins; - (void)true_branch; - (void)false_branch; -#endif -} - -llvm::Value *RaviCodeGenerator::emit_gep(RaviFunctionDef *def, const char *name, - llvm::Value *s, int arg1) { - llvm::SmallVector values; - values.push_back(def->types->kInt[arg1]); - return def->builder->CreateInBoundsGEP(s, values, name); -} - -llvm::Value *RaviCodeGenerator::emit_gep(RaviFunctionDef *def, const char *name, - llvm::Value *s, int arg1, int arg2) { - llvm::SmallVector values; - values.push_back(def->types->kInt[arg1]); - values.push_back(def->types->kInt[arg2]); - return def->builder->CreateInBoundsGEP(s, values, name); -} - -llvm::Value *RaviCodeGenerator::emit_gep(RaviFunctionDef *def, const char *name, - llvm::Value *s, int arg1, int arg2, - int arg3) { - llvm::SmallVector values; - values.push_back(def->types->kInt[arg1]); - values.push_back(def->types->kInt[arg2]); - values.push_back(def->types->kInt[arg3]); - return def->builder->CreateInBoundsGEP(s, values, name); -} - -llvm::Value *RaviCodeGenerator::emit_gep(RaviFunctionDef *def, const char *name, - llvm::Value *ptr, llvm::Value *offset, - int arg1) { - llvm::SmallVector values; - values.push_back(offset); - values.push_back(def->types->kInt[arg1]); - return def->builder->CreateInBoundsGEP(ptr, values, name); -} - -llvm::Value *RaviCodeGenerator::emit_gep(RaviFunctionDef *def, const char *name, - llvm::Value *ptr, llvm::Value *offset, - int arg1, int arg2) { - llvm::SmallVector values; - values.push_back(offset); - values.push_back(def->types->kInt[arg1]); - values.push_back(def->types->kInt[arg2]); - return def->builder->CreateInBoundsGEP(ptr, values, name); -} - -llvm::Value *RaviCodeGenerator::emit_array_get(RaviFunctionDef *def, - llvm::Value *ptr, int offset) { - // emit code for &ptr[offset] - return def->builder->CreateInBoundsGEP( - ptr, llvm::ConstantInt::get(def->types->C_intT, offset)); -} - -// emit code for LClosure *cl = clLvalue(ci->func); -llvm::Instruction *RaviCodeGenerator::emit_gep_ci_func_value_gc_asLClosure( - RaviFunctionDef *def) { - // clLvalue() is a macros that expands to (LClosure *)ci->func->value_.gc - // via a complex series of macros and unions - // fortunately as func is at the beginning of the CallInfo - // structure we can just cast ci to LClosure*** - // This insight is based on code generated by Clang - llvm::Value *pppLuaClosure = - def->builder->CreateBitCast(def->ci_val, def->types->pppLClosureT); - - // Load pointer to LClosure** - llvm::Instruction *ppLuaClosure = def->builder->CreateLoad(pppLuaClosure); - ppLuaClosure->setMetadata(llvm::LLVMContext::MD_tbaa, - def->types->tbaa_CallInfo_funcT); - - // Load pointer to LClosure* - llvm::Instruction *cl_ptr = def->builder->CreateLoad(ppLuaClosure); - cl_ptr->setMetadata(llvm::LLVMContext::MD_tbaa, - def->types->tbaa_CallInfo_func_LClosureT); - - return cl_ptr; -} - -// Retrieve the proto->sizep -// sizep is a count of the number of closures defined -// in the function -llvm::Instruction *RaviCodeGenerator::emit_load_proto_sizep( - RaviFunctionDef *def) { - llvm::Value *psize_ptr = emit_gep(def, "sizep", def->proto_ptr, 0, 10); - llvm::Instruction *psize = def->builder->CreateLoad(psize_ptr); - psize->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_Proto_sizepT); - return psize; -} - -// Updates the savedpc pointer in the call frame -// The savedpc is unimportant for the JIT but it is relied upon -// by the debug interface. So we need to set this in order for the -// debug api to work. Rather than setting it on every bytecode instruction -// we have a dual approach. By default the JIT code only sets this prior to -// function calls - this enables better stack traces for example, and ad-hoc -// calls to debug api. An optional setting in the JIT compiler also -// enables this to be updated per bytecode instruction - this is only -// required if someone wishes to set a line hook. The second option -// is very expensive and will inhibit optimizations, hence it is optional -// See issue #15 -void RaviCodeGenerator::emit_update_savedpc(RaviFunctionDef *def, int pc) { - // Get proto->code - llvm::Value *proto_code_ptr = emit_gep(def, "code", def->proto_ptr, 0, 15); - llvm::Instruction *code_ptr = def->builder->CreateLoad(proto_code_ptr); - code_ptr->setMetadata(llvm::LLVMContext::MD_tbaa, - def->types->tbaa_Proto_codeT); - // Need to set savedpc to the next instruction (pc+1) rather than current as - // that is - // what the VM does in interpreted mode - llvm::Value *code_offset_ptr = emit_array_get(def, code_ptr, pc + 1); - llvm::Value *savedpc_ptr = emit_gep(def, "savedpc", def->ci_val, 0, 4, 1); - llvm::Instruction *ins = - def->builder->CreateStore(code_offset_ptr, savedpc_ptr); - ins->setMetadata(llvm::LLVMContext::MD_tbaa, - def->types->tbaa_CallInfo_savedpcT); -} - -// Generate code to reload the function's stack 'base' -// pointer - the VM needs to do this after any bytecode that -// may invoke a Lua function and thereby resize the stack; which -// would invalidate the current 'base' pointer -void RaviCodeGenerator::emit_load_base(RaviFunctionDef *def) { - // Load pointer to base - llvm::Instruction *base_ptr = def->builder->CreateLoad(def->Ci_base); - base_ptr->setMetadata(llvm::LLVMContext::MD_tbaa, - def->types->tbaa_luaState_ci_baseT); - def->base_ptr = base_ptr; -} - -// emit code to obtain address of register at location A -llvm::Value *RaviCodeGenerator::emit_gep_register(RaviFunctionDef *def, int A) { - llvm::Value *dest; - if (A == 0) { - // If A is 0 we can use the base pointer which is &base[0] - dest = def->base_ptr; - } - else { - // emit &base[A] - dest = emit_array_get(def, def->base_ptr, A); - } - return dest; -} - -// Emit code to obtain address of a constant -llvm::Value *RaviCodeGenerator::emit_gep_constant(RaviFunctionDef *def, - int Bx) { - // Load pointer to k - llvm::Value *k_ptr = def->k_ptr; - llvm::Value *src; - if (Bx == 0) { - // If Bx is 0 we can use the base pointer which is &k[0] - src = k_ptr; - } - else { - // emit &k[Bx] - src = emit_array_get(def, k_ptr, Bx); - } - return src; -} - -// Loads the value at register or constant at location B - -// if the value is an integer constant -// then returns a constant literal -llvm::Value *RaviCodeGenerator::emit_load_register_or_constant_i( - RaviFunctionDef *def, int B) { - if (ISK(B) && def->p->k[INDEXK(B)].tt_ == LUA_TNUMINT) { - TValue *Konst = &def->p->k[INDEXK(B)]; - return llvm::ConstantInt::get(def->types->lua_IntegerT, Konst->value_.i); - } - else { - llvm::Value *rb = emit_gep_register_or_constant(def, B); - return emit_load_reg_i(def, rb); - } -} - -// Loads the value at register B - if the value is an number constant -// then returns a constant literal -llvm::Value *RaviCodeGenerator::emit_load_register_or_constant_n( - RaviFunctionDef *def, int B) { - if (ISK(B) && def->p->k[INDEXK(B)].tt_ == LUA_TNUMFLT) { - TValue *Konst = &def->p->k[INDEXK(B)]; - return llvm::ConstantFP::get(def->types->lua_NumberT, Konst->value_.n); - } - else { - llvm::Value *rb = emit_gep_register_or_constant(def, B); - return emit_load_reg_n(def, rb); - } -} - -// emit code to load the lua_Number value from register (TValue) -llvm::Instruction *RaviCodeGenerator::emit_load_reg_n(RaviFunctionDef *def, - llvm::Value *rb) { - llvm::Value *rb_n = def->builder->CreateBitCast(rb, def->types->plua_NumberT); - // llvm::Value *rb_n = emit_gep(def, "value.value_.n", rb, 0, 0, 0); - llvm::Instruction *lhs = def->builder->CreateLoad(rb_n); - lhs->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_nT); - return lhs; -} - -// emit code to load the lua_Integer value from register (TValue) -llvm::Instruction *RaviCodeGenerator::emit_load_reg_i(RaviFunctionDef *def, - llvm::Value *rb) { - llvm::Value *rb_n = - def->builder->CreateBitCast(rb, def->types->plua_IntegerT); - llvm::Instruction *lhs = def->builder->CreateLoad(rb_n); - lhs->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_nT); - return lhs; -} - -// emit code to load the boolean value from register (TValue) -llvm::Instruction *RaviCodeGenerator::emit_load_reg_b(RaviFunctionDef *def, - llvm::Value *rb) { - llvm::Value *rb_n = def->builder->CreateBitCast(rb, def->types->C_pintT); - llvm::Instruction *lhs = def->builder->CreateLoad(rb_n); - lhs->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_nT); - return lhs; -} - -// emit code to load the table value from register (TValue) -llvm::Instruction *RaviCodeGenerator::emit_load_reg_h(RaviFunctionDef *def, - llvm::Value *rb) { - llvm::Value *rb_h = def->builder->CreateBitCast(rb, def->types->ppTableT); - llvm::Instruction *h = def->builder->CreateLoad(rb_h); - h->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_hT); - return h; -} - -// emit code to load the RaviArray value from register (TValue) -llvm::Instruction* RaviCodeGenerator::emit_load_reg_arr(RaviFunctionDef* def, - llvm::Value* rb) { - llvm::Value* rb_h = def->builder->CreateBitCast(rb, def->types->ppRaviArrayT); - llvm::Instruction* h = def->builder->CreateLoad(rb_h); - h->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_hT); - return h; -} - -// Gets the size of the hash table -// This is the sizenode() macro in lobject.h -llvm::Value *RaviCodeGenerator::emit_table_get_hashsize(RaviFunctionDef *def, - llvm::Value *t) { - // Obtain the lsizenode of the hash table - llvm::Value *lsizenode_ptr = emit_gep(def, "lsizenode", t, 0, 4); - llvm::Instruction *lsizenode = def->builder->CreateLoad(lsizenode_ptr); - lsizenode->setMetadata(llvm::LLVMContext::MD_tbaa, - def->types->tbaa_Table_lsizenode); - // convert to integer (lsizenode is a byte) - llvm::Value *intsize = - def->builder->CreateZExt(lsizenode, def->types->C_intT); - // #define twoto(x) (1<<(x)) - // #define sizenode(t) (twoto((t)->lsizenode)) - llvm::Value *size = def->builder->CreateShl(def->types->kInt[1], intsize); - return size; -} - -// Gets the location of the hash node for given string key -// return value is the offset into the node array -llvm::Value *RaviCodeGenerator::emit_table_get_hashstr(RaviFunctionDef *def, - llvm::Value *table, - TString *key) { -#if RAVI_USE_NEWHASH - unsigned int hash = key->hash; - llvm::Value *hmask_ptr = emit_gep(def, "hmask", table, 0, 11); - llvm::Instruction *hmask = def->builder->CreateLoad(hmask_ptr); - hmask->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_Table_hmask); - llvm::Value *offset = def->builder->CreateAnd( - llvm::ConstantInt::get(def->types->C_intT, hash), hmask); -#else - llvm::Value *size = emit_table_get_hashsize(def, table); - unsigned int hash = key->hash; - // #define lmod(s,size) (cast(int, (s) & ((size)-1))) - llvm::Value *sizeminusone = - def->builder->CreateNSWSub(size, def->types->kInt[1]); - llvm::Value *offset = def->builder->CreateAnd( - llvm::ConstantInt::get(def->types->C_intT, hash), sizeminusone); -#endif - return offset; -} - -// Gets access to the Table's node array (t->node) -llvm::Value *RaviCodeGenerator::emit_table_get_nodearray(RaviFunctionDef *def, - llvm::Value *table) { - // Get access to the node array - llvm::Value *node_ptr = emit_gep(def, "node", table, 0, 7); - llvm::Instruction *node = def->builder->CreateLoad(node_ptr); - node->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_Table_node); - return node; -} - -// Given a pointer to table's node array (node = t->node) and -// the location of the hashed key (index), this method retrieves the -// type of the value stored at the node - return value is of type int -// and is the type information stored in TValue->tt field. -llvm::Value *RaviCodeGenerator::emit_table_get_keytype(RaviFunctionDef *def, - llvm::Value *node, - llvm::Value *index) { - llvm::Value *ktype_ptr = emit_gep(def, "keytype", node, index, 1, 1); - llvm::Instruction *ktype = def->builder->CreateLoad(ktype_ptr); - ktype->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_ttT); - return ktype; -} - -// Given a pointer to table's node array (node = t->node) and -// the location of the hashed key (index), this method retrieves the -// the string value stored at the node - return value is of type TString* -llvm::Value *RaviCodeGenerator::emit_table_get_strkey(RaviFunctionDef *def, - llvm::Value *node, - llvm::Value *index) { - llvm::Value *value_ptr = emit_gep(def, "keyvalue", node, index, 1, 0); - llvm::Value *sptr = - def->builder->CreateBitCast(value_ptr, def->types->ppTStringT); - llvm::Instruction *keyvalue = def->builder->CreateLoad(sptr); - keyvalue->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_ppointerT); - return keyvalue; -} - -// Given a pointer to table's node array (node = t->node) and -// the location of the hashed key (index), this method retrieves the -// the pointer to value stored at the node - return value is of type TValue* -llvm::Value *RaviCodeGenerator::emit_table_get_value(RaviFunctionDef *def, - llvm::Value *node, - llvm::Value *index) { - return emit_gep(def, "nodeval", node, index, 0); -} - -// Gets the size of the table's array part -llvm::Value *RaviCodeGenerator::emit_table_get_arraysize(RaviFunctionDef *def, - llvm::Value *table) { - // Obtain the lsizenode of the hash table - llvm::Value *sizearray_ptr = emit_gep(def, "sizearray", table, 0, 5); - llvm::Instruction *sizearray = def->builder->CreateLoad(sizearray_ptr); - sizearray->setMetadata(llvm::LLVMContext::MD_tbaa, - def->types->tbaa_Table_sizearray); - return sizearray; -} - -llvm::Value *RaviCodeGenerator::emit_table_get_array(RaviFunctionDef *def, - llvm::Value *table) { - // Get access to the node array - llvm::Value *array_ptr = emit_gep(def, "array", table, 0, 6); - llvm::Instruction *arry = def->builder->CreateLoad(array_ptr); - arry->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_Table_array); - return arry; -} - -llvm::Instruction *RaviCodeGenerator::emit_load_reg_s(RaviFunctionDef *def, - llvm::Value *rb) { - llvm::Value *rb_s = def->builder->CreateBitCast(rb, def->types->ppTStringT); - llvm::Instruction *s = def->builder->CreateLoad(rb_s); - // Following TBAA is okay as the field type is a pointer - s->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_hT); - return s; -} - -/* Loads the data pointer as lua_Number[] from a RaviArray object */ -llvm::Instruction *RaviCodeGenerator::emit_load_reg_h_floatarray( - RaviFunctionDef *def, llvm::Instruction *h) { - llvm::Value *data_ptr = emit_gep(def, "data_ptr", h, 0, 7); - llvm::Value *darray_ptr = - def->builder->CreateBitCast(data_ptr, def->types->pplua_NumberT); - llvm::Instruction *darray = def->builder->CreateLoad(darray_ptr); - darray->setMetadata(llvm::LLVMContext::MD_tbaa, - def->types->tbaa_RaviArray_dataT); - return darray; -} - -/* Loads the data pointer as lua_Integer[] from a RaviArray object */ -llvm::Instruction *RaviCodeGenerator::emit_load_reg_h_intarray( - RaviFunctionDef *def, llvm::Instruction *h) { - llvm::Value *data_ptr = emit_gep(def, "data_ptr", h, 0, 7); - llvm::Value *darray_ptr = - def->builder->CreateBitCast(data_ptr, def->types->pplua_IntegerT); - llvm::Instruction *darray = def->builder->CreateLoad(darray_ptr); - darray->setMetadata(llvm::LLVMContext::MD_tbaa, - def->types->tbaa_RaviArray_dataT); - return darray; -} - -void RaviCodeGenerator::emit_store_reg_n(RaviFunctionDef *def, - llvm::Value *result, - llvm::Value *dest_ptr) { - llvm::Value *ra_n = - def->builder->CreateBitCast(dest_ptr, def->types->plua_NumberT); - // llvm::Value *ra_n = emit_gep(def, "value.value_.n", dest_ptr, 0, 0, 0); - llvm::Instruction *store = def->builder->CreateStore(result, ra_n); - store->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_nT); -} - -void RaviCodeGenerator::emit_store_reg_n_withtype(RaviFunctionDef *def, - llvm::Value *result, - llvm::Value *dest_ptr) { - emit_store_reg_n(def, result, dest_ptr); - emit_store_type_(def, dest_ptr, LUA_TNUMFLT); -} - -void RaviCodeGenerator::emit_store_reg_i(RaviFunctionDef *def, - llvm::Value *result, - llvm::Value *dest_ptr) { - llvm::Value *ra_n = - def->builder->CreateBitCast(dest_ptr, def->types->plua_IntegerT); - llvm::Instruction *store = def->builder->CreateStore(result, ra_n); - store->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_nT); -} - -void RaviCodeGenerator::emit_store_reg_i_withtype(RaviFunctionDef *def, - llvm::Value *result, - llvm::Value *dest_ptr) { - emit_store_reg_i(def, result, dest_ptr); - emit_store_type_(def, dest_ptr, LUA_TNUMINT); -} - -void RaviCodeGenerator::emit_store_reg_b(RaviFunctionDef *def, - llvm::Value *result, - llvm::Value *dest_ptr) { - llvm::Value *ra_n = - def->builder->CreateBitCast(dest_ptr, def->types->C_pintT); - llvm::Instruction *store = def->builder->CreateStore(result, ra_n); - store->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_nT); -} - -void RaviCodeGenerator::emit_store_reg_b_withtype(RaviFunctionDef *def, - llvm::Value *result, - llvm::Value *dest_ptr) { - emit_store_reg_b(def, result, dest_ptr); - emit_store_type_(def, dest_ptr, LUA_TBOOLEAN); -} - -void RaviCodeGenerator::emit_store_type_(RaviFunctionDef *def, - llvm::Value *value, int type) { - lua_assert(type == LUA_TNUMFLT || type == LUA_TNUMINT || - type == LUA_TBOOLEAN || type == LUA_TNIL); - llvm::Value *desttype = emit_gep(def, "dest.tt", value, 0, 1); - llvm::Instruction *store = def->builder->CreateStore( - llvm::ConstantInt::get(def->types->lua_LuaTypeT, type), - desttype); - store->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_ttT); -} - -llvm::Instruction *RaviCodeGenerator::emit_load_type(RaviFunctionDef *def, - llvm::Value *value) { - llvm::Value *tt_ptr = emit_gep(def, "value.tt.ptr", value, 0, 1); - llvm::Instruction *tt = def->builder->CreateLoad(tt_ptr, "value.tt"); - tt->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_ttT); - return tt; -} - -llvm::Value *RaviCodeGenerator::emit_is_value_of_type(RaviFunctionDef *def, - llvm::Value *value_type, - LuaTypeCode lua_type, - const char *varname) { - return def->builder->CreateICmpEQ( - value_type, llvm::ConstantInt::get(def->types->lua_LuaTypeT, lua_type), - varname); -} - -llvm::Value *RaviCodeGenerator::emit_is_not_value_of_type( - RaviFunctionDef *def, llvm::Value *value_type, LuaTypeCode lua_type, - const char *varname) { - return def->builder->CreateICmpNE( - value_type, llvm::ConstantInt::get(def->types->lua_LuaTypeT, lua_type), - varname); -} - -// Compare without variants i.e. ttnov(value_type) == lua_type -llvm::Value *RaviCodeGenerator::emit_is_not_value_of_type_class( - RaviFunctionDef *def, llvm::Value *value_type, int lua_type, - const char *varname) { - llvm::Value *novariant_type = def->builder->CreateAnd( - value_type, llvm::ConstantInt::get(def->types->lua_LuaTypeT, 0x000F)); - return def->builder->CreateICmpNE( - novariant_type, - llvm::ConstantInt::get(def->types->lua_LuaTypeT, lua_type), varname); -} - -/* This loads the RaviArray type value from the tt field maintained in the - GC part. However this tt is 8-bit value and needs to be converted to - the 16-bit value used in TValue objects */ -//llvm::Instruction *RaviCodeGenerator::emit_load_ravi_arraytype( -// RaviFunctionDef *def, llvm::Value *value) { -// llvm::Value *tt_ptr = emit_gep(def, "raviarray.type_ptr", value, 0, 1); -// llvm::Instruction *tt = def->builder->CreateLoad(tt_ptr, "raviarray.type"); -// // FIXME promote to 16 bit and set collectible bit -// tt->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_RaviArray_typeT); -// return tt; -//} - -llvm::Instruction *RaviCodeGenerator::emit_load_ravi_arraylength( - RaviFunctionDef *def, llvm::Value *value) { - llvm::Value *tt_ptr = emit_gep(def, "raviarray.len_ptr", value, 0, 4); - llvm::Instruction *tt = def->builder->CreateLoad(tt_ptr, "raviarray.len"); - tt->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_RaviArray_lenT); - return tt; -} - -// Tests following: -// ((t) == NULL) || ((t)->flags & (1u<builder->CreateLoad(metatable_ptr, "table.metatable"); - metatable->setMetadata(llvm::LLVMContext::MD_tbaa, - def->types->tbaa_Table_metatable); - llvm::Value *null_constant = - llvm::ConstantPointerNull::get(def->types->pTableT); - llvm::Value *is_null = def->builder->CreateICmpEQ( - def->builder->CreatePtrToInt(null_constant, def->types->C_intptr_t), - def->builder->CreatePtrToInt(metatable, def->types->C_intptr_t)); - - // Is metatable->flags & (1<builder->CreateLoad(flags_ptr, "table.flags"); - flags->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_Table_flags); - llvm::Value *no_event = def->builder->CreateICmpNE( - def->builder->CreateAnd( - flags, llvm::ConstantInt::get(def->types->lu_byteT, 1u << event)), - llvm::ConstantInt::get(def->types->lu_byteT, 0)); - - llvm::Value *metaabsent = - def->builder->CreateOr(is_null, no_event, "metatable.isnull.or.no.event"); - return metaabsent; -} - -// Store lua_Number or lua_Integer -llvm::Instruction *RaviCodeGenerator::emit_store_local_n(RaviFunctionDef *def, - llvm::Value *src, - llvm::Value *dest) { - llvm::Instruction *ins = def->builder->CreateStore(src, dest); - ins->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_plonglongT); - return ins; -} - -// Load lua_Number or lua_Integer -llvm::Instruction *RaviCodeGenerator::emit_load_local_n(RaviFunctionDef *def, - llvm::Value *src) { - llvm::Instruction *ins = def->builder->CreateLoad(src); - ins->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_plonglongT); - return ins; -} - -// Store int -llvm::Instruction *RaviCodeGenerator::emit_store_local_int(RaviFunctionDef *def, - llvm::Value *src, - llvm::Value *dest) { - llvm::Instruction *ins = def->builder->CreateStore(src, dest); - ins->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_pintT); - return ins; -} - -// Load int -llvm::Instruction *RaviCodeGenerator::emit_load_local_int(RaviFunctionDef *def, - llvm::Value *src) { - llvm::Instruction *ins = def->builder->CreateLoad(src); - ins->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_pintT); - return ins; -} - -// emit code to obtain address of register or constant at location B -llvm::Value *RaviCodeGenerator::emit_gep_register_or_constant( - RaviFunctionDef *def, int B) { - // Load pointer to k - llvm::Value *k_ptr = def->k_ptr; - llvm::Value *rb; - // Get pointer to register B - llvm::Value *base_or_k = ISK(B) ? k_ptr : def->base_ptr; - int b = ISK(B) ? INDEXK(B) : B; - if (b == 0) { rb = base_or_k; } - else { - rb = emit_array_get(def, base_or_k, b); - } - return rb; -} - -#if 0 -// Test if ci->jistatus is true, ci is of type CallInfo -llvm::Value *RaviCodeGenerator::emit_is_jit_call(RaviFunctionDef *def, - llvm::Value *ci) { - // Get pointer to ci->jitstatus - llvm::Value *ci_jitstatus_ptr = emit_gep(def, "ci_jit_status_ptr", ci, 0, 9); - - // Load ci->jitstatus - llvm::Instruction *ci_jitstatus = def->builder->CreateLoad(ci_jitstatus_ptr); - ci_jitstatus->setMetadata(llvm::LLVMContext::MD_tbaa, - def->types->tbaa_CallInfo_jitstatusT); - - return def->builder->CreateICmpNE( - ci_jitstatus, llvm::ConstantInt::get(def->types->lu_byteT, 0), - "jit_call"); -} - -// Return (ci->callstatus & CIST_LUA) != 0 -llvm::Value *RaviCodeGenerator::emit_ci_is_Lua(RaviFunctionDef *def, - llvm::Value *ci) { - // Get pointer to ci->callstatus - llvm::Value *ci_callstatus_ptr = - emit_gep(def, "ci_call_status_ptr", ci, 0, 7); - - // Load ci->callstatus - llvm::Instruction *ci_callstatus = - def->builder->CreateLoad(ci_callstatus_ptr, "ci_call_status"); - ci_callstatus->setMetadata(llvm::LLVMContext::MD_tbaa, - def->types->tbaa_CallInfo_callstatusT); - - llvm::Value *isLua = def->builder->CreateAnd( - ci_callstatus, llvm::ConstantInt::get(def->types->C_shortT, CIST_LUA), - "isLua"); - return def->builder->CreateICmpNE( - isLua, llvm::ConstantInt::get(def->types->C_shortT, 0)); -} -#endif - -llvm::Value *RaviCodeGenerator::emit_load_ci(RaviFunctionDef *def) { - llvm::Value *L_ci = emit_gep(def, "L_ci", def->L, 0, 6); - - llvm::Instruction *ci_val = def->builder->CreateLoad(L_ci); - ci_val->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_CallInfoT); - - return ci_val; -} - -// L->top = ci->top -void RaviCodeGenerator::emit_refresh_L_top(RaviFunctionDef *def, - llvm::Value *ci_val) { - // Get pointer to ci->top - llvm::Value *citop = emit_gep(def, "ci_top", ci_val, 0, 1); - - // Load ci->top - llvm::Instruction *citop_val = def->builder->CreateLoad(citop); - citop_val->setMetadata(llvm::LLVMContext::MD_tbaa, - def->types->tbaa_CallInfo_topT); - - // Get L->top - llvm::Value *top = emit_gep(def, "L_top", def->L, 0, 4); - - // Assign ci>top to L->top - auto ins = def->builder->CreateStore(citop_val, top); - ins->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_luaState_topT); -} - -llvm::Value *RaviCodeGenerator::emit_gep_L_top(RaviFunctionDef *def) { - // Get pointer to L->top - return emit_gep(def, "L.top", def->L, 0, 4); -} - -// L->top = R(B) -void RaviCodeGenerator::emit_set_L_top_toreg(RaviFunctionDef *def, int B) { - // Get pointer to register at R(B) - llvm::Value *ptr = emit_gep_register(def, B); - // Get pointer to L->top - llvm::Value *top = emit_gep_L_top(def); - // Assign to L->top - llvm::Instruction *ins = def->builder->CreateStore(ptr, top); - ins->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_luaState_topT); -} - -llvm::Instruction *RaviCodeGenerator::emit_tointeger(RaviFunctionDef *def, - llvm::Value *reg) { - llvm::IRBuilder<> TmpB(def->entry, def->entry->begin()); - llvm::Value *value = - TmpB.CreateAlloca(def->types->lua_IntegerT, nullptr, "value"); - llvm::Value *reg_type = emit_load_type(def, reg); - - // Is reg an integer? - llvm::Value *cmp1 = - emit_is_value_of_type(def, reg_type, LUA__TNUMINT, "reg.is.integer"); - - llvm::BasicBlock *convert_reg = - llvm::BasicBlock::Create(def->jitState->context(), "convert.reg"); - llvm::BasicBlock *copy_reg = - llvm::BasicBlock::Create(def->jitState->context(), "copy.reg"); - llvm::BasicBlock *load_val = - llvm::BasicBlock::Create(def->jitState->context(), "load.val"); - llvm::BasicBlock *failed_conversion = llvm::BasicBlock::Create( - def->jitState->context(), "if.conversion.failed"); - - // If reg is integer then copy reg, else convert reg - auto brinst1 = def->builder->CreateCondBr(cmp1, copy_reg, convert_reg); - attach_branch_weights(def, brinst1, 100, 0); - - // Convert RB - def->f->getBasicBlockList().push_back(convert_reg); - def->builder->SetInsertPoint(convert_reg); - - llvm::Value *var_isint = - CreateCall2(def->builder, def->luaV_tointegerF, reg, value); - llvm::Value *tobool = def->builder->CreateICmpEQ( - var_isint, def->types->kInt[0], "conversion.failed"); - - // Did conversion fail? - def->builder->CreateCondBr(tobool, failed_conversion, load_val); - - // Conversion failed, so raise error - def->f->getBasicBlockList().push_back(failed_conversion); - def->builder->SetInsertPoint(failed_conversion); - emit_raise_lua_error(def, "integer expected"); - def->builder->CreateBr(load_val); - - // Conversion OK - def->f->getBasicBlockList().push_back(copy_reg); - def->builder->SetInsertPoint(copy_reg); - - llvm::Value *i = emit_load_reg_i(def, reg); - emit_store_local_int(def, i, value); - def->builder->CreateBr(load_val); - - def->f->getBasicBlockList().push_back(load_val); - def->builder->SetInsertPoint(load_val); - - return emit_load_local_int(def, value); -} - -llvm::Instruction *RaviCodeGenerator::emit_tofloat(RaviFunctionDef *def, - llvm::Value *reg) { - llvm::IRBuilder<> TmpB(def->entry, def->entry->begin()); - llvm::Value *value = - TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "value"); - llvm::Value *reg_type = emit_load_type(def, reg); - - // Is reg an number? - llvm::Value *cmp1 = - emit_is_value_of_type(def, reg_type, LUA__TNUMFLT, "reg.is.float"); - - llvm::BasicBlock *convert_reg = - llvm::BasicBlock::Create(def->jitState->context(), "convert.reg"); - llvm::BasicBlock *copy_reg = - llvm::BasicBlock::Create(def->jitState->context(), "copy.reg"); - llvm::BasicBlock *load_val = - llvm::BasicBlock::Create(def->jitState->context(), "load.val"); - llvm::BasicBlock *failed_conversion = llvm::BasicBlock::Create( - def->jitState->context(), "if.conversion.failed"); - - // If reg is integer then copy reg, else convert reg - auto brinst1 = def->builder->CreateCondBr(cmp1, copy_reg, convert_reg); - attach_branch_weights(def, brinst1, 100, 0); - - // Convert RB - def->f->getBasicBlockList().push_back(convert_reg); - def->builder->SetInsertPoint(convert_reg); - - llvm::Value *var_isfloat = - CreateCall2(def->builder, def->luaV_tonumberF, reg, value); - llvm::Value *tobool = def->builder->CreateICmpEQ( - var_isfloat, def->types->kInt[0], "conversion.failed"); - - // Did conversion fail? - def->builder->CreateCondBr(tobool, failed_conversion, load_val); - - // Conversion failed, so raise error - def->f->getBasicBlockList().push_back(failed_conversion); - def->builder->SetInsertPoint(failed_conversion); - emit_raise_lua_error(def, "number expected"); - def->builder->CreateBr(load_val); - - // Conversion OK - def->f->getBasicBlockList().push_back(copy_reg); - def->builder->SetInsertPoint(copy_reg); - - llvm::Value *i = emit_load_reg_n(def, reg); - emit_store_local_n(def, i, value); - def->builder->CreateBr(load_val); - - def->f->getBasicBlockList().push_back(load_val); - def->builder->SetInsertPoint(load_val); - - return emit_load_local_n(def, value); -} - -// (int)(L->top - ra) -llvm::Value *RaviCodeGenerator::emit_num_stack_elements(RaviFunctionDef *def, - llvm::Value *ra) { - llvm::Value *L_top = emit_gep_L_top(def); - llvm::Instruction *top_ptr = def->builder->CreateLoad(L_top, "L_top_ptr"); - llvm::Value *top_asint = def->builder->CreatePtrToInt( - top_ptr, def->types->C_intptr_t, "L_top_ptr_as_int"); - llvm::Value *ra_asint = - def->builder->CreatePtrToInt(ra, def->types->C_intptr_t, "ra_ptr_as_int"); - llvm::Value *diff = - def->builder->CreateSub(top_asint, ra_asint, "L_top_minus_ra"); - // Because each value object is 16 bytes we need to divide by 16 - llvm::Value *n_elements = def->builder->CreateSDiv( - diff, llvm::ConstantInt::get(def->types->C_intptr_t, sizeof(TValue)), - "num_tvalue_elements", true); - return def->builder->CreateTrunc(n_elements, def->types->C_intT, - "num_stack_elements"); -} - -// Check if we can compile -// The cases we can compile will increase over time -bool RaviCodeGenerator::canCompile(Proto *p) { - if (p->ravi_jit.jit_status == RAVI_JIT_CANT_COMPILE) return false; - if (jitState_ == nullptr) { - p->ravi_jit.jit_status = RAVI_JIT_CANT_COMPILE; - return false; - } - // const Instruction *code = p->code; - // int pc, n = p->sizecode; - // Loop over the byte codes; as Lua compiler inserts - // an extra RETURN op we need to ignore the last op - // for (pc = 0; pc < n; pc++) { - // Instruction i = code[pc]; - // OpCode o = GET_OPCODE(i); - // if (o == OP_EXTRAARG) - // return false; - // else if (o == OP_RAVI_UNMF || o == OP_RAVI_UNMI) { - // fprintf(stderr, "Unexpected bytecode %d\n", o); - // abort(); - // } - //} - return true; -} - -std::unique_ptr RaviCodeGenerator::create_function( - Proto *p, std::shared_ptr module, llvm::IRBuilder<> &builder, - RaviFunctionDef *def) { - LuaLLVMTypes *types = jitState_->types(); - - std::unique_ptr func = - std::unique_ptr(new RaviJITFunction( - &p->ravi_jit.jit_function, module, types->jitFunctionT, - llvm::Function::ExternalLinkage, unique_function_name())); - if (!func) return func; - - llvm::Function *mainFunc = func->function(); - llvm::BasicBlock *entry = - llvm::BasicBlock::Create(jitState_->context(), "entry", mainFunc); - builder.SetInsertPoint(entry); - - auto argiter = mainFunc->arg_begin(); - llvm::Value *arg1 = &(*argiter); - arg1->setName("L"); - - def->jitState = jitState_; - def->f = mainFunc; - def->entry = entry; - def->L = arg1; - def->raviF = func.get(); - def->types = types; - def->builder = &builder; - - return func; -} - -#if 0 -void RaviCodeGenerator::emit_dump_stack(RaviFunctionDef *def, const char *str) { - CreateCall2(def->builder, def->ravi_dump_stackF, def->L, - def->builder->CreateGlobalStringPtr(str)); -} - -void RaviCodeGenerator::emit_dump_stacktop(RaviFunctionDef *def, - const char *str) { - CreateCall2(def->builder, def->ravi_dump_stacktopF, def->L, - def->builder->CreateGlobalStringPtr(str)); -} -#endif - -// Emit a call to ravi_debug_trace() function. -// This function will set savedpc and also invoke -// "line" hook if defined -bool RaviCodeGenerator::emit_debug_trace(RaviFunctionDef *def, int opCode, - int pc) { - if (def->jitState->is_tracehook_enabled()) { - CreateCall3(def->builder, def->ravi_debug_traceF, def->L, - llvm::ConstantInt::get(def->types->C_intT, opCode), - llvm::ConstantInt::get(def->types->C_intT, pc)); - return true; - } - return false; -} - -void RaviCodeGenerator::emit_raise_lua_error(RaviFunctionDef *def, - const char *str) { - CreateCall2(def->builder, def->luaG_runerrorF, def->L, - def->builder->CreateGlobalStringPtr(str)); -} - -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) { -#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) { -#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) { -#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) { -#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) { - // Add extern declarations for Lua functions that we need to call - def->luaT_trybinTMF = def->raviF->addExternFunction( - def->types->luaT_trybinTMT, reinterpret_cast(&luaT_trybinTM), - "luaT_trybinTM"); - def->luaD_callF = def->raviF->addExternFunction( - def->types->luaD_callT, reinterpret_cast(&luaD_call), - "luaD_call"); - def->luaD_poscallF = def->raviF->addExternFunction( - def->types->luaD_poscallT, reinterpret_cast(&luaD_poscall), - "luaD_poscall"); - def->luaD_precallF = def->raviF->addExternFunction( - def->types->luaD_precallT, reinterpret_cast(&luaD_precall), - "luaD_precall"); - def->luaF_closeF = def->raviF->addExternFunction( - def->types->luaF_closeT, reinterpret_cast(&luaF_close), - "luaF_close"); - def->luaG_runerrorF = def->raviF->addExternFunction( - def->types->luaG_runerrorT, reinterpret_cast(&luaG_runerror), - "luaG_runerror"); - def->luaG_runerrorF->setDoesNotReturn(); - def->luaV_equalobjF = def->raviF->addExternFunction( - def->types->luaV_equalobjT, reinterpret_cast(&luaV_equalobj), - "luaV_equalobj"); - def->luaV_lessthanF = def->raviF->addExternFunction( - def->types->luaV_lessthanT, reinterpret_cast(&luaV_lessthan), - "luaV_lessthan"); - def->luaV_lessequalF = def->raviF->addExternFunction( - def->types->luaV_lessequalT, reinterpret_cast(&luaV_lessequal), - "luaV_lessequal"); - def->luaV_forlimitF = def->raviF->addExternFunction( - def->types->luaV_forlimitT, reinterpret_cast(&luaV_forlimit), - "luaV_forlimit"); - def->luaV_tonumberF = def->raviF->addExternFunction( - def->types->luaV_tonumberT, reinterpret_cast(&luaV_tonumber_), - "luaV_tonumber_"); - def->luaV_tointegerF = def->raviF->addExternFunction( - def->types->luaV_tointegerT, reinterpret_cast(&luaV_tointeger_), - "luaV_tointeger_"); - def->luaV_executeF = def->raviF->addExternFunction( - def->types->luaV_executeT, reinterpret_cast(&luaV_execute), - "luaV_execute"); - def->luaV_settableF = def->raviF->addExternFunction( - def->types->luaV_settableT, reinterpret_cast(&luaV_settable), - "luaV_settable"); - def->luaV_gettableF = def->raviF->addExternFunction( - def->types->luaV_gettableT, reinterpret_cast(&luaV_gettable), - "luaV_gettable"); - def->luaH_getintF = def->raviF->addExternFunction( - def->types->luaH_getintT, reinterpret_cast(&luaH_getint), - "luaH_getint"); - def->luaH_setintF = def->raviF->addExternFunction( - def->types->luaH_setintT, reinterpret_cast(&luaH_setint), - "luaH_setint"); - def->luaH_getstrF = def->raviF->addExternFunction( - def->types->luaH_getstrT, reinterpret_cast(&luaH_getstr), - "luaH_getstr"); - def->luaH_getstrF->addFnAttr(llvm::Attribute::AttrKind::ReadOnly); - // def->luaH_getstrF->setDoesNotAlias(1); - // def->luaH_getstrF->setDoesNotCapture(1); - // def->luaH_getstrF->setDoesNotAlias(2); - // def->luaH_getstrF->setDoesNotCapture(2); - def->luaV_finishgetF = def->raviF->addExternFunction( - def->types->luaV_finishgetT, reinterpret_cast(&luaV_finishget), - "luaV_finishget"); - - def->raviV_op_loadnilF = def->raviF->addExternFunction( - def->types->raviV_op_loadnilT, - reinterpret_cast(&raviV_op_loadnil), "raviV_op_loadnil"); - def->raviV_op_newarrayintF = def->raviF->addExternFunction( - def->types->raviV_op_newarrayintT, - reinterpret_cast(&raviV_op_newarrayint), "raviV_op_newarrayint"); - def->raviV_op_newarrayfloatF = def->raviF->addExternFunction( - def->types->raviV_op_newarrayfloatT, - reinterpret_cast(&raviV_op_newarrayfloat), - "raviV_op_newarrayfloat"); - def->raviV_op_newtableF = def->raviF->addExternFunction( - def->types->raviV_op_newtableT, - reinterpret_cast(&raviV_op_newtable), "raviV_op_newtable"); - def->raviV_op_setlistF = def->raviF->addExternFunction( - def->types->raviV_op_setlistT, - reinterpret_cast(&raviV_op_setlist), "raviV_op_setlist"); - def->luaV_modF = def->raviF->addExternFunction( - def->types->luaV_modT, reinterpret_cast(&luaV_mod), "luaV_mod"); - def->luaV_idivF = def->raviF->addExternFunction( - def->types->luaV_idivT, reinterpret_cast(&luaV_idiv), "luaV_idiv"); - def->luaV_objlenF = def->raviF->addExternFunction( - def->types->luaV_objlenT, reinterpret_cast(&luaV_objlen), - "luaV_objlen"); - def->luaC_upvalbarrierF = def->raviF->addExternFunction( - def->types->luaC_upvalbarrierT, - reinterpret_cast(&luaC_upvalbarrier_compat), "luaC_upvalbarrier_"); - def->raviV_op_concatF = def->raviF->addExternFunction( - def->types->raviV_op_concatT, reinterpret_cast(&raviV_op_concat), - "raviV_op_concat"); - def->raviV_op_closureF = def->raviF->addExternFunction( - def->types->raviV_op_closureT, - reinterpret_cast(&raviV_op_closure), "raviV_op_closure"); - def->raviV_op_varargF = def->raviF->addExternFunction( - def->types->raviV_op_varargT, reinterpret_cast(&raviV_op_vararg), - "raviV_op_vararg"); - def->raviH_set_intF = def->raviF->addExternFunction( - def->types->raviH_set_intT, reinterpret_cast(&raviH_set_int), - "raviH_set_int"); - def->raviH_set_floatF = def->raviF->addExternFunction( - def->types->raviH_set_floatT, reinterpret_cast(&raviH_set_float), - "raviH_set_float"); - def->raviV_op_shlF = def->raviF->addExternFunction( - def->types->raviV_op_shlT, reinterpret_cast(&raviV_op_shl), - "raviV_op_shl"); - def->raviV_op_shrF = def->raviF->addExternFunction( - def->types->raviV_op_shrT, reinterpret_cast(&raviV_op_shr), - "raviV_op_shr"); - def->raviV_op_borF = def->raviF->addExternFunction( - def->types->raviV_op_borT, reinterpret_cast(&raviV_op_bor), - "raviV_op_bor"); - def->raviV_op_bxorF = def->raviF->addExternFunction( - def->types->raviV_op_bxorT, reinterpret_cast(&raviV_op_bxor), - "raviV_op_bxor"); - def->raviV_op_bandF = def->raviF->addExternFunction( - def->types->raviV_op_bandT, reinterpret_cast(&raviV_op_band), - "raviV_op_band"); - def->raviV_op_bnotF = def->raviF->addExternFunction( - def->types->raviV_op_bnotT, reinterpret_cast(&raviV_op_bnot), - "raviV_op_bnot"); - def->raviV_op_addF = def->raviF->addExternFunction( - def->types->raviV_op_addT, reinterpret_cast(&raviV_op_add), - "raviV_op_add"); - def->raviV_op_subF = def->raviF->addExternFunction( - def->types->raviV_op_subT, reinterpret_cast(&raviV_op_sub), - "raviV_op_sub"); - def->raviV_op_mulF = def->raviF->addExternFunction( - def->types->raviV_op_mulT, reinterpret_cast(&raviV_op_mul), - "raviV_op_mul"); - def->raviV_op_divF = def->raviF->addExternFunction( - def->types->raviV_op_divT, reinterpret_cast(&raviV_op_div), - "raviV_op_div"); - def->raviV_op_setupvaliF = def->raviF->addExternFunction( - def->types->raviV_op_setupvaliT, - reinterpret_cast(&raviV_op_setupvali), "raviV_op_setupvali"); - def->raviV_op_setupvalfF = def->raviF->addExternFunction( - def->types->raviV_op_setupvalfT, - reinterpret_cast(&raviV_op_setupvalf), "raviV_op_setupvalf"); - def->raviV_op_setupvalaiF = def->raviF->addExternFunction( - def->types->raviV_op_setupvalaiT, - reinterpret_cast(&raviV_op_setupvalai), "raviV_op_setupvalai"); - def->raviV_op_setupvalafF = def->raviF->addExternFunction( - def->types->raviV_op_setupvalafT, - reinterpret_cast(&raviV_op_setupvalaf), "raviV_op_setupvalaf"); - def->raviV_op_setupvaltF = def->raviF->addExternFunction( - def->types->raviV_op_setupvaltT, - reinterpret_cast(&raviV_op_setupvalt), "raviV_op_setupvalt"); - def->raviV_settable_sskeyF = def->raviF->addExternFunction( - def->types->raviV_settable_sskeyT, - reinterpret_cast(&raviV_settable_sskey), "raviV_settable_sskey"); - def->raviV_gettable_sskeyF = def->raviF->addExternFunction( - def->types->raviV_gettable_sskeyT, - reinterpret_cast(&raviV_gettable_sskey), "raviV_gettable_sskey"); - def->raviV_settable_iF = def->raviF->addExternFunction( - def->types->raviV_settable_iT, - reinterpret_cast(&raviV_settable_i), "raviV_settable_i"); - def->raviV_gettable_iF = def->raviF->addExternFunction( - def->types->raviV_gettable_iT, - reinterpret_cast(&raviV_gettable_i), "raviV_gettable_i"); - def->raviV_op_totypeF = def->raviF->addExternFunction( - def->types->raviV_op_totypeT, reinterpret_cast(&raviV_op_totype), - "raviV_op_totype"); -#ifdef RAVI_DEFER_STATEMENT - def->raviV_op_deferF = def->raviF->addExternFunction( - def->types->raviV_op_deferT, reinterpret_cast(&raviV_op_defer), - "raviV_op_defer"); -#endif -#if 0 - // DEBUG routines - def->ravi_dump_valueF = def->raviF->addExternFunction( - def->types->ravi_dump_valueT, reinterpret_cast(&ravi_dump_value), - "ravi_dump_value"); - def->ravi_dump_stackF = def->raviF->addExternFunction( - def->types->ravi_dump_stackT, reinterpret_cast(&ravi_dump_stack), - "ravi_dump_stack"); - def->ravi_dump_stacktopF = def->raviF->addExternFunction( - def->types->ravi_dump_stacktopT, - reinterpret_cast(&ravi_dump_stacktop), "ravi_dump_stacktop"); -#endif - def->ravi_debug_traceF = def->raviF->addExternFunction( - def->types->ravi_debug_traceT, - reinterpret_cast(&raviV_debug_trace), "raviV_debug_trace"); - - // Create printf declaration - std::vector args; - args.push_back(def->types->C_pcharT); - // accepts a char*, is vararg, and returns int - llvm::FunctionType *printfType = - llvm::FunctionType::get(def->types->C_intT, args, true); - def->printfFunc = - def->raviF->module()->getOrInsertFunction("printf", printfType); - - // stdc fmod declaration - args.clear(); - args.push_back(def->types->lua_NumberT); - args.push_back(def->types->lua_NumberT); - llvm::FunctionType *fmodType = - llvm::FunctionType::get(def->types->lua_NumberT, args, false); -#ifdef LUA_32BITS - def->fmodFunc = def->raviF->module()->getOrInsertFunction("fmodf", fmodType); -#else - def->fmodFunc = def->raviF->module()->getOrInsertFunction("fmod", fmodType); -#endif - llvm::FunctionType *powType = - llvm::FunctionType::get(def->types->lua_NumberT, args, false); -#ifdef LUA_32BITS - def->powFunc = def->raviF->module()->getOrInsertFunction("powf", powType); -#else - def->powFunc = def->raviF->module()->getOrInsertFunction("pow", powType); -#endif - // stdc floor declaration - args.clear(); - args.push_back(def->types->lua_NumberT); - llvm::FunctionType *floorType = - llvm::FunctionType::get(def->types->lua_NumberT, args, false); -#ifdef LUA_32BITS - def->floorFunc = - def->raviF->module()->getOrInsertFunction("floorf", floorType); -#else - def->floorFunc = - def->raviF->module()->getOrInsertFunction("floor", floorType); -#endif -} - -void RaviCodeGenerator::link_block(RaviFunctionDef *def, int pc) { - // If we are on a jump target then check if this is a forloop - // target. Forloop targets are special as they use computed goto - // to branch to one of 4 possible labels. That is why we test for - // jmp2 below. - // We need to check whether current block is already terminated - - // this can be because of a return or break or goto within the forloop - // body - if (def->jmp_targets[pc].jmp2 && - !def->builder->GetInsertBlock()->getTerminator()) { - // Handle special case for body of FORLOOP - auto b = def->builder->CreateLoad(def->jmp_targets[pc].forloop_branch); - auto idb = def->builder->CreateIndirectBr(b, 4); - idb->addDestination(def->jmp_targets[pc].jmp1); - idb->addDestination(def->jmp_targets[pc].jmp2); - idb->addDestination(def->jmp_targets[pc].jmp3); - idb->addDestination(def->jmp_targets[pc].jmp4); - // As we have terminated the block the code below will not - // add the branch instruction, but we still need to create the new - // block which is handled below. - } - // If the current bytecode offset pc is on a jump target - // then we need to insert the block we previously created in - // scan_jump_targets() - // and make it the current insert block; also if the previous block - // is unterminated then we simply provide a branch from previous block to the - // new block - if (def->jmp_targets[pc].jmp1) { - // We are on a jump target - // Get the block we previously created scan_jump_targets - llvm::BasicBlock *block = def->jmp_targets[pc].jmp1; - if (!def->builder->GetInsertBlock()->getTerminator()) { - // Previous block not terminated so branch to the - // new block - def->builder->CreateBr(block); - } - // Now add the new block and make it current - def->f->getBasicBlockList().push_back(block); - def->builder->SetInsertPoint(block); - } -} - -llvm::Value *RaviCodeGenerator::emit_gep_upvals(RaviFunctionDef *def, - int offset) { - return emit_gep(def, "upvals", def->p_LClosure, 0, 6, offset); -} - -llvm::Instruction *RaviCodeGenerator::emit_load_pupval(RaviFunctionDef *def, - llvm::Value *ppupval) { - llvm::Instruction *ins = def->builder->CreateLoad(ppupval); - ins->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_ppointerT); - return ins; -} - -// Load upval->v -llvm::Instruction *RaviCodeGenerator::emit_load_upval_v( - RaviFunctionDef *def, llvm::Instruction *pupval) { - llvm::Value *p_v = emit_gep_upval_v(def, pupval); - llvm::Instruction *v = def->builder->CreateLoad(p_v); - v->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_UpVal_vT); - return v; -} - -// Get &upval->v -llvm::Value *RaviCodeGenerator::emit_gep_upval_v(RaviFunctionDef *def, - llvm::Instruction *pupval) { - return emit_gep(def, "v", pupval, 0, 0); -} - -// Get &upval->value -> result is TValue * -llvm::Value *RaviCodeGenerator::emit_gep_upval_value( - RaviFunctionDef *def, llvm::Instruction *pupval) { -#ifdef RAVI_DEFER_STATEMENT - return emit_gep(def, "value", pupval, 0, 3); -#else - return emit_gep(def, "value", pupval, 0, 2); -#endif -} - -bool RaviCodeGenerator::compile(lua_State *L, Proto *p, - std::shared_ptr module, - ravi_compile_options_t *options) { - if (p->ravi_jit.jit_status == RAVI_JIT_COMPILED) return true; - - // Avoid recursive calls - if (module->owner()->get_compiling_flag()) return false; - - bool doVerify = module->owner()->get_validation() != 0; - bool omitArrayGetRangeCheck = - options ? options->omit_array_get_range_check != 0 : 0; - - if (p->ravi_jit.jit_status != RAVI_JIT_NOT_COMPILED || !canCompile(p)) { - // fprintf(stderr, "failed to compile!\n"); - return false; - } - - llvm::LLVMContext &context = jitState_->context(); - llvm::IRBuilder<> builder(context); - - RaviFunctionDef definition = {0}; - RaviFunctionDef *def = &definition; - - auto f = create_function(p, module, builder, def); - if (!f) { - p->ravi_jit.jit_status = RAVI_JIT_CANT_COMPILE; // can't compile - return false; - } - - // Set flag so we can avoid recursive calls - module->owner()->set_compiling_flag(true); - - // The functions constants - TValue *k = p->k; - - // Add extern declarations for Lua functions we need to call - emit_extern_declarations(def); - def->p = p; - - // Create BasicBlocks for all the jump targets in the Lua bytecode - scan_jump_targets(def, p); - - // Get pointer to L->ci - def->L_ci = emit_gep(def, "L_ci", def->L, 0, 6); - - // Load L->ci - // This is the function's activation record / stack frame - def->ci_val = builder.CreateLoad(def->L_ci); - def->ci_val->setMetadata(llvm::LLVMContext::MD_tbaa, - def->types->tbaa_luaState_ciT); - - // Get pointer to function's 'base' stack location - // 'base' is the address relative to which all the - // function registers are located - def->Ci_base = emit_gep(def, "base", def->ci_val, 0, 4, 0); - - // We need to get hold of the constants table - // which is located in the function definition - // This is the line in lvm.c that says: - // LClosure *cl = clLvalue(ci->func) - def->p_LClosure = emit_gep_ci_func_value_gc_asLClosure(def); - - // Get pointer to the Proto* which is cl->p - def->proto = emit_gep(def, "Proto", def->p_LClosure, 0, 5); - - // Load pointer to proto - def->proto_ptr = builder.CreateLoad(def->proto); - def->proto_ptr->setMetadata(llvm::LLVMContext::MD_tbaa, - def->types->tbaa_LClosure_pT); - - // Obtain pointer to Proto->k - def->proto_k = emit_gep(def, "k", def->proto_ptr, 0, 14); - - // Load pointer to k - def->k_ptr = builder.CreateLoad(def->proto_k); - def->k_ptr->setMetadata(llvm::LLVMContext::MD_tbaa, - def->types->tbaa_Proto_kT); - - // emit_dump_stack(def, "Function entry-->"); - - const Instruction *code = p->code; - int pc, n = p->sizecode; - for (pc = 0; pc < n; pc++) { - link_block(def, pc); - Instruction i = code[pc]; - OpCode op = GET_OPCODE(i); - int A = GETARG_A(i); - switch (op) { - case OP_LOADK: { - int Bx = GETARG_Bx(i); - emit_LOADK(def, A, Bx, pc); - } break; - case OP_LOADKX: { - // OP_LOADKX is followed by OP_EXTRAARG - Instruction inst = code[++pc]; - int Ax = GETARG_Ax(inst); - lua_assert(GET_OPCODE(inst) == OP_EXTRAARG); - emit_LOADK(def, A, Ax, pc - 1); - } break; - - case OP_CONCAT: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_CONCAT(def, A, B, C, pc); - } break; - case OP_CLOSURE: { - int Bx = GETARG_Bx(i); - emit_CLOSURE(def, A, Bx, pc); - } break; - case OP_VARARG: { - int B = GETARG_B(i); - emit_VARARG(def, A, B, pc); - } break; - - case OP_LOADBOOL: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_LOADBOOL(def, A, B, C, pc + 2, pc); - } break; - case OP_MOVE: { - int B = GETARG_B(i); - emit_MOVE(def, A, B, pc); - } break; - case OP_RAVI_MOVEI: { - int B = GETARG_B(i); - emit_MOVEI(def, A, B, pc); - } break; - case OP_RAVI_MOVEF: { - int B = GETARG_B(i); - emit_MOVEF(def, A, B, pc); - } break; - case OP_RAVI_TOINT: { - emit_TOINT(def, A, pc); - } break; - case OP_RAVI_TOFLT: { - emit_TOFLT(def, A, pc); - } break; - case OP_RAVI_NEW_IARRAY: { - emit_NEWARRAYINT(def, A, pc); - } break; - case OP_RAVI_NEW_FARRAY: { - emit_NEWARRAYFLOAT(def, A, pc); - } break; - case OP_NEWTABLE: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_NEWTABLE(def, A, B, C, pc); - } break; - case OP_SETLIST: { - int B = GETARG_B(i); - int C = GETARG_C(i); - if (C == 0) { - // OP_SETLIST is followed by OP_EXTRAARG - Instruction inst = code[++pc]; - C = GETARG_Ax(inst); - lua_assert(GET_OPCODE(inst) == OP_EXTRAARG); - } - emit_SETLIST(def, A, B, C, pc); - } break; - case OP_SELF: - case OP_RAVI_SELF_SK: { - int B = GETARG_B(i); - int C = GETARG_C(i); - if (op == OP_RAVI_SELF_SK) { emit_SELF_SK(def, A, B, C, pc); } - else { - emit_SELF(def, A, B, C, pc); - } - } break; - case OP_LEN: { - int B = GETARG_B(i); - emit_LEN(def, A, B, pc); - } break; - - case OP_RETURN: { - int B = GETARG_B(i); - emit_RETURN(def, A, B, pc); - } break; - case OP_RAVI_EQ_II: - case OP_RAVI_EQ_FF: - case OP_RAVI_LT_II: - case OP_RAVI_LT_FF: - case OP_RAVI_LE_II: - case OP_RAVI_LE_FF: - case OP_LT: - case OP_LE: - case OP_EQ: { - int B = GETARG_B(i); - int C = GETARG_C(i); - OpCode compOperator = op; - llvm::Constant *comparison_function = - ((op == OP_EQ || op == OP_RAVI_EQ_II || op == OP_RAVI_EQ_FF) - ? def->luaV_equalobjF - : ((op == OP_LT || op == OP_RAVI_LT_II || op == OP_RAVI_LT_FF) - ? def->luaV_lessthanF - : def->luaV_lessequalF)); - // OP_EQ is followed by OP_JMP - we process this - // along with OP_EQ - pc++; - i = code[pc]; - op = GET_OPCODE(i); - lua_assert(op == OP_JMP); - int sbx = GETARG_sBx(i); - // j below is the jump target - int j = sbx + pc + 1; - emit_EQ(def, A, B, C, j, GETARG_A(i), comparison_function, compOperator, - pc - 1); - } break; - case OP_TFORCALL: { - int B = GETARG_B(i); - int C = GETARG_C(i); - // OP_TFORCALL is followed by OP_TFORLOOP - we process this - // along with OP_TFORCALL - pc++; - i = code[pc]; - op = GET_OPCODE(i); - lua_assert(op == OP_TFORLOOP); - int sbx = GETARG_sBx(i); - // j below is the jump target - int j = sbx + pc + 1; - emit_TFORCALL(def, A, B, C, j, GETARG_A(i), pc - 1); - } break; - case OP_TFORLOOP: { - int sbx = GETARG_sBx(i); - int j = sbx + pc + 1; - emit_TFORLOOP(def, A, j, pc); - } break; - case OP_NOT: { - int B = GETARG_B(i); - emit_NOT(def, A, B, pc); - } break; - case OP_RAVI_BNOT_I: { - int B = GETARG_B(i); - emit_BNOT_I(def, A, B, pc); - } break; - case OP_BNOT: { - int B = GETARG_B(i); - emit_BNOT(def, A, B, pc); - } break; - case OP_TEST: { - int B = GETARG_B(i); - int C = GETARG_C(i); - // OP_TEST is followed by OP_JMP - we process this - // along with OP_EQ - pc++; - i = code[pc]; - op = GET_OPCODE(i); - lua_assert(op == OP_JMP); - int sbx = GETARG_sBx(i); - // j below is the jump target - int j = sbx + pc + 1; - emit_TEST(def, A, B, C, j, GETARG_A(i), pc - 1); - } break; - case OP_TESTSET: { - int B = GETARG_B(i); - int C = GETARG_C(i); - // OP_TESTSET is followed by OP_JMP - we process this - // along with OP_EQ - pc++; - i = code[pc]; - op = GET_OPCODE(i); - lua_assert(op == OP_JMP); - int sbx = GETARG_sBx(i); - // j below is the jump target - int j = sbx + pc + 1; - emit_TESTSET(def, A, B, C, j, GETARG_A(i), pc - 1); - } break; - - case OP_JMP: { - int sbx = GETARG_sBx(i); - int j = sbx + pc + 1; - emit_JMP(def, A, j, pc); - } break; - - case OP_RAVI_FORPREP_I1: - case OP_RAVI_FORPREP_IP: { - int sbx = GETARG_sBx(i); - int j = sbx + pc + 1; - emit_iFORPREP(def, A, j, op == OP_RAVI_FORPREP_I1, pc); - } break; - case OP_FORPREP: { - int sbx = GETARG_sBx(i); - int j = sbx + pc + 1; -#if RAVI_CODEGEN_FORPREP2 - emit_FORPREP2(def, A, j, pc); -#else - emit_FORPREP(def, A, j, pc); -#endif - } break; - case OP_RAVI_FORLOOP_I1: - case OP_RAVI_FORLOOP_IP: { - int sbx = GETARG_sBx(i); - int j = sbx + pc + 1; - emit_iFORLOOP(def, A, j, def->jmp_targets[pc], op == OP_RAVI_FORLOOP_I1, - pc); - } break; - case OP_FORLOOP: { - int sbx = GETARG_sBx(i); - int j = sbx + pc + 1; -#if RAVI_CODEGEN_FORPREP2 - emit_FORLOOP2(def, A, j, def->jmp_targets[pc], pc); -#else - emit_FORLOOP(def, A, j, pc); -#endif - } break; - - case OP_LOADNIL: { - int B = GETARG_B(i); - emit_LOADNIL(def, A, B, pc); - } break; - case OP_RAVI_LOADFZ: { - emit_LOADFZ(def, A, pc); - } break; - case OP_RAVI_LOADIZ: { - emit_LOADIZ(def, A, pc); - } break; - case OP_TAILCALL: - case OP_CALL: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_CALL(def, A, B, C, pc); - } break; - - case OP_RAVI_SETFIELD: - case OP_RAVI_TABLE_SETFIELD: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_SETFIELD(def, A, B, C, pc); - } break; - case OP_RAVI_SETI: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_SETI(def, A, B, C, pc); - } break; - case OP_SETTABLE: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_SETTABLE(def, A, B, C, pc); - } break; - case OP_RAVI_TABLE_GETFIELD: { - int C = GETARG_C(i); - int B = GETARG_B(i); - lua_assert(ISK(C)); - TValue *kv = k + INDEXK(C); - TString *key = tsvalue(kv); - lua_assert(key->tt == LUA_TSHRSTR); - emit_GETTABLE_S(def, A, B, C, pc, key); - } break; - - case OP_RAVI_TABLE_SELF_SK: { - int C = GETARG_C(i); - int B = GETARG_B(i); - lua_assert(ISK(C)); - TValue *kv = k + INDEXK(C); - TString *key = tsvalue(kv); - lua_assert(key->tt == LUA_TSHRSTR); - emit_TABLE_SELF_SK(def, A, B, C, pc, key); - } break; - case OP_RAVI_GETI: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_GETI(def, A, B, C, pc); - } break; - case OP_RAVI_GETFIELD: { - int B = GETARG_B(i); - int C = GETARG_C(i); - lua_assert(ISK(C)); - TValue *kv = k + INDEXK(C); - TString *key = tsvalue(kv); - lua_assert(key->tt == LUA_TSHRSTR); - emit_GETFIELD(def, A, B, C, pc, key); - } break; - case OP_GETTABLE: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_GETTABLE(def, A, B, C, pc); - } break; - case OP_RAVI_IARRAY_GET: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_IARRAY_GET(def, A, B, C, omitArrayGetRangeCheck, pc); - } break; - case OP_RAVI_IARRAY_SETI: - case OP_RAVI_IARRAY_SET: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_IARRAY_SET(def, A, B, C, op == OP_RAVI_IARRAY_SETI, pc); - } break; - case OP_RAVI_FARRAY_GET: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_FARRAY_GET(def, A, B, C, omitArrayGetRangeCheck, pc); - } break; - case OP_RAVI_FARRAY_SETF: - case OP_RAVI_FARRAY_SET: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_FARRAY_SET(def, A, B, C, op == OP_RAVI_FARRAY_SETF, pc); - } break; - case OP_RAVI_TOTAB: { - emit_TOARRAY(def, A, RAVI_TTABLE, "table expected", pc); - } break; - case OP_RAVI_TOIARRAY: { - emit_TOARRAY(def, A, RAVI_TARRAYINT, "integer[] expected", pc); - } break; - case OP_RAVI_TOFARRAY: { - emit_TOARRAY(def, A, RAVI_TARRAYFLT, "number[] expected", pc); - } break; - case OP_RAVI_TOSTRING: { - emit_TOSTRING(def, A, pc); - break; - } - case OP_RAVI_TOCLOSURE: { - emit_TOCLOSURE(def, A, pc); - break; - } - case OP_RAVI_TOTYPE: { - int Bx = GETARG_Bx(i); - emit_TOTYPE(def, A, Bx, pc); - break; - } - case OP_RAVI_MOVEIARRAY: { - int B = GETARG_B(i); - emit_MOVEIARRAY(def, A, B, pc); - } break; - case OP_RAVI_MOVEFARRAY: { - int B = GETARG_B(i); - emit_MOVEFARRAY(def, A, B, pc); - } break; - case OP_RAVI_MOVETAB: { - int B = GETARG_B(i); - emit_MOVETAB(def, A, B, pc); - } break; - - case OP_RAVI_GETTABUP_SK: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_GETTABUP_SK(def, A, B, C, pc); - } break; - case OP_GETTABUP: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_GETTABUP(def, A, B, C, pc); - } break; - case OP_GETUPVAL: { - int B = GETARG_B(i); - emit_GETUPVAL(def, A, B, pc); - } break; - case OP_SETTABUP: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_SETTABUP(def, A, B, C, pc); - } break; - case OP_SETUPVAL: { - int B = GETARG_B(i); - emit_SETUPVAL(def, A, B, pc); - } break; - - case OP_RAVI_SETUPVALI: { - int B = GETARG_B(i); - emit_SETUPVAL_Specific(def, A, B, pc, OP_RAVI_SETUPVALI, - def->raviV_op_setupvaliF); - } break; - case OP_RAVI_SETUPVALF: { - int B = GETARG_B(i); - emit_SETUPVAL_Specific(def, A, B, pc, OP_RAVI_SETUPVALF, - def->raviV_op_setupvalfF); - } break; - case OP_RAVI_SETUPVAL_IARRAY: { - int B = GETARG_B(i); - emit_SETUPVAL_Specific(def, A, B, pc, OP_RAVI_SETUPVAL_IARRAY, - def->raviV_op_setupvalaiF); - } break; - case OP_RAVI_SETUPVAL_FARRAY: { - int B = GETARG_B(i); - emit_SETUPVAL_Specific(def, A, B, pc, OP_RAVI_SETUPVAL_FARRAY, - def->raviV_op_setupvalafF); - } break; - case OP_RAVI_SETUPVALT: { - int B = GETARG_B(i); - emit_SETUPVAL_Specific(def, A, B, pc, OP_RAVI_SETUPVALT, - def->raviV_op_setupvaltF); - } break; - - case OP_RAVI_BXOR_II: - case OP_RAVI_BOR_II: - case OP_RAVI_BAND_II: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_BITWISE_BINARY_OP(def, op, A, B, C, pc); - } break; - - case OP_BAND: - case OP_BOR: - case OP_BXOR: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_BOR_BXOR_BAND(def, op, A, B, C, pc); - } break; - - case OP_SHR: - case OP_SHL: - case OP_RAVI_SHL_II: - case OP_RAVI_SHR_II: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_BITWISE_SHIFT_OP(def, op, A, B, C, pc); - } break; - - case OP_ADD: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_ARITH(def, A, B, C, OP_ADD, TM_ADD, pc); - } break; - case OP_RAVI_ADDFF: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_ADDFF(def, A, B, C, pc); - } break; - case OP_RAVI_ADDFI: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_ADDFI(def, A, B, C, pc); - } break; - case OP_RAVI_ADDII: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_ADDII(def, A, B, C, pc); - } break; - - case OP_SUB: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_ARITH(def, A, B, C, OP_SUB, TM_SUB, pc); - } break; - case OP_RAVI_SUBFF: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_SUBFF(def, A, B, C, pc); - } break; - case OP_RAVI_SUBFI: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_SUBFI(def, A, B, C, pc); - } break; - case OP_RAVI_SUBIF: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_SUBIF(def, A, B, C, pc); - } break; - case OP_RAVI_SUBII: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_SUBII(def, A, B, C, pc); - } break; - - case OP_MUL: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_ARITH(def, A, B, C, OP_MUL, TM_MUL, pc); - } break; - case OP_RAVI_MULFF: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_MULFF(def, A, B, C, pc); - } break; - case OP_RAVI_MULFI: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_MULFI(def, A, B, C, pc); - } break; - case OP_RAVI_MULII: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_MULII(def, A, B, C, pc); - } break; - - case OP_DIV: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_ARITH(def, A, B, C, OP_DIV, TM_DIV, pc); - } break; - case OP_RAVI_DIVFF: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_DIVFF(def, A, B, C, pc); - } break; - case OP_RAVI_DIVFI: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_DIVFI(def, A, B, C, pc); - } break; - case OP_RAVI_DIVIF: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_DIVIF(def, A, B, C, pc); - } break; - case OP_RAVI_DIVII: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_DIVII(def, A, B, C, pc); - } break; - - case OP_MOD: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_MOD(def, A, B, C, pc); - } break; - case OP_IDIV: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_IDIV(def, A, B, C, pc); - } break; - case OP_POW: { - int B = GETARG_B(i); - int C = GETARG_C(i); - emit_POW(def, A, B, C, pc); - } break; - case OP_UNM: { - int B = GETARG_B(i); - emit_UNM(def, A, B, pc); - } break; -#ifdef RAVI_DEFER_STATEMENT - case OP_RAVI_DEFER: { - emit_DEFER(def, A, pc); - } break; -#endif - default: { - fprintf(stderr, "Unexpected bytecode %d\n", op); - abort(); - } - } - } - if (doVerify && llvm::verifyFunction(*f->function(), &llvm::errs())) { - f->dump(); - fprintf(stderr, "LLVM Code Verification failed\n"); - exit(1); - } - - ravi::RaviJITFunction *llvm_func = f.release(); - p->ravi_jit.jit_data = reinterpret_cast(llvm_func); - p->ravi_jit.jit_function = nullptr; - p->ravi_jit.jit_status = RAVI_JIT_COMPILED; - - module->owner()->set_compiling_flag(false); - - return llvm_func != nullptr; -} - -void RaviCodeGenerator::scan_jump_targets(RaviFunctionDef *def, Proto *p) { - // We need to pre-create blocks for jump targets so that we - // can generate branch instructions in the code - def->jmp_targets.clear(); - const Instruction *code = p->code; - int pc, n = p->sizecode; - def->jmp_targets.resize(n); - for (pc = 0; pc < n; pc++) { - Instruction i = code[pc]; - OpCode op = GET_OPCODE(i); - switch (op) { - case OP_LOADBOOL: { - int C = GETARG_C(i); - int j = pc + 2; // jump target - if (C && !def->jmp_targets[j].jmp1) - def->jmp_targets[j].jmp1 = - llvm::BasicBlock::Create(def->jitState->context(), "loadbool"); - } break; - case OP_JMP: - case OP_RAVI_FORPREP_IP: - case OP_RAVI_FORPREP_I1: - case OP_RAVI_FORLOOP_IP: - case OP_RAVI_FORLOOP_I1: - case OP_FORLOOP: - case OP_FORPREP: - case OP_TFORLOOP: { - const char *targetname = nullptr; - char temp[80]; - if (op == OP_JMP) - targetname = "jmp"; - else if (op == OP_FORLOOP || op == OP_RAVI_FORLOOP_IP || - op == OP_RAVI_FORLOOP_I1) - targetname = "forbody"; - else if (op == OP_FORPREP || op == OP_RAVI_FORPREP_IP || - op == OP_RAVI_FORPREP_I1) -#if RAVI_CODEGEN_FORPREP2 - targetname = "forloop_ilt"; -#else - targetname = "forloop"; -#endif - else - targetname = "tforbody"; - int sbx = GETARG_sBx(i); - int j = sbx + pc + 1; - // We append the Lua bytecode location to help debug the IR - snprintf(temp, sizeof temp, "%s%d_", targetname, j + 1); - // - if (!def->jmp_targets[j].jmp1) { - def->jmp_targets[j].jmp1 = - llvm::BasicBlock::Create(def->jitState->context(), temp); - } -#if RAVI_CODEGEN_FORPREP2 - if (op == OP_FORPREP) { - lua_assert(def->jmp_targets[j].jmp2 == nullptr); - // first target (created above) is for int < limit - // Second target is for int > limit - snprintf(temp, sizeof temp, "%s%d_", "forloop_igt", j + 1); - def->jmp_targets[j].jmp2 = - llvm::BasicBlock::Create(def->jitState->context(), temp); - // Third target is for float < limit - snprintf(temp, sizeof temp, "%s%d_", "forloop_flt", j + 1); - def->jmp_targets[j].jmp3 = - llvm::BasicBlock::Create(def->jitState->context(), temp); - // Fourth target is for float > limit - snprintf(temp, sizeof temp, "%s%d_", "forloop_fgt", j + 1); - def->jmp_targets[j].jmp4 = - llvm::BasicBlock::Create(def->jitState->context(), temp); - } -#endif - } break; - default: break; - } - } -} -} // namespace ravi diff --git a/src/ravi_llvmcomp.cpp b/src/ravi_llvmcomp.cpp deleted file mode 100644 index e613989..0000000 --- a/src/ravi_llvmcomp.cpp +++ /dev/null @@ -1,339 +0,0 @@ -/****************************************************************************** -* 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. -******************************************************************************/ -#include "ravi_llvmcodegen.h" - -namespace ravi { - -// Although the name is EQ this actually -// implements EQ, LE and LT - by using the supplied lua function to call. -void RaviCodeGenerator::emit_EQ(RaviFunctionDef *def, int A, int B, int C, - int j, int jA, llvm::Constant *callee, - OpCode opCode, int pc) { - // case OP_EQ: { - // TValue *rb = RKB(i); - // TValue *rc = RKC(i); - // Protect( - // if (cast_int(luaV_equalobj(L, rb, rc)) != GETARG_A(i)) - // ci->u.l.savedpc++; - // else - // donextjump(ci); - // ) - // } break; - - bool traced = emit_debug_trace(def, opCode, pc); - - // Load pointer to base - emit_load_base(def); - - // Get pointer to register B - llvm::Value *regB = emit_gep_register_or_constant(def, B); - // Get pointer to register C - llvm::Value *regC = emit_gep_register_or_constant(def, C); - - llvm::Value *result = NULL; - switch (opCode) { - - case OP_RAVI_LT_II: - case OP_RAVI_LE_II: - case OP_RAVI_EQ_II: { - llvm::Instruction *p1 = emit_load_reg_i(def, regB); - llvm::Instruction *p2 = emit_load_reg_i(def, regC); - - switch (opCode) { - case OP_RAVI_EQ_II: - result = def->builder->CreateICmpEQ(p1, p2, "EQ_II_result"); - break; - case OP_RAVI_LT_II: - result = def->builder->CreateICmpSLT(p1, p2, "LT_II_result"); - break; - case OP_RAVI_LE_II: - result = def->builder->CreateICmpSLE(p1, p2, "LE_II_result"); - break; - default: - assert(0); - } - result = - def->builder->CreateZExt(result, def->types->C_intT, "II_result_int"); - - } break; - - case OP_RAVI_LT_FF: - case OP_RAVI_LE_FF: - case OP_RAVI_EQ_FF: { - llvm::Instruction *p1 = emit_load_reg_n(def, regB); - llvm::Instruction *p2 = emit_load_reg_n(def, regC); - - switch (opCode) { - case OP_RAVI_EQ_FF: - result = def->builder->CreateFCmpOEQ(p1, p2, "EQ_FF_result"); - break; - case OP_RAVI_LT_FF: - result = def->builder->CreateFCmpULT(p1, p2, "LT_FF_result"); - break; - case OP_RAVI_LE_FF: - result = def->builder->CreateFCmpULE(p1, p2, "LE_FF_result"); - break; - default: - assert(0); - } - result = - def->builder->CreateZExt(result, def->types->C_intT, "FF_result_int"); - - } break; - - default: - // As below may invoke metamethod we need to set savedpc - if (!traced) emit_update_savedpc(def, pc); - // Call luaV_equalobj with register B and C - result = CreateCall3(def->builder, callee, def->L, regB, regC); - } - - // Test if result is equal to operand A - llvm::Value *result_eq_A = def->builder->CreateICmpEQ( - result, llvm::ConstantInt::get(def->types->C_intT, A)); - - // If result == A then we need to execute the next statement which is a jump - llvm::BasicBlock *then_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.then", def->f); - llvm::BasicBlock *else_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.else"); - def->builder->CreateCondBr(result_eq_A, then_block, else_block); - def->builder->SetInsertPoint(then_block); - - // if (a > 0) luaF_close(L, ci->u.l.base + a - 1); - if (jA > 0) { - // jA is the A operand of the Jump instruction - - // Reload pointer to base as the call to luaV_equalobj() may - // have invoked a Lua function and as a result the stack may have - // been reallocated - so the previous base pointer could be stale - emit_load_base(def); - - // base + a - 1 - llvm::Value *val = emit_gep_register(def, jA - 1); -#ifdef RAVI_DEFER_STATEMENT - if (!traced) - emit_update_savedpc(def, pc); - // Call luaF_close - CreateCall3(def->builder, def->luaF_closeF, def->L, val, def->types->kInt[LUA_OK]); -#else - CreateCall2(def->builder, def->luaF_closeF, def->L, val); -#endif - } - // Do the jump - def->builder->CreateBr(def->jmp_targets[j].jmp1); - // Add the else block and make it current so that the next instruction flows - // here - def->f->getBasicBlockList().push_back(else_block); - def->builder->SetInsertPoint(else_block); -} - -llvm::Value *RaviCodeGenerator::emit_boolean_testfalse(RaviFunctionDef *def, - llvm::Value *reg, - bool donot) { - // (isnil() || isbool() && b == 0) - - llvm::IRBuilder<> TmpB(def->entry, def->entry->begin()); - llvm::Value *var = TmpB.CreateAlloca( - llvm::Type::getInt1Ty(def->jitState->context()), nullptr, "b"); - - llvm::Value *type = emit_load_type(def, reg); - - // Test if type == LUA_TNIL (0) - llvm::Value *isnil = emit_is_value_of_type(def, type, LUA__TNIL, "is.nil"); - llvm::BasicBlock *then_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.nil", def->f); - llvm::BasicBlock *else_block = - llvm::BasicBlock::Create(def->jitState->context(), "not.nil"); - llvm::BasicBlock *end_block = - llvm::BasicBlock::Create(def->jitState->context(), "end"); - def->builder->CreateCondBr(isnil, then_block, else_block); - def->builder->SetInsertPoint(then_block); - - emit_store_local_int(def, isnil, var); - def->builder->CreateBr(end_block); - - def->f->getBasicBlockList().push_back(else_block); - def->builder->SetInsertPoint(else_block); - // value is not nil - // so check if bool and b == 0 - - // Test if type == LUA_TBOOLEAN - llvm::Value *isbool = - emit_is_value_of_type(def, type, LUA__TBOOLEAN, "is.boolean"); - // Test if bool value == 0 - llvm::Value *bool_value = emit_load_reg_b(def, reg); - llvm::Value *boolzero = - def->builder->CreateICmpEQ(bool_value, def->types->kInt[0]); - // Test type == LUA_TBOOLEAN && bool value == 0 - llvm::Value *andvalue = def->builder->CreateAnd(isbool, boolzero); - - emit_store_local_int(def, andvalue, var); - def->builder->CreateBr(end_block); - - def->f->getBasicBlockList().push_back(end_block); - def->builder->SetInsertPoint(end_block); - - llvm::Value *result = nullptr; - if (donot) { - auto ins = emit_load_local_int(def, var); - result = def->builder->CreateNot(ins); - } else { - auto ins = emit_load_local_int(def, var); - result = ins; - } - - return result; -} - -void RaviCodeGenerator::emit_TEST(RaviFunctionDef *def, int A, int B, int C, - int j, int jA, int pc) { - - // case OP_TEST: { - // if (GETARG_C(i) ? l_isfalse(ra) : !l_isfalse(ra)) - // ci->u.l.savedpc++; - // else - // donextjump(ci); - // } break; - - bool traced = emit_debug_trace(def, OP_TEST, pc); - // Load pointer to base - emit_load_base(def); - - // Get pointer to register A - llvm::Value *ra = emit_gep_register(def, A); - // v = C ? is_false(ra) : !is_false(ra) - llvm::Value *v = C ? emit_boolean_testfalse(def, ra, false) - : emit_boolean_testfalse(def, ra, true); - - // Test NOT v - llvm::Value *result = def->builder->CreateNot(v); - // If !v then we need to execute the next statement which is a jump - llvm::BasicBlock *then_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.then", def->f); - llvm::BasicBlock *else_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.else"); - def->builder->CreateCondBr(result, then_block, else_block); - def->builder->SetInsertPoint(then_block); - - // if (a > 0) luaF_close(L, ci->u.l.base + a - 1); - if (jA > 0) { - // jA is the A operand of the Jump instruction - - // base + a - 1 - llvm::Value *val = emit_gep_register(def, jA - 1); -#ifdef RAVI_DEFER_STATEMENT - if (!traced) - emit_update_savedpc(def, pc); - // Call luaF_close - CreateCall3(def->builder, def->luaF_closeF, def->L, val, def->types->kInt[LUA_OK]); -#else - CreateCall2(def->builder, def->luaF_closeF, def->L, val); -#endif - } - // Do the jump - def->builder->CreateBr(def->jmp_targets[j].jmp1); - - // Add the else block and make it current so that the next instruction flows - // here - def->f->getBasicBlockList().push_back(else_block); - def->builder->SetInsertPoint(else_block); -} - -void RaviCodeGenerator::emit_NOT(RaviFunctionDef *def, int A, int B, int pc) { - // case OP_NOT: { - // TValue *rb = RB(i); - // int res = l_isfalse(rb); /* next assignment may change this value */ - // setbvalue(ra, res); - // } break; - emit_debug_trace(def, OP_NOT, pc); - emit_load_base(def); - // Get pointer to register B - llvm::Value *rb = emit_gep_register(def, B); - llvm::Value *v = emit_boolean_testfalse(def, rb, false); - llvm::Value *result = def->builder->CreateZExt(v, def->types->C_intT, "i"); - llvm::Value *ra = emit_gep_register(def, A); - emit_store_reg_b_withtype(def, result, ra); -} - -void RaviCodeGenerator::emit_TESTSET(RaviFunctionDef *def, int A, int B, int C, - int j, int jA, int pc) { - - // case OP_TESTSET: { - // TValue *rb = RB(i); - // if (GETARG_C(i) ? l_isfalse(rb) : !l_isfalse(rb)) - // ci->u.l.savedpc++; - // else { - // setobjs2s(L, ra, rb); - // donextjump(ci); - // } - // } break; - - bool traced = emit_debug_trace(def, OP_TESTSET, pc); - // Load pointer to base - emit_load_base(def); - - // Get pointer to register B - llvm::Value *rb = emit_gep_register(def, B); - // v = C ? is_false(ra) : !is_false(ra) - llvm::Value *v = C ? emit_boolean_testfalse(def, rb, false) - : emit_boolean_testfalse(def, rb, true); - - // Test NOT v - llvm::Value *result = def->builder->CreateNot(v); - // If !v then we need to execute the next statement which is a jump - llvm::BasicBlock *then_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.then", def->f); - llvm::BasicBlock *else_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.else"); - def->builder->CreateCondBr(result, then_block, else_block); - def->builder->SetInsertPoint(then_block); - - // Get pointer to register A - llvm::Value *ra = emit_gep_register(def, A); - emit_assign(def, ra, rb); - - // if (a > 0) luaF_close(L, ci->u.l.base + a - 1); - if (jA > 0) { - // jA is the A operand of the Jump instruction - - // base + a - 1 - llvm::Value *val = emit_gep_register(def, jA - 1); -#ifdef RAVI_DEFER_STATEMENT - if (!traced) - emit_update_savedpc(def, pc); - // Call luaF_close - CreateCall3(def->builder, def->luaF_closeF, def->L, val, def->types->kInt[LUA_OK]); -#else - CreateCall2(def->builder, def->luaF_closeF, def->L, val); -#endif - } - // Do the jump - def->builder->CreateBr(def->jmp_targets[j].jmp1); - - // Add the else block and make it current so that the next instruction flows - // here - def->f->getBasicBlockList().push_back(else_block); - def->builder->SetInsertPoint(else_block); -} -} diff --git a/src/ravi_llvmforloop.cpp b/src/ravi_llvmforloop.cpp deleted file mode 100644 index 0a69c54..0000000 --- a/src/ravi_llvmforloop.cpp +++ /dev/null @@ -1,454 +0,0 @@ -/****************************************************************************** -* 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. -******************************************************************************/ -#include "ravi_llvmcodegen.h" - -namespace ravi { - -void RaviCodeGenerator::emit_FORLOOP2(RaviFunctionDef *def, int A, int pc, - RaviBranchDef &b, int pc1) { - - // 7[1] FORLOOP 1 - 2; to 6 - // if (ttisinteger(ra)) { /* integer loop? */ - // lua_Integer step = ivalue(ra + 2); - // lua_Integer idx = ivalue(ra) + step; /* increment index */ - // lua_Integer limit = ivalue(ra + 1); - // if ((0 < step) ? (idx <= limit) : (limit <= idx)) { - // ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - // setivalue(ra, idx); /* update internal index... */ - // setivalue(ra + 3, idx); /* ...and external index */ - // } - //} - // else { /* floating loop */ - // lua_Number step = fltvalue(ra + 2); - // lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */ - // lua_Number limit = fltvalue(ra + 1); - // if (luai_numlt(0, step) ? luai_numle(idx, limit) - // : luai_numle(limit, idx)) { - // ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - // setfltvalue(ra, idx); /* update internal index... */ - // setfltvalue(ra + 3, idx); /* ...and external index */ - // } - //} - - emit_debug_trace(def, OP_FORLOOP, pc1); - - // We are in b.jmp1 as this is already the current block - lua_assert(def->builder->GetInsertBlock() == b.jmp1); - - // Obtain pointers to the value.i field - llvm::Value *step_int_ptr = b.istep; - llvm::Value *idx_int_ptr = b.iidx; - llvm::Value *limit_int_ptr = b.ilimit; - // Obtain pointers to the value.n field - llvm::Value *step_double_ptr = b.fstep; - llvm::Value *idx_double_ptr = b.fidx; - llvm::Value *limit_double_ptr = b.flimit; - - // Create the done block - llvm::BasicBlock *exit_block = - llvm::BasicBlock::Create(def->jitState->context(), "exit_iforloop"); - - // INTEGER CASE - - // lua_Integer step = ivalue(ra + 2); - llvm::Instruction *step_int_value = emit_load_local_n(def, step_int_ptr); - - // lua_Integer idx = ivalue(ra) + step; /* increment index */ - llvm::Instruction *idx_int_value = emit_load_local_n(def, idx_int_ptr); - llvm::Value *new_idx = def->builder->CreateAdd(step_int_value, idx_int_value, - "next.idx", false, true); - emit_store_local_n(def, new_idx, idx_int_ptr); - - // lua_Integer limit = ivalue(ra + 1); - llvm::Instruction *limit_int_value = emit_load_local_n(def, limit_int_ptr); - - // idx > limit? - llvm::Value *new_idx_gt_limit = - def->builder->CreateICmpSGT(new_idx, limit_int_value, "idx.gt.limit"); - - // If idx > limit we are done - llvm::BasicBlock *update_block = - llvm::BasicBlock::Create(def->jitState->context(), "updatei"); - def->builder->CreateCondBr(new_idx_gt_limit, exit_block, update_block); - - // NOW INTEGER step < 0 - - def->f->getBasicBlockList().push_back(b.jmp2); - def->builder->SetInsertPoint(b.jmp2); - - step_int_value = emit_load_local_n(def, step_int_ptr); - - // lua_Integer idx = ivalue(ra) + step; /* increment index */ - idx_int_value = emit_load_local_n(def, idx_int_ptr); - new_idx = def->builder->CreateAdd(step_int_value, idx_int_value, "next.idx", - false, true); - emit_store_local_n(def, new_idx, idx_int_ptr); - - // lua_Integer limit = ivalue(ra + 1); - limit_int_value = emit_load_local_n(def, limit_int_ptr); - - // limit > idx? - llvm::Value *limit_gt_idx = - def->builder->CreateICmpSGT(limit_int_value, new_idx, "limit.gt.idx"); - - // If limit > idx we are done - def->builder->CreateCondBr(limit_gt_idx, exit_block, update_block); - - // Merge into update block - def->f->getBasicBlockList().push_back(update_block); - def->builder->SetInsertPoint(update_block); - - emit_load_base(def); - - llvm::Value *rvar = emit_gep_register(def, A + 3); - - // setivalue(ra + 3, idx); /* ...and external index */ - idx_int_value = emit_load_local_n(def, idx_int_ptr); - - emit_store_reg_i_withtype(def, idx_int_value, rvar); - - // ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - def->builder->CreateBr(def->jmp_targets[pc].jmp1); - - // FLOATING CASE - - def->f->getBasicBlockList().push_back(b.jmp3); - def->builder->SetInsertPoint(b.jmp3); - - // lua_Number step = fltvalue(ra + 2); - llvm::Instruction *step_double_value = - emit_load_local_n(def, step_double_ptr); - - // lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */ - llvm::Instruction *idx_double_value = emit_load_local_n(def, idx_double_ptr); - new_idx = - def->builder->CreateFAdd(step_double_value, idx_double_value, "next.idx"); - emit_store_local_n(def, new_idx, idx_double_ptr); - - // lua_Number limit = fltvalue(ra + 1); - llvm::Instruction *limit_double_value = - emit_load_local_n(def, limit_double_ptr); - - // step > 0? - // idx > limit? - new_idx_gt_limit = - def->builder->CreateFCmpOGT(new_idx, limit_double_value, "idx.gt.limit"); - - // If idx > limit we are done - update_block = llvm::BasicBlock::Create(def->jitState->context(), "updatef"); - def->builder->CreateCondBr(new_idx_gt_limit, exit_block, update_block); - - def->f->getBasicBlockList().push_back(b.jmp4); - def->builder->SetInsertPoint(b.jmp4); - - // lua_Number step = fltvalue(ra + 2); - step_double_value = emit_load_local_n(def, step_double_ptr); - - // lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */ - idx_double_value = emit_load_local_n(def, idx_double_ptr); - new_idx = - def->builder->CreateFAdd(step_double_value, idx_double_value, "next.idx"); - emit_store_local_n(def, new_idx, idx_double_ptr); - - // lua_Number limit = fltvalue(ra + 1); - limit_double_value = emit_load_local_n(def, limit_double_ptr); - - // limit > idx? - limit_gt_idx = - def->builder->CreateFCmpOGT(limit_double_value, new_idx, "limit.gt.idx"); - - // If limit > idx we are done - def->builder->CreateCondBr(limit_gt_idx, exit_block, update_block); - - // Merge into update block - def->f->getBasicBlockList().push_back(update_block); - def->builder->SetInsertPoint(update_block); - - emit_load_base(def); - rvar = emit_gep_register(def, A + 3); - - // setfltvalue(ra + 3, idx); /* ...and external index */ - idx_double_value = emit_load_local_n(def, idx_double_ptr); - - emit_store_reg_n_withtype(def, idx_double_value, rvar); - - // ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - def->builder->CreateBr(def->jmp_targets[pc].jmp1); - - def->f->getBasicBlockList().push_back(exit_block); - def->builder->SetInsertPoint(exit_block); -} - -void RaviCodeGenerator::emit_FORLOOP(RaviFunctionDef *def, int A, int pc, - int pc1) { - - // 7[1] FORLOOP 1 - 2; to 6 - // if (ttisinteger(ra)) { /* integer loop? */ - // lua_Integer step = ivalue(ra + 2); - // lua_Integer idx = ivalue(ra) + step; /* increment index */ - // lua_Integer limit = ivalue(ra + 1); - // if ((0 < step) ? (idx <= limit) : (limit <= idx)) { - // ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - // setivalue(ra, idx); /* update internal index... */ - // setivalue(ra + 3, idx); /* ...and external index */ - // } - //} - // else { /* floating loop */ - // lua_Number step = fltvalue(ra + 2); - // lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */ - // lua_Number limit = fltvalue(ra + 1); - // if (luai_numlt(0, step) ? luai_numle(idx, limit) - // : luai_numle(limit, idx)) { - // ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - // setfltvalue(ra, idx); /* update internal index... */ - // setfltvalue(ra + 3, idx); /* ...and external index */ - // } - //} - - emit_debug_trace(def, OP_FORLOOP, pc1); - - // Load pointer to base - emit_load_base(def); - - // TValue *rinit = ra; - // TValue *rlimit = ra + 1; - // TValue *rstep = ra + 2; - // TValue *rvar = ra + 3 - llvm::Value *rinit = emit_gep_register(def, A); - llvm::Value *rlimit = emit_gep_register(def, A + 1); - llvm::Value *rstep = emit_gep_register(def, A + 2); - llvm::Value *rvar = emit_gep_register(def, A + 3); - - // Create the done block - llvm::BasicBlock *exit_block = - llvm::BasicBlock::Create(def->jitState->context(), "exit_forloop"); - - // Is index an integer? - llvm::Instruction *rinit_tt = emit_load_type(def, rinit); - llvm::Value *cmp1 = - emit_is_value_of_type(def, rinit_tt, LUA__TNUMINT, "init.is.integer"); - - // Setup if then else branch for integer - llvm::BasicBlock *if_integer = - llvm::BasicBlock::Create(def->jitState->context(), "if.integer", def->f); - llvm::BasicBlock *else_integer = - llvm::BasicBlock::Create(def->jitState->context(), "if.not.integer"); - def->builder->CreateCondBr(cmp1, if_integer, else_integer); - def->builder->SetInsertPoint(if_integer); - - // INTEGER CASE - - // lua_Integer step = ivalue(ra + 2); - llvm::Instruction *step_int_value = emit_load_reg_i(def, rstep); - - // lua_Integer idx = ivalue(ra) + step; /* increment index */ - llvm::Instruction *idx_int_value = emit_load_reg_i(def, rinit); - llvm::Value *new_idx = def->builder->CreateAdd(step_int_value, idx_int_value, - "next.idx", false, true); - - // lua_Integer limit = ivalue(ra + 1); - llvm::Instruction *limit_int_value = emit_load_reg_i(def, rlimit); - - // step > 0? - llvm::Value *step_gt_zero = def->builder->CreateICmpSGT( - step_int_value, def->types->kluaInteger[0], "step.gt.zero"); - - llvm::BasicBlock *step_gt_zero_true = llvm::BasicBlock::Create( - def->jitState->context(), "step.gt.zero.true", def->f); - llvm::BasicBlock *step_gt_zero_false = - llvm::BasicBlock::Create(def->jitState->context(), "step.gt.zero.false"); - def->builder->CreateCondBr(step_gt_zero, step_gt_zero_true, - step_gt_zero_false); - def->builder->SetInsertPoint(step_gt_zero_true); - - // idx > limit? - llvm::Value *new_idx_gt_limit = - def->builder->CreateICmpSGT(new_idx, limit_int_value, "idx.gt.limit"); - - // If idx > limit we are done - llvm::BasicBlock *update_block = - llvm::BasicBlock::Create(def->jitState->context(), "update"); - def->builder->CreateCondBr(new_idx_gt_limit, exit_block, update_block); - - def->f->getBasicBlockList().push_back(step_gt_zero_false); - def->builder->SetInsertPoint(step_gt_zero_false); - - // limit > idx? - llvm::Value *limit_gt_idx = - def->builder->CreateICmpSGT(limit_int_value, new_idx, "limit.gt.idx"); - - // If limit > idx we are done - def->builder->CreateCondBr(limit_gt_idx, exit_block, update_block); - - // Merge into update block - def->f->getBasicBlockList().push_back(update_block); - def->builder->SetInsertPoint(update_block); - - // setivalue(ra, idx); /* update internal index... */ - emit_store_reg_i(def, new_idx, rinit); - - // setivalue(ra + 3, idx); /* ...and external index */ - emit_store_reg_i_withtype(def, new_idx, rvar); - - // ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - def->builder->CreateBr(def->jmp_targets[pc].jmp1); - - // FLOATING CASE - - def->f->getBasicBlockList().push_back(else_integer); - def->builder->SetInsertPoint(else_integer); - - // lua_Number step = fltvalue(ra + 2); - llvm::Instruction *step_double_value = emit_load_reg_n(def, rstep); - - // lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */ - llvm::Instruction *idx_double_value = emit_load_reg_n(def, rinit); - - new_idx = - def->builder->CreateFAdd(step_double_value, idx_double_value, "next.idx"); - - // lua_Number limit = fltvalue(ra + 1); - llvm::Instruction *limit_double_value = emit_load_reg_n(def, rlimit); - - // step > 0? - step_gt_zero = def->builder->CreateFCmpOGT( - step_double_value, llvm::ConstantFP::get(def->types->lua_NumberT, 0.0), - "step.gt.zero"); - - step_gt_zero_true = llvm::BasicBlock::Create(def->jitState->context(), - "step.gt.zero.true", def->f); - step_gt_zero_false = - llvm::BasicBlock::Create(def->jitState->context(), "step.gt.zero.false"); - def->builder->CreateCondBr(step_gt_zero, step_gt_zero_true, - step_gt_zero_false); - def->builder->SetInsertPoint(step_gt_zero_true); - - // idx > limit? - new_idx_gt_limit = - def->builder->CreateFCmpOGT(new_idx, limit_double_value, "idx.gt.limit"); - - // If idx > limit we are done - update_block = llvm::BasicBlock::Create(def->jitState->context(), "update"); - def->builder->CreateCondBr(new_idx_gt_limit, exit_block, update_block); - - def->f->getBasicBlockList().push_back(step_gt_zero_false); - def->builder->SetInsertPoint(step_gt_zero_false); - - // limit > idx? - limit_gt_idx = - def->builder->CreateFCmpOGT(limit_double_value, new_idx, "limit.gt.idx"); - - // If limit > idx we are done - def->builder->CreateCondBr(limit_gt_idx, exit_block, update_block); - - // Merge into update block - def->f->getBasicBlockList().push_back(update_block); - def->builder->SetInsertPoint(update_block); - - // setfltvalue(ra, idx); /* update internal index... */ - emit_store_reg_n(def, new_idx, rinit); - - // setfltvalue(ra + 3, idx); /* ...and external index */ - emit_store_reg_n_withtype(def, new_idx, rvar); - - // ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - def->builder->CreateBr(def->jmp_targets[pc].jmp1); - - def->f->getBasicBlockList().push_back(exit_block); - def->builder->SetInsertPoint(exit_block); -} - -void RaviCodeGenerator::emit_iFORLOOP(RaviFunctionDef *def, int A, int pc, - RaviBranchDef &b, int step_one, int pc1) { - - // lua_Integer step = ivalue(ra + 2); - // lua_Integer idx = ivalue(ra) + step; /* increment index */ - // lua_Integer limit = ivalue(ra + 1); - // if (idx <= limit) { - // ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - // setivalue(ra, idx); /* update internal index... */ - // setivalue(ra + 3, idx); /* ...and external index */ - // } - - emit_debug_trace(def, step_one ? OP_RAVI_FORLOOP_I1 : OP_RAVI_FORLOOP_IP, - pc1); - // We are in b.jmp1 as this is already the current block - lua_assert(def->builder->GetInsertBlock() == b.jmp1); - - // Obtain pointers to the value.i field - llvm::Value *idx_int_ptr = b.iidx; - llvm::Value *limit_int_ptr = b.ilimit; - - // Create the done block - llvm::BasicBlock *exit_block = - llvm::BasicBlock::Create(def->jitState->context(), "exit_iforloop"); - - // lua_Integer idx = ivalue(ra) + step; /* increment index */ - llvm::Instruction *idx_int_value = emit_load_local_n(def, idx_int_ptr); - llvm::Value *new_idx; - - if (!step_one) { - // lua_Integer step = ivalue(ra + 2); - llvm::Value *step_int_ptr = b.istep; - llvm::Instruction *step_int_value = emit_load_local_n(def, step_int_ptr); - new_idx = def->builder->CreateAdd(step_int_value, idx_int_value, "next.idx", - false, true); - } else - new_idx = def->builder->CreateAdd(def->types->kluaInteger[1], idx_int_value, - "next.idx", false, true); - - // save new index - emit_store_local_n(def, new_idx, idx_int_ptr); - - // lua_Integer limit = ivalue(ra + 1); - llvm::Instruction *limit_int_value = emit_load_local_n(def, limit_int_ptr); - - // idx > limit? - llvm::Value *new_idx_gt_limit = - def->builder->CreateICmpSGT(new_idx, limit_int_value, "idx.gt.limit"); - - // If idx > limit we are done - llvm::BasicBlock *update_block = - llvm::BasicBlock::Create(def->jitState->context(), "updatei"); - def->builder->CreateCondBr(new_idx_gt_limit, exit_block, update_block); - - // Merge into update block - def->f->getBasicBlockList().push_back(update_block); - def->builder->SetInsertPoint(update_block); - - // Load pointer to base - emit_load_base(def); - - llvm::Value *rvar = emit_gep_register(def, A + 3); - - // setivalue(ra + 3, idx); /* ...and external index */ - idx_int_value = emit_load_local_n(def, idx_int_ptr); - emit_store_reg_i_withtype(def, idx_int_value, rvar); - - // ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - def->builder->CreateBr(def->jmp_targets[pc].jmp1); - - def->f->getBasicBlockList().push_back(exit_block); - def->builder->SetInsertPoint(exit_block); -} -} \ No newline at end of file diff --git a/src/ravi_llvmforprep.cpp b/src/ravi_llvmforprep.cpp deleted file mode 100644 index f4ce603..0000000 --- a/src/ravi_llvmforprep.cpp +++ /dev/null @@ -1,764 +0,0 @@ -/****************************************************************************** -* 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. -******************************************************************************/ -#include "ravi_llvmcodegen.h" - -namespace ravi { - -void RaviCodeGenerator::emit_FORPREP2(RaviFunctionDef *def, int A, int pc, - int pc1) { - - // Create additional forloop targets - // First target is for int < limit - RaviBranchDef &forloop_target = def->jmp_targets[pc]; - - // case OP_FORPREP: { - // if (ttisinteger(init) && ttisinteger(pstep) && - // forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) { - // /* all values are integer */ - // lua_Integer initv = (stopnow ? 0 : ivalue(init)); - // setivalue(plimit, ilimit); - // setivalue(init, initv - ivalue(pstep)); - // } - // else { /* try making all values floats */ - // if (!tonumber(plimit, &nlimit)) - // luaG_runerror(L, "'for' limit must be a number"); - // setfltvalue(plimit, nlimit); - // if (!tonumber(pstep, &nstep)) - // luaG_runerror(L, "'for' step must be a number"); - // setfltvalue(pstep, nstep); - // if (!tonumber(init, &ninit)) - // luaG_runerror(L, "'for' initial value must be a number"); - // setfltvalue(init, luai_numsub(L, ninit, nstep)); - // } - // ci->u.l.savedpc += GETARG_sBx(i); - //} break; - - emit_debug_trace(def, OP_FORPREP, pc1); - // Load pointer to base - emit_load_base(def); - - // lua_Integer ilimit; - // int stopnow; - // lua_Number ninit; lua_Number nlimit; lua_Number nstep; - - // Setup local vars on C stack and link them - // to the forloop_target so that the forloop code can access these - - llvm::IRBuilder<> TmpB(def->entry, def->entry->begin()); - llvm::Value *stopnow = - TmpB.CreateAlloca(def->types->C_intT, nullptr, "stopnow"); - - forloop_target.ilimit = - TmpB.CreateAlloca(def->types->lua_IntegerT, nullptr, "ilimit"); - forloop_target.istep = - TmpB.CreateAlloca(def->types->lua_IntegerT, nullptr, "istep"); - forloop_target.iidx = - TmpB.CreateAlloca(def->types->lua_IntegerT, nullptr, "iidx"); - forloop_target.flimit = - TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "nlimit"); - forloop_target.fidx = - TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "ninit"); - forloop_target.fstep = - TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "nstep"); - forloop_target.forloop_branch = - TmpB.CreateAlloca(def->types->C_pcharT, nullptr, "brnch"); - - llvm::Value *isinc = nullptr; - - // TValue *init = ra; - // TValue *plimit = ra + 1; - // TValue *pstep = ra + 2; - llvm::Value *init = emit_gep_register(def, A); - llvm::Value *plimit = emit_gep_register(def, A + 1); - llvm::Value *pstep = emit_gep_register(def, A + 2); - - // if (ttisinteger(init) && ttisinteger(pstep) && - // forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) { - - // Get init->tt - llvm::Instruction *pinit_tt = emit_load_type(def, init); - - // Compare init->tt == LUA_TNUMINT - llvm::Value *cmp1 = - emit_is_value_of_type(def, pinit_tt, LUA__TNUMINT, "init.is.integer"); - - // Get pstep->tt - llvm::Instruction *pstep_tt = emit_load_type(def, pstep); - - // Compare pstep->tt == LUA_TNUMINT - llvm::Value *icmp2 = - emit_is_value_of_type(def, pstep_tt, LUA__TNUMINT, "step.is.integer"); - - // Get ivalue(pstep) - llvm::Instruction *pstep_ivalue = emit_load_reg_i(def, pstep); - - // Call forlimit() - llvm::Value *forlimit_ret = - CreateCall4(def->builder, def->luaV_forlimitF, plimit, - forloop_target.ilimit, pstep_ivalue, stopnow); - - // Is init->tt == LUA_TNUMINT && pstep->tt == LUA_TNUMINT - llvm::Value *and1 = - def->builder->CreateAnd(cmp1, icmp2, "init.and.step.are.integers"); - - // Convert result from forlimit() to bool - llvm::Value *tobool = - def->builder->CreateICmpNE(forlimit_ret, def->types->kInt[0]); - - // Are all vars integers? - // init->tt == LUA_TNUMINT && pstep->tt == LUA_TNUMINT && forlimit() - llvm::Value *and2 = def->builder->CreateAnd(and1, tobool, "all.integers"); - - // Create if then else branch - llvm::BasicBlock *then1 = llvm::BasicBlock::Create(def->jitState->context(), - "if.all.integers", def->f); - llvm::BasicBlock *else1 = - llvm::BasicBlock::Create(def->jitState->context(), "if.not.all.integers"); - def->builder->CreateCondBr(and2, then1, else1); - def->builder->SetInsertPoint(then1); - - // all values are integers - // lua_Integer initv = (stopnow ? 0 : ivalue(init)); - // Save step - emit_store_local_n(def, pstep_ivalue, forloop_target.istep); - - // Get stopnow - llvm::Instruction *stopnow_val = emit_load_local_int(def, stopnow); - - // Test if stopnow is 0 - llvm::Value *stopnow_is_zero = def->builder->CreateICmpEQ( - stopnow_val, def->types->kInt[0], "stopnow.is.zero"); - - // Get ptr to init->i - - // Setup if then else branch for stopnow - llvm::BasicBlock *then1_iffalse = llvm::BasicBlock::Create( - def->jitState->context(), "if.stopnow.iszero", def->f); - llvm::BasicBlock *then1_iftrue = - llvm::BasicBlock::Create(def->jitState->context(), "if.stopnow.notzero"); - def->builder->CreateCondBr(stopnow_is_zero, then1_iffalse, then1_iftrue); - def->builder->SetInsertPoint(then1_iffalse); - - // stopnow is 0 - // Get init->i - llvm::Instruction *init_ivalue = emit_load_reg_i(def, init); - - // Join after the branch - def->builder->CreateBr(then1_iftrue); - def->f->getBasicBlockList().push_back(then1_iftrue); - def->builder->SetInsertPoint(then1_iftrue); - - // Set initv to 0 if !stopnow else init->i - auto phi1 = def->builder->CreatePHI(def->types->lua_IntegerT, 2, "initv"); - phi1->addIncoming(init_ivalue, then1_iffalse); - phi1->addIncoming(def->types->kluaInteger[0], then1); - - // setivalue(init, initv - ivalue(pstep)); - // we aleady know init is LUA_TNUMINT - - llvm::Value *sub = - def->builder->CreateSub(phi1, pstep_ivalue, "initv-pstep.i", false, true); - emit_store_local_n(def, sub, forloop_target.iidx); - - // Ok so now we need to decide which jump target - isinc = def->builder->CreateICmpSGT(pstep_ivalue, def->types->kluaInteger[0], - "step.gt.zero"); - - // Create if then else branch - llvm::BasicBlock *b1 = - llvm::BasicBlock::Create(def->jitState->context(), "b1", def->f); - llvm::BasicBlock *b2 = - llvm::BasicBlock::Create(def->jitState->context(), "b2"); - llvm::BasicBlock *b3 = - llvm::BasicBlock::Create(def->jitState->context(), "b3"); - - def->builder->CreateCondBr(isinc, b1, b2); - def->builder->SetInsertPoint(b1); - - // TODO tbaa? - def->builder->CreateStore( - llvm::BlockAddress::get(def->f, forloop_target.jmp1), - forloop_target.forloop_branch); - - def->builder->CreateBr(b3); - - def->f->getBasicBlockList().push_back(b2); - def->builder->SetInsertPoint(b2); - - // TODO tbaa? - def->builder->CreateStore( - llvm::BlockAddress::get(def->f, forloop_target.jmp2), - forloop_target.forloop_branch); - - def->builder->CreateBr(b3); - - def->f->getBasicBlockList().push_back(b3); - def->builder->SetInsertPoint(b3); - - // Create branch - def->builder->CreateCondBr(isinc, forloop_target.jmp1, forloop_target.jmp2); - - // NOW the non-integer case - - def->f->getBasicBlockList().push_back(else1); - def->builder->SetInsertPoint(else1); - - // ************ PLIMIT - Convert plimit to float - - llvm::Instruction *plimit_tt = emit_load_type(def, plimit); - - // Test if already a float - cmp1 = emit_is_value_of_type(def, plimit_tt, LUA__TNUMFLT, "limit.is.float"); - llvm::BasicBlock *else1_plimit_ifnum = llvm::BasicBlock::Create( - def->jitState->context(), "if.limit.isfloat", def->f); - llvm::BasicBlock *else1_plimit_elsenum = - llvm::BasicBlock::Create(def->jitState->context(), "if.limit.notfloat"); - def->builder->CreateCondBr(cmp1, else1_plimit_ifnum, else1_plimit_elsenum); - def->builder->SetInsertPoint(else1_plimit_ifnum); - - // Already a float - copy to nlimit - llvm::Instruction *plimit_nvalue_load = emit_load_reg_n(def, plimit); - emit_store_local_n(def, plimit_nvalue_load, forloop_target.flimit); - - // Go to the PSTEP section - llvm::BasicBlock *else1_pstep = - llvm::BasicBlock::Create(def->jitState->context(), "if.else.step"); - def->builder->CreateBr(else1_pstep); - - // If plimit was not already a float we need to convert - def->f->getBasicBlockList().push_back(else1_plimit_elsenum); - def->builder->SetInsertPoint(else1_plimit_elsenum); - // Call luaV_tonumber_() - llvm::Value *plimit_isnum = CreateCall2(def->builder, def->luaV_tonumberF, - plimit, forloop_target.flimit); - llvm::Value *plimit_isnum_bool = def->builder->CreateICmpEQ( - plimit_isnum, def->types->kInt[0], "limit.float.ok"); - - // Did conversion fail? - llvm::BasicBlock *else1_plimit_tonum_elsenum = llvm::BasicBlock::Create( - def->jitState->context(), "if.limit.float.failed", def->f); - def->builder->CreateCondBr(plimit_isnum_bool, else1_plimit_tonum_elsenum, - else1_pstep); - - // Conversion failed, so raise error - def->builder->SetInsertPoint(else1_plimit_tonum_elsenum); - emit_raise_lua_error(def, "'for' limit must be a number"); - def->builder->CreateBr(else1_pstep); - - // Conversion OK - // Update plimit - def->f->getBasicBlockList().push_back(else1_pstep); - def->builder->SetInsertPoint(else1_pstep); - - // *********** PSTEP - convert pstep to float - // Test if already a float - pstep_tt = emit_load_type(def, pstep); - cmp1 = emit_is_value_of_type(def, pstep_tt, LUA__TNUMFLT, "step.is.float"); - llvm::BasicBlock *else1_pstep_ifnum = llvm::BasicBlock::Create( - def->jitState->context(), "if.step.isfloat", def->f); - llvm::BasicBlock *else1_pstep_elsenum = - llvm::BasicBlock::Create(def->jitState->context(), "if.step.notfloat"); - def->builder->CreateCondBr(cmp1, else1_pstep_ifnum, else1_pstep_elsenum); - def->builder->SetInsertPoint(else1_pstep_ifnum); - - // We float then copy to nstep - llvm::Instruction *pstep_nvalue_load = emit_load_reg_n(def, pstep); - emit_store_local_n(def, pstep_nvalue_load, forloop_target.fstep); - - // Now go to handle initial value - llvm::BasicBlock *else1_pinit = - llvm::BasicBlock::Create(def->jitState->context(), "if.else.init"); - def->builder->CreateBr(else1_pinit); - - // If pstep was not already a float then we need to convert - def->f->getBasicBlockList().push_back(else1_pstep_elsenum); - def->builder->SetInsertPoint(else1_pstep_elsenum); - - // call luaV_tonumber_() - llvm::Value *pstep_isnum = CreateCall2(def->builder, def->luaV_tonumberF, - pstep, forloop_target.fstep); - llvm::Value *pstep_isnum_bool = def->builder->CreateICmpEQ( - pstep_isnum, def->types->kInt[0], "step.float.ok"); - llvm::BasicBlock *else1_pstep_tonum_elsenum = llvm::BasicBlock::Create( - def->jitState->context(), "if.step.float.failed", def->f); - def->builder->CreateCondBr(pstep_isnum_bool, else1_pstep_tonum_elsenum, - else1_pinit); - - // If conversion failed raise error - def->builder->SetInsertPoint(else1_pstep_tonum_elsenum); - emit_raise_lua_error(def, "'for' step must be a number"); - def->builder->CreateBr(else1_pinit); - - // Conversion okay so update pstep - def->f->getBasicBlockList().push_back(else1_pinit); - def->builder->SetInsertPoint(else1_pinit); - - // *********** PINIT finally handle initial value - - // Check if it is already a float - pinit_tt = emit_load_type(def, init); - cmp1 = emit_is_value_of_type(def, pinit_tt, LUA__TNUMFLT, "init.is.float"); - llvm::BasicBlock *else1_pinit_ifnum = llvm::BasicBlock::Create( - def->jitState->context(), "if.init.is.float", def->f); - llvm::BasicBlock *else1_pinit_elsenum = - llvm::BasicBlock::Create(def->jitState->context(), "if.init.not.float"); - def->builder->CreateCondBr(cmp1, else1_pinit_ifnum, else1_pinit_elsenum); - def->builder->SetInsertPoint(else1_pinit_ifnum); - - // Already float so copy to ninit - llvm::Instruction *pinit_nvalue_load = emit_load_reg_n(def, init); - emit_store_local_n(def, pinit_nvalue_load, forloop_target.fidx); - - // Go to final section - llvm::BasicBlock *else1_pdone = - llvm::BasicBlock::Create(def->jitState->context(), "if.else.done"); - def->builder->CreateBr(else1_pdone); - - // Not a float so we need to convert - def->f->getBasicBlockList().push_back(else1_pinit_elsenum); - def->builder->SetInsertPoint(else1_pinit_elsenum); - - // Call luaV_tonumber_() - llvm::Value *pinit_isnum = - CreateCall2(def->builder, def->luaV_tonumberF, init, forloop_target.fidx); - llvm::Value *pinit_isnum_bool = def->builder->CreateICmpEQ( - pinit_isnum, def->types->kInt[0], "init.float.ok"); - llvm::BasicBlock *else1_pinit_tonum_elsenum = llvm::BasicBlock::Create( - def->jitState->context(), "if.init.float.failed", def->f); - def->builder->CreateCondBr(pinit_isnum_bool, else1_pinit_tonum_elsenum, - else1_pdone); - - // Conversion failed so raise error - def->builder->SetInsertPoint(else1_pinit_tonum_elsenum); - emit_raise_lua_error(def, "'for' initial value must be a number"); - def->builder->CreateBr(else1_pdone); - - // Conversion OK so we are nearly done - def->f->getBasicBlockList().push_back(else1_pdone); - def->builder->SetInsertPoint(else1_pdone); - llvm::Instruction *ninit_load = emit_load_local_n(def, forloop_target.fidx); - llvm::Instruction *nstep_load = emit_load_local_n(def, forloop_target.fstep); - - // setfltvalue(init, luai_numsub(L, ninit, nstep)); - llvm::Value *init_n = - def->builder->CreateFSub(ninit_load, nstep_load, "ninit-nstep"); - - emit_store_local_n(def, init_n, forloop_target.fidx); - - // Done so jump to forloop - llvm::Value *fstep_gt_zero = def->builder->CreateFCmpOGT( - nstep_load, llvm::ConstantFP::get(def->types->lua_NumberT, 0.0), - "step.gt.zero"); - - // Create if then else branch - b1 = llvm::BasicBlock::Create(def->jitState->context(), "b1", def->f); - b2 = llvm::BasicBlock::Create(def->jitState->context(), "b2"); - b3 = llvm::BasicBlock::Create(def->jitState->context(), "b3"); - - def->builder->CreateCondBr(fstep_gt_zero, b1, b2); - def->builder->SetInsertPoint(b1); - - def->builder->CreateStore( - llvm::BlockAddress::get(def->f, forloop_target.jmp3), - forloop_target.forloop_branch); - def->builder->CreateBr(b3); - - def->f->getBasicBlockList().push_back(b2); - def->builder->SetInsertPoint(b2); - def->builder->CreateStore( - llvm::BlockAddress::get(def->f, forloop_target.jmp4), - forloop_target.forloop_branch); - def->builder->CreateBr(b3); - - def->f->getBasicBlockList().push_back(b3); - def->builder->SetInsertPoint(b3); - - def->builder->CreateCondBr(fstep_gt_zero, forloop_target.jmp3, - forloop_target.jmp4); -} - -void RaviCodeGenerator::emit_FORPREP(RaviFunctionDef *def, int A, int pc, - int pc1) { - - // case OP_FORPREP: { - // if (ttisinteger(init) && ttisinteger(pstep) && - // forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) { - // /* all values are integer */ - // lua_Integer initv = (stopnow ? 0 : ivalue(init)); - // setivalue(plimit, ilimit); - // setivalue(init, initv - ivalue(pstep)); - // } - // else { /* try making all values floats */ - // if (!tonumber(plimit, &nlimit)) - // luaG_runerror(L, "'for' limit must be a number"); - // setfltvalue(plimit, nlimit); - // if (!tonumber(pstep, &nstep)) - // luaG_runerror(L, "'for' step must be a number"); - // setfltvalue(pstep, nstep); - // if (!tonumber(init, &ninit)) - // luaG_runerror(L, "'for' initial value must be a number"); - // setfltvalue(init, luai_numsub(L, ninit, nstep)); - // } - // ci->u.l.savedpc += GETARG_sBx(i); - //} break; - - emit_debug_trace(def, OP_FORPREP, pc1); - // Load pointer to base - emit_load_base(def); - - // lua_Integer ilimit; - // int stopnow; - // lua_Number ninit; lua_Number nlimit; lua_Number nstep; - llvm::IRBuilder<> TmpB(def->entry, def->entry->begin()); - - llvm::Value *ilimit = - TmpB.CreateAlloca(def->types->lua_IntegerT, nullptr, "ilimit"); - llvm::Value *stopnow = - TmpB.CreateAlloca(def->types->C_intT, nullptr, "stopnow"); - llvm::Value *nlimit = - TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "nlimit"); - llvm::Value *ninit = - TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "ninit"); - llvm::Value *nstep = - TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "nstep"); - - // TValue *init = ra; - // TValue *plimit = ra + 1; - // TValue *pstep = ra + 2; - llvm::Value *init = emit_gep_register(def, A); - llvm::Value *plimit = emit_gep_register(def, A + 1); - llvm::Value *pstep = emit_gep_register(def, A + 2); - - // if (ttisinteger(init) && ttisinteger(pstep) && - // forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) { - - // Get init->tt_ - llvm::Instruction *pinit_tt = emit_load_type(def, init); - - // Compare init->tt_ == LUA_TNUMINT - llvm::Value *cmp1 = - emit_is_value_of_type(def, pinit_tt, LUA__TNUMINT, "init.is.integer"); - - // Get pstep->tt_ - llvm::Instruction *pstep_tt = emit_load_type(def, pstep); - - // Compare pstep->tt_ == LUA_TNUMINT - llvm::Value *icmp2 = - emit_is_value_of_type(def, pstep_tt, LUA__TNUMINT, "step.is.integer"); - - // Get ivalue(pstep) - llvm::Instruction *pstep_ivalue = emit_load_reg_i(def, pstep); - - // Call forlimit() - llvm::Value *forlimit_ret = CreateCall4( - def->builder, def->luaV_forlimitF, plimit, ilimit, pstep_ivalue, stopnow); - - // init->tt_ == LUA_TNUMINT && pstep->tt_ == LUA_TNUMINT - llvm::Value *and1 = - def->builder->CreateAnd(cmp1, icmp2, "init.and.step.are.integers"); - - // Convert result from forlimit() to bool - llvm::Value *tobool = - def->builder->CreateICmpNE(forlimit_ret, def->types->kInt[0]); - - // init->tt_ == LUA_TNUMINT && pstep->tt_ == LUA_TNUMINT && forlimit() - llvm::Value *and2 = def->builder->CreateAnd(and1, tobool, "all.integers"); - - // Create if then else branch - llvm::BasicBlock *then1 = llvm::BasicBlock::Create(def->jitState->context(), - "if.all.integers", def->f); - llvm::BasicBlock *else1 = - llvm::BasicBlock::Create(def->jitState->context(), "if.not.all.integers"); - def->builder->CreateCondBr(and2, then1, else1); - def->builder->SetInsertPoint(then1); - - // all values are integers - // lua_Integer initv = (stopnow ? 0 : ivalue(init)); - - // Get stopnow - llvm::Instruction *stopnow_val = emit_load_local_int(def, stopnow); - - // Test if stopnow is 0 - llvm::Value *stopnow_is_zero = def->builder->CreateICmpEQ( - stopnow_val, def->types->kInt[0], "stopnow.is.zero"); - - // Setup if then else branch for stopnow - llvm::BasicBlock *then1_iffalse = llvm::BasicBlock::Create( - def->jitState->context(), "if.stopnow.iszero", def->f); - llvm::BasicBlock *then1_iftrue = - llvm::BasicBlock::Create(def->jitState->context(), "if.stopnow.notzero"); - def->builder->CreateCondBr(stopnow_is_zero, then1_iffalse, then1_iftrue); - def->builder->SetInsertPoint(then1_iffalse); - - // stopnow is 0 - // Get init->i - llvm::Instruction *init_ivalue = emit_load_reg_i(def, init); - - // Join after the branch - def->builder->CreateBr(then1_iftrue); - def->f->getBasicBlockList().push_back(then1_iftrue); - def->builder->SetInsertPoint(then1_iftrue); - - // Set initv to 0 if !stopnow else init->i - auto phi1 = def->builder->CreatePHI(def->types->lua_IntegerT, 2, "initv"); - phi1->addIncoming(init_ivalue, then1_iffalse); - phi1->addIncoming(def->types->kluaInteger[0], then1); - - // setivalue(plimit, ilimit); - llvm::Instruction *ilimit_val = emit_load_local_n(def, ilimit); - - emit_store_reg_i_withtype(def, ilimit_val, plimit); - - // setivalue(init, initv - ivalue(pstep)); - // we aleady know init is LUA_TNUMINT - pstep_ivalue = emit_load_reg_i(def, pstep); - llvm::Value *sub = - def->builder->CreateSub(phi1, pstep_ivalue, "initv-pstep.i", false, true); - - emit_store_reg_i(def, sub, init); - - // We are done so jump to forloop - lua_assert(def->jmp_targets[pc].jmp1); - def->builder->CreateBr(def->jmp_targets[pc].jmp1); - - // NOW the non-integer case - - def->f->getBasicBlockList().push_back(else1); - def->builder->SetInsertPoint(else1); - - // ************ PLIMIT - Convert plimit to float - - llvm::Instruction *plimit_tt = emit_load_type(def, plimit); - // Test if already a float - cmp1 = emit_is_value_of_type(def, plimit_tt, LUA__TNUMFLT, "limit.is.float"); - llvm::BasicBlock *else1_plimit_ifnum = llvm::BasicBlock::Create( - def->jitState->context(), "if.limit.isfloat", def->f); - llvm::BasicBlock *else1_plimit_elsenum = - llvm::BasicBlock::Create(def->jitState->context(), "if.limit.notfloat"); - def->builder->CreateCondBr(cmp1, else1_plimit_ifnum, else1_plimit_elsenum); - def->builder->SetInsertPoint(else1_plimit_ifnum); - - // Already a float - copy to nlimit - llvm::Instruction *plimit_nvalue_load = emit_load_reg_n(def, plimit); - emit_store_local_n(def, plimit_nvalue_load, nlimit); - - // Go to the PSTEP section - llvm::BasicBlock *else1_pstep = - llvm::BasicBlock::Create(def->jitState->context(), "if.else.step"); - def->builder->CreateBr(else1_pstep); - - // If plimit was not already a float we need to convert - def->f->getBasicBlockList().push_back(else1_plimit_elsenum); - def->builder->SetInsertPoint(else1_plimit_elsenum); - // Call luaV_tonumber_() - llvm::Value *plimit_isnum = - CreateCall2(def->builder, def->luaV_tonumberF, plimit, nlimit); - llvm::Value *plimit_isnum_bool = def->builder->CreateICmpEQ( - plimit_isnum, def->types->kInt[0], "limit.float.ok"); - - // Did conversion fail? - llvm::BasicBlock *else1_plimit_tonum_elsenum = llvm::BasicBlock::Create( - def->jitState->context(), "if.limit.float.failed", def->f); - def->builder->CreateCondBr(plimit_isnum_bool, else1_plimit_tonum_elsenum, - else1_pstep); - - // Conversion failed, so raise error - def->builder->SetInsertPoint(else1_plimit_tonum_elsenum); - emit_raise_lua_error(def, "'for' limit must be a number"); - def->builder->CreateBr(else1_pstep); - - // Conversion OK - // Update plimit - def->f->getBasicBlockList().push_back(else1_pstep); - def->builder->SetInsertPoint(else1_pstep); - llvm::Instruction *nlimit_load = emit_load_local_n(def, nlimit); - - emit_store_reg_n_withtype(def, nlimit_load, plimit); - - // *********** PSTEP - convert pstep to float - // Test if already a float - pstep_tt = emit_load_type(def, pstep); - cmp1 = emit_is_value_of_type(def, pstep_tt, LUA__TNUMFLT, "step.is.float"); - llvm::BasicBlock *else1_pstep_ifnum = llvm::BasicBlock::Create( - def->jitState->context(), "if.step.isfloat", def->f); - llvm::BasicBlock *else1_pstep_elsenum = - llvm::BasicBlock::Create(def->jitState->context(), "if.step.notfloat"); - def->builder->CreateCondBr(cmp1, else1_pstep_ifnum, else1_pstep_elsenum); - def->builder->SetInsertPoint(else1_pstep_ifnum); - - // We float then copy to nstep - llvm::Instruction *pstep_nvalue_load = emit_load_reg_n(def, pstep); - emit_store_local_n(def, pstep_nvalue_load, nstep); - - // Now go to handle initial value - llvm::BasicBlock *else1_pinit = - llvm::BasicBlock::Create(def->jitState->context(), "if.else.init"); - def->builder->CreateBr(else1_pinit); - - // If pstep was not already a float then we need to convert - def->f->getBasicBlockList().push_back(else1_pstep_elsenum); - def->builder->SetInsertPoint(else1_pstep_elsenum); - - // call luaV_tonumber_() - llvm::Value *pstep_isnum = - CreateCall2(def->builder, def->luaV_tonumberF, pstep, nstep); - llvm::Value *pstep_isnum_bool = def->builder->CreateICmpEQ( - pstep_isnum, def->types->kInt[0], "step.float.ok"); - llvm::BasicBlock *else1_pstep_tonum_elsenum = llvm::BasicBlock::Create( - def->jitState->context(), "if.step.float.failed", def->f); - def->builder->CreateCondBr(pstep_isnum_bool, else1_pstep_tonum_elsenum, - else1_pinit); - - // If conversion failed raise error - def->builder->SetInsertPoint(else1_pstep_tonum_elsenum); - emit_raise_lua_error(def, "'for' step must be a number"); - def->builder->CreateBr(else1_pinit); - - // Conversion okay so update pstep - def->f->getBasicBlockList().push_back(else1_pinit); - def->builder->SetInsertPoint(else1_pinit); - - llvm::Instruction *nstep_load = emit_load_local_n(def, nstep); - - emit_store_reg_n_withtype(def, nstep_load, pstep); - - // *********** PINIT finally handle initial value - - // Check if it is already a float - pinit_tt = emit_load_type(def, init); - cmp1 = emit_is_value_of_type(def, pinit_tt, LUA__TNUMFLT, "init.is.float"); - llvm::BasicBlock *else1_pinit_ifnum = llvm::BasicBlock::Create( - def->jitState->context(), "if.init.is.float", def->f); - llvm::BasicBlock *else1_pinit_elsenum = - llvm::BasicBlock::Create(def->jitState->context(), "if.init.not.float"); - def->builder->CreateCondBr(cmp1, else1_pinit_ifnum, else1_pinit_elsenum); - def->builder->SetInsertPoint(else1_pinit_ifnum); - - // Already float so copy to ninit - llvm::Instruction *pinit_nvalue_load = emit_load_reg_n(def, init); - emit_store_local_n(def, pinit_nvalue_load, ninit); - - // Go to final section - llvm::BasicBlock *else1_pdone = - llvm::BasicBlock::Create(def->jitState->context(), "if.else.done"); - def->builder->CreateBr(else1_pdone); - - // Not a float so we need to convert - def->f->getBasicBlockList().push_back(else1_pinit_elsenum); - def->builder->SetInsertPoint(else1_pinit_elsenum); - - // Call luaV_tonumber_() - llvm::Value *pinit_isnum = - CreateCall2(def->builder, def->luaV_tonumberF, init, ninit); - llvm::Value *pinit_isnum_bool = def->builder->CreateICmpEQ( - pinit_isnum, def->types->kInt[0], "init.float.ok"); - llvm::BasicBlock *else1_pinit_tonum_elsenum = llvm::BasicBlock::Create( - def->jitState->context(), "if.init.float.failed", def->f); - def->builder->CreateCondBr(pinit_isnum_bool, else1_pinit_tonum_elsenum, - else1_pdone); - - // Conversion failed so raise error - def->builder->SetInsertPoint(else1_pinit_tonum_elsenum); - emit_raise_lua_error(def, "'for' initial value must be a number"); - def->builder->CreateBr(else1_pdone); - - // Conversion OK so we are nearly done - def->f->getBasicBlockList().push_back(else1_pdone); - def->builder->SetInsertPoint(else1_pdone); - llvm::Instruction *ninit_load = emit_load_local_n(def, ninit); - nstep_load = emit_load_local_n(def, nstep); - - // setfltvalue(init, luai_numsub(L, ninit, nstep)); - llvm::Value *init_n = - def->builder->CreateFSub(ninit_load, nstep_load, "ninit-nstep"); - - emit_store_reg_n_withtype(def, init_n, init); - - // Done so jump to forloop - def->builder->CreateBr(def->jmp_targets[pc].jmp1); -} - -void RaviCodeGenerator::emit_iFORPREP(RaviFunctionDef *def, int A, int pc, - int step_one, int pc1) { - - RaviBranchDef &forloop_target = def->jmp_targets[pc]; - - llvm::IRBuilder<> TmpB(def->entry, def->entry->begin()); - - forloop_target.ilimit = - TmpB.CreateAlloca(def->types->lua_IntegerT, nullptr, "ilimit"); - if (!step_one) { - forloop_target.istep = - TmpB.CreateAlloca(def->types->lua_IntegerT, nullptr, "istep"); - } - forloop_target.iidx = - TmpB.CreateAlloca(def->types->lua_IntegerT, nullptr, "iidx"); - - // lua_Integer initv = ivalue(init); - // setivalue(init, initv - ivalue(pstep)); - - emit_debug_trace(def, step_one ? OP_RAVI_FORPREP_I1 : OP_RAVI_FORPREP_IP, - pc1); - // Load pointer to base - emit_load_base(def); - - // TValue *init = ra; - // TValue *pstep = ra + 2; - llvm::Value *init = emit_gep_register(def, A); - llvm::Value *plimit = emit_gep_register(def, A + 1); - llvm::Value *pstep = nullptr; - if (!step_one) - pstep = emit_gep_register(def, A + 2); - - // Get ivalue(pstep) - llvm::Instruction *limit_ivalue = emit_load_reg_i(def, plimit); - llvm::Instruction *init_ivalue = emit_load_reg_i(def, init); - - if (!step_one) { - // setivalue(init, initv - ivalue(pstep)); - llvm::Instruction *step_ivalue = emit_load_reg_i(def, pstep); - llvm::Value *idx = def->builder->CreateSub(init_ivalue, step_ivalue, - "initv-pstep.i", false, true); - - // Save idx - emit_store_local_n(def, idx, forloop_target.iidx); - - // Save step - emit_store_local_n(def, step_ivalue, forloop_target.istep); - } else { - // setivalue(init, initv - ivalue(pstep)); - llvm::Value *idx = def->builder->CreateSub( - init_ivalue, def->types->kluaInteger[1], "initv-pstep.i", false, true); - - // Save idx - emit_store_local_n(def, idx, forloop_target.iidx); - } - - // Save limit - emit_store_local_n(def, limit_ivalue, forloop_target.ilimit); - - // We are done so jump to forloop - lua_assert(def->jmp_targets[pc].jmp1); - def->builder->CreateBr(def->jmp_targets[pc].jmp1); -} -} \ No newline at end of file diff --git a/src/ravi_llvmjit.cpp b/src/ravi_llvmjit.cpp deleted file mode 100644 index a08d222..0000000 --- a/src/ravi_llvmjit.cpp +++ /dev/null @@ -1,1091 +0,0 @@ -/****************************************************************************** - * 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. - ******************************************************************************/ -#include -// Important to include the C++ header files (ravi_llvmcodegen.h) before following -// (ravi_jitshared.h) as the Lua headers define macros that mess with C++ headers -#include - -/* - * Implementation Notes: - * Each Lua function is compiled into an LLVM Module/Function - * This strategy allows functions to be garbage collected as normal by Lua - * See issue #78 for changes to this (wip) - */ - -namespace ravi { - -// This is just to avoid initializing LLVM repeatedly - -// see below -static std::atomic_int init; - -static const char *errortext[] = {"integer expected", - "number expected", - "integer[] expected", - "number[] expected", - "table expected", - "upvalue of integer type, cannot be set to non integer value", - "upvalue of number type, cannot be set to non number value", - "upvalue of integer[] type, cannot be set to non integer[] value", - "upvalue of number[] type, cannot be set to non number[] value", - "upvalue of table type, cannot be set to non table value", - "for llimit must be a number", - "for step must be a number", - "for initial value must be a number", - "array index is out of bounds", - "string expected", - "closure expected", - "type mismatch: wrong userdata type", - NULL}; - -static struct { - const char *name; - void *address; -} global_syms[] = {{"lua_absindex", reinterpret_cast(lua_absindex)}, - {"lua_gettop", reinterpret_cast(lua_gettop)}, - {"lua_settop", reinterpret_cast(lua_settop)}, - {"lua_pushvalue", reinterpret_cast(lua_pushvalue)}, - {"lua_rotate", reinterpret_cast(lua_rotate)}, - {"lua_copy", reinterpret_cast(lua_copy)}, - {"lua_checkstack", reinterpret_cast(lua_checkstack)}, - {"lua_xmove", reinterpret_cast(lua_xmove)}, - {"lua_isnumber", reinterpret_cast(lua_isnumber)}, - {"lua_isstring", reinterpret_cast(lua_isstring)}, - {"lua_iscfunction", reinterpret_cast(lua_iscfunction)}, - {"lua_isinteger", reinterpret_cast(lua_isinteger)}, - {"lua_isuserdata", reinterpret_cast(lua_isuserdata)}, - {"lua_type", reinterpret_cast(lua_type)}, - {"lua_typename", reinterpret_cast(lua_typename)}, - {"lua_tonumberx", reinterpret_cast(lua_tonumberx)}, - {"lua_tointegerx", reinterpret_cast(lua_tointegerx)}, - {"lua_toboolean", reinterpret_cast(lua_toboolean)}, - {"lua_tolstring", reinterpret_cast(lua_tolstring)}, - {"lua_rawlen", reinterpret_cast(lua_rawlen)}, - {"lua_tocfunction", reinterpret_cast(lua_tocfunction)}, - {"lua_touserdata", reinterpret_cast(lua_touserdata)}, - {"lua_tothread", reinterpret_cast(lua_tothread)}, - {"lua_topointer", reinterpret_cast(lua_topointer)}, - {"lua_arith", reinterpret_cast(lua_arith)}, - {"lua_rawequal", reinterpret_cast(lua_rawequal)}, - {"lua_compare", reinterpret_cast(lua_compare)}, - {"lua_pushnil", reinterpret_cast(lua_pushnil)}, - {"lua_pushnumber", reinterpret_cast(lua_pushnumber)}, - {"lua_pushinteger", reinterpret_cast(lua_pushinteger)}, - {"lua_pushlstring", reinterpret_cast(lua_pushlstring)}, - {"lua_pushstring", reinterpret_cast(lua_pushstring)}, - {"lua_pushvfstring", reinterpret_cast(lua_pushvfstring)}, - {"lua_pushfstring", reinterpret_cast(lua_pushfstring)}, - {"lua_pushcclosure", reinterpret_cast(lua_pushcclosure)}, - {"lua_pushboolean", reinterpret_cast(lua_pushboolean)}, - {"lua_pushlightuserdata", reinterpret_cast(lua_pushlightuserdata)}, - {"lua_pushthread", reinterpret_cast(lua_pushthread)}, - {"lua_getglobal", reinterpret_cast(lua_getglobal)}, - {"lua_gettable", reinterpret_cast(lua_gettable)}, - {"lua_getfield", reinterpret_cast(lua_getfield)}, - {"lua_geti", reinterpret_cast(lua_geti)}, - {"lua_rawget", reinterpret_cast(lua_rawget)}, - {"lua_rawgeti", reinterpret_cast(lua_rawgeti)}, - {"lua_rawgetp", reinterpret_cast(lua_rawgetp)}, - {"lua_createtable", reinterpret_cast(lua_createtable)}, - {"lua_newuserdata", reinterpret_cast(lua_newuserdata)}, - {"lua_getmetatable", reinterpret_cast(lua_getmetatable)}, - {"lua_getuservalue", reinterpret_cast(lua_getuservalue)}, - {"lua_setglobal", reinterpret_cast(lua_setglobal)}, - {"lua_settable", reinterpret_cast(lua_settable)}, - {"lua_setfield", reinterpret_cast(lua_setfield)}, - {"lua_seti", reinterpret_cast(lua_seti)}, - {"lua_rawset", reinterpret_cast(lua_rawset)}, - {"lua_rawseti", reinterpret_cast(lua_rawseti)}, - {"lua_rawsetp", reinterpret_cast(lua_rawsetp)}, - {"lua_setmetatable", reinterpret_cast(lua_setmetatable)}, - {"lua_setuservalue", reinterpret_cast(lua_setuservalue)}, - {"lua_gc", reinterpret_cast(lua_gc)}, - {"lua_error", reinterpret_cast(lua_error)}, - {"lua_next", reinterpret_cast(lua_next)}, - {"lua_concat", reinterpret_cast(lua_concat)}, - {"lua_len", reinterpret_cast(lua_len)}, - {"lua_stringtonumber", reinterpret_cast(lua_stringtonumber)}, - {"luaC_upvalbarrier_", reinterpret_cast(luaC_upvalbarrier_)}, - {"luaD_call", reinterpret_cast(luaD_call)}, - {"luaD_poscall", reinterpret_cast(luaD_poscall)}, - {"luaD_precall", reinterpret_cast(luaD_precall)}, - {"luaF_close", reinterpret_cast(luaF_close)}, - {"luaG_runerror", reinterpret_cast(luaG_runerror)}, - {"luaH_getstr", reinterpret_cast(luaH_getstr)}, - {"luaO_arith", reinterpret_cast(luaO_arith)}, - {"luaT_trybinTM", reinterpret_cast(luaT_trybinTM)}, - {"luaV_tonumber_", reinterpret_cast(luaV_tonumber_)}, - {"luaV_tointeger", reinterpret_cast(luaV_tointeger)}, - {"luaV_tointeger_", reinterpret_cast(luaV_tointeger_)}, - {"luaV_equalobj", reinterpret_cast(luaV_equalobj)}, - {"luaV_lessthan", reinterpret_cast(luaV_lessthan)}, - {"luaV_lessequal", reinterpret_cast(luaV_lessequal)}, - {"luaV_execute", reinterpret_cast(luaV_execute)}, - {"luaV_gettable", reinterpret_cast(luaV_gettable)}, - {"luaV_settable", reinterpret_cast(luaV_settable)}, - {"luaV_objlen", reinterpret_cast(luaV_objlen)}, - {"luaV_forlimit", reinterpret_cast(luaV_forlimit)}, - {"luaV_finishget", reinterpret_cast(luaV_finishget)}, - {"luaV_mod", reinterpret_cast(luaV_mod)}, - {"luaV_idiv", reinterpret_cast(luaV_idiv)}, - {"raviV_op_newtable", reinterpret_cast(raviV_op_newtable)}, - {"raviV_op_newarrayint", reinterpret_cast(raviV_op_newarrayint)}, - {"raviV_op_newarrayfloat", reinterpret_cast(raviV_op_newarrayfloat)}, - {"raviV_op_setlist", reinterpret_cast(raviV_op_setlist)}, - {"raviV_op_concat", reinterpret_cast(raviV_op_concat)}, - {"raviV_op_closure", reinterpret_cast(raviV_op_closure)}, - {"raviV_op_vararg", reinterpret_cast(raviV_op_vararg)}, - {"raviV_op_setupval", reinterpret_cast(raviV_op_setupval)}, - {"raviV_op_setupvali", reinterpret_cast(raviV_op_setupvali)}, - {"raviV_op_setupvalf", reinterpret_cast(raviV_op_setupvalf)}, - {"raviV_op_setupvalai", reinterpret_cast(raviV_op_setupvalai)}, - {"raviV_op_setupvalaf", reinterpret_cast(raviV_op_setupvalaf)}, - {"raviV_op_setupvalt", reinterpret_cast(raviV_op_setupvalt)}, - {"raviH_set_int", reinterpret_cast(raviH_set_int)}, - {"raviH_set_float", reinterpret_cast(raviH_set_float)}, - {"raviV_check_usertype", reinterpret_cast(raviV_check_usertype)}, - {"raviV_gettable_sskey", reinterpret_cast(raviV_gettable_sskey)}, - {"raviV_settable_sskey", reinterpret_cast(raviV_settable_sskey)}, - {"raviV_gettable_i", reinterpret_cast(raviV_gettable_i)}, - {"raviV_settable_i", reinterpret_cast(raviV_settable_i)}, - {"raviV_op_add", reinterpret_cast(raviV_op_add)}, - {"raviV_op_mul", reinterpret_cast(raviV_op_mul)}, - {"raviV_op_sub", reinterpret_cast(raviV_op_sub)}, - {"raviV_op_div", reinterpret_cast(raviV_op_div)}, - {"raviV_op_shr", reinterpret_cast(raviV_op_shr)}, - {"raviV_op_shl", reinterpret_cast(raviV_op_shl)}, - {"raviV_op_bnot", reinterpret_cast(raviV_op_bnot)}, - {"raviV_op_band", reinterpret_cast(raviV_op_band)}, - {"raviV_op_bor", reinterpret_cast(raviV_op_bor)}, - {"raviV_op_bxor", reinterpret_cast(raviV_op_bxor)}, - {"raviV_op_totype", reinterpret_cast(raviV_op_totype)}, -#ifdef RAVI_DEFER_STATEMENT - {"raviV_op_defer", reinterpret_cast(raviV_op_defer)}, -#endif - {"raviV_debug_trace", reinterpret_cast(raviV_debug_trace)}, - {"raviV_raise_error", reinterpret_cast(raviV_raise_error)}, - {"printf", reinterpret_cast(printf)}, - {"puts", reinterpret_cast(puts)}, - {nullptr, nullptr}}; - -// Construct the JIT compiler state -// The JIT compiler state will be attached to the -// lua_State - all compilation activity happens -// in the context of the JIT State -RaviJITState::RaviJITState() - : auto_(false), - enabled_(true), - opt_level_(2), - size_level_(0), - verbosity_(0), - tracehook_enabled_(false), - validation_(false), - min_code_size_(150), - min_exec_count_(50), - allocated_modules_(0), - compiling_(false) -#if LLVM_VERSION_MAJOR >= 10 && USE_ORCv2_JIT - ,MainJD(nullptr) -#endif -{ - // LLVM needs to be initialized else - // ExecutionEngine cannot be created - // This needs to be an atomic check although LLVM docs - // say that it is okay to call these functions more than once - if (init == 0) { - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - llvm::InitializeNativeTargetAsmParser(); - // TODO see email trail on resolving symbols in process - llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); - init++; - } - triple_ = llvm::sys::getProcessTriple(); - -#if USE_ORCv2_JIT - auto JTMB = llvm::cantFail(llvm::orc::JITTargetMachineBuilder::detectHost()); - JTMB.setCodeGenOptLevel(llvm::CodeGenOpt::Default); - auto dataLayout = llvm::cantFail(JTMB.getDefaultDataLayoutForTarget()); - TM = llvm::cantFail(JTMB.createTargetMachine()); - ES = std::make_unique(); - ObjectLayer = std::make_unique( - *ES, []() { return std::make_unique(); }); -#if LLVM_VERSION_MAJOR < 10 - CompileLayer = std::make_unique(*ES, *ObjectLayer, llvm::orc::SimpleCompiler(*TM)); -#else -#ifndef _WIN32 - if (JTMB.getTargetTriple().isOSBinFormatCOFF()) -#endif - // Force on Win32 - ObjectLayer->setOverrideObjectFlagsWithResponsibilityFlags(true); - CompileLayer = std::make_unique(*ES, *ObjectLayer, std::make_unique(*TM)); -#endif - OptimizeLayer = std::make_unique( - *ES, *CompileLayer, [this](llvm::orc::ThreadSafeModule TSM, const llvm::orc::MaterializationResponsibility &R) { - return this->optimizeModule(std::move(TSM), R); - }); - DL = std::make_unique(std::move(dataLayout)); - Mangle = std::make_unique(*ES, *this->DL); - Ctx = std::make_unique(std::make_unique()); -#if LLVM_VERSION_MAJOR >= 10 - ES->createJITDylib("

"); - MainJD = ES->getJITDylibByName("
"); - MainJD->addGenerator( - cantFail(llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( - DL->getGlobalPrefix()))); -#elif 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_ = std::make_unique(*Ctx->getContext()); - -#else - -#if defined(_WIN32) && (!defined(_WIN64) || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7) - // On Windows we get compilation error saying incompatible object format - // Reading posts on mailing lists I found that the issue is that COEFF - // format is not supported and therefore we need to set -elf as the object - // format; LLVM 3.7 onwards COEFF is supported - triple_ += "-elf"; -#endif - context_ = std::unique_ptr(new llvm::LLVMContext()); - -#if USE_ORC_JIT - auto target = llvm::EngineBuilder().selectTarget(); - TM = std::unique_ptr(target); - TM->setO0WantsFastISel(true); // enable FastISel when -O0 is used - DL = std::unique_ptr(new llvm::DataLayout(TM->createDataLayout())); - -#if LLVM_VERSION_MAJOR >= 8 - StringPool = std::make_shared(); - ES = std::unique_ptr(new llvm::orc::ExecutionSession(StringPool)); - ObjectLayer = std::unique_ptr(new ObjectLayerT(*ES, [this](llvm::orc::VModuleKey K) { - return ObjectLayerT::Resources{std::make_shared(), Resolvers[K]}; - })); -#else - ObjectLayer = - std::unique_ptr(new ObjectLayerT([]() { return std::make_shared(); })); -#endif - - CompileLayer = std::unique_ptr(new CompileLayerT(*ObjectLayer, llvm::orc::SimpleCompiler(*TM))); - -#if LLVM_VERSION_MAJOR >= 8 - OptimizeLayer = std::unique_ptr(new OptimizerLayerT( - *CompileLayer, [this](std::unique_ptr M) { return optimizeModule(std::move(M)); })); - CompileCallbackManager = cantFail(llvm::orc::createLocalCompileCallbackManager(TM->getTargetTriple(), *ES, 0)); - CompileOnDemandLayer = std::unique_ptr(new CODLayerT( - *ES, *OptimizeLayer, [&](llvm::orc::VModuleKey K) { return Resolvers[K]; }, - [&](llvm::orc::VModuleKey K, std::shared_ptr R) { Resolvers[K] = std::move(R); }, - [](llvm::Function &F) { return std::set({&F}); }, *CompileCallbackManager, - llvm::orc::createLocalIndirectStubsManagerBuilder(TM->getTargetTriple()))); -#else - OptimizeLayer = std::unique_ptr(new OptimizerLayerT( - *CompileLayer, [this](std::shared_ptr M) { return optimizeModule(std::move(M)); })); -#endif - -#endif - - types_ = std::unique_ptr(new LuaLLVMTypes(*context_)); - -#endif // USE_ORCv2_JIT - - // Register global symbols -#if USE_ORCv2_JIT -#if LLVM_VERSION_MAJOR >= 10 - auto &JD = *MainJD; -#else - auto &JD = ES->getMainJITDylib(); -#endif - llvm::orc::MangleAndInterner mangle(*ES, *this->DL); - llvm::orc::SymbolMap Symbols; - for (int i = 0; global_syms[i].name != nullptr; i++) { - Symbols.insert({mangle(global_syms[i].name), - llvm::JITEvaluatedSymbol(llvm::pointerToJITTargetAddress(global_syms[i].address), - llvm::JITSymbolFlags(llvm::JITSymbolFlags::FlagNames::Absolute))}); - } - llvm::cantFail(JD.define(llvm::orc::absoluteSymbols(Symbols)), "Failed to install extern symbols"); -#else - for (int i = 0; global_syms[i].name != nullptr; i++) { - llvm::sys::DynamicLibrary::AddSymbol(global_syms[i].name, global_syms[i].address); - } -#endif -} - -// Destroy the JIT state freeing up any -// functions that were compiled -RaviJITState::~RaviJITState() { assert(allocated_modules_ == 0); } - -#if USE_ORC_JIT || USE_ORCv2_JIT -#if USE_ORCv2_JIT -llvm::Expected RaviJITState::optimizeModule( - llvm::orc::ThreadSafeModule TSM, const llvm::orc::MaterializationResponsibility &R) { -#else -#if LLVM_VERSION_MAJOR >= 8 -std::unique_ptr RaviJITState::optimizeModule(std::unique_ptr M) { -#else -std::shared_ptr RaviJITState::optimizeModule(std::shared_ptr M) { -#endif -#endif - using llvm::legacy::FunctionPassManager; - using llvm::legacy::PassManager; - -#if USE_ORCv2_JIT -#if LLVM_VERSION_MAJOR >= 10 - auto M = TSM.getModuleUnlocked(); -#else - auto M = TSM.getModule(); -#endif -#endif - if (get_verbosity() >= 1) - M->print(llvm::errs(), nullptr, false, true); - if (get_verbosity() >= 3) - TM->Options.PrintMachineCode = 1; - else - TM->Options.PrintMachineCode = 0; - if (get_optlevel() == 0) - TM->Options.EnableFastISel = 1; - else - TM->Options.EnableFastISel = 0; - - // We use the PassManagerBuilder to setup optimization - // passes - the PassManagerBuilder allows easy configuration of - // typical C/C++ passes corresponding to O0, O1, O2, and O3 compiler options - // If dumpAsm is true then the generated assembly code will be - // dumped to stderr - - llvm::PassManagerBuilder pmb; - - pmb.OptLevel = get_optlevel(); - pmb.SizeLevel = get_sizelevel(); - { - // Create a function pass manager for this engine - auto FPM = std::make_unique(&*M); - pmb.populateFunctionPassManager(*FPM); - FPM->doInitialization(); - // Run the optimizations over all functions in the module being added to - // the JIT. - // llvm::dbgs() << "Before optimization:\n" << *M << "-->\n"; - for (auto &F : *M) - FPM->run(F); - } - std::string codestr; - { - llvm::raw_string_ostream ostream(codestr); - llvm::buffer_ostream formatted_stream(ostream); - - std::unique_ptr MPM(new PassManager()); - pmb.populateModulePassManager(*MPM); - - for (int i = 0; get_verbosity() == 2 && i < 1; i++) { - if (!TM) { - llvm::errs() << "unable to dump assembly\n"; - break; - } - if (TM->addPassesToEmitFile(*MPM, formatted_stream, -#if LLVM_VERSION_MAJOR >= 7 - nullptr, // DWO output file -#endif -#if LLVM_VERSION_MAJOR < 10 - llvm::TargetMachine::CGFT_AssemblyFile -#else - llvm::CodeGenFileType::CGFT_AssemblyFile -#endif - )) { - llvm::errs() << "unable to add passes for generating assembly file\n"; - break; - } - } - MPM->run(*M); - // llvm::dbgs() << "After optimization:\n" << *M << "-->\n"; - } - if (get_verbosity() == 2 && codestr.length() > 0) - llvm::errs() << codestr << "\n"; - -#if USE_ORCv2_JIT - return TSM; -#else - return M; -#endif -} - -#endif - -void RaviJITState::addGlobalSymbol(const std::string &name, void *address) { - llvm::sys::DynamicLibrary::AddSymbol(name, address); -} - -#if USE_ORCv2_JIT -llvm::Error RaviJITState::addModule(std::unique_ptr M) { -#if LLVM_VERSION_MAJOR < 10 - return OptimizeLayer->add(ES->getMainJITDylib(), llvm::orc::ThreadSafeModule(std::move(M), *Ctx)); -#else - return OptimizeLayer->add(*MainJD, llvm::orc::ThreadSafeModule(std::move(M), *Ctx)); -#endif -} -#elif USE_ORC_JIT -RaviJITState::ModuleHandle RaviJITState::addModule(std::unique_ptr M) { -#if LLVM_VERSION_MAJOR >= 8 - // Create a new VModuleKey. - llvm::orc::VModuleKey K = ES->allocateVModule(); - // Build a resolver and associate it with the new key. - Resolvers[K] = - createLegacyLookupResolver(*ES, - [this](const std::string &Name) -> llvm::JITSymbol { - if (auto Sym = CompileLayer->findSymbol(Name, false)) - return Sym; - else if (auto Err = Sym.takeError()) - return std::move(Err); - if (auto SymAddr = llvm::RTDyldMemoryManager::getSymbolAddressInProcess(Name)) - return llvm::JITSymbol(SymAddr, llvm::JITSymbolFlags::Exported); - return nullptr; - }, - [](llvm::Error Err) { cantFail(std::move(Err), "lookupFlags failed"); }); - // Add the module to the JIT with the new key. - llvm::cantFail(CompileOnDemandLayer->addModule(K, std::move(M))); - return K; -#else - // Build our symbol resolver: - // Lambda 1: Look back into the JIT itself to find symbols that are part of - // the same "logical dylib". - // Lambda 2: Search for external symbols in the host process. - auto Resolver = llvm::orc::createLambdaResolver( - [&](const std::string &Name) { - if (auto Sym = OptimizeLayer->findSymbol(Name, false)) - return Sym; - return llvm::JITSymbol(nullptr); - }, - [](const std::string &Name) { - if (auto SymAddr = llvm::RTDyldMemoryManager::getSymbolAddressInProcess(Name)) - return llvm::JITSymbol(SymAddr, llvm::JITSymbolFlags::Exported); - return llvm::JITSymbol(nullptr); - }); - - // Add the set to the JIT with the resolver we created above and a newly - // created SectionMemoryManager. - return llvm::cantFail(OptimizeLayer->addModule(std::move(M), std::move(Resolver))); -#endif -} - -llvm::JITSymbol RaviJITState::findSymbol(const std::string &Name) { - std::string MangledName; - llvm::raw_string_ostream MangledNameStream(MangledName); - llvm::Mangler::getNameWithPrefix(MangledNameStream, Name, *DL); -#if LLVM_VERSION_MAJOR >= 8 - return CompileOnDemandLayer->findSymbol(MangledNameStream.str(), false); -#else - // Note that the LLVM tutorial uses true below but that appears to - // cause a failure in lookup - return OptimizeLayer->findSymbol(MangledNameStream.str(), false); -#endif -} - -void RaviJITState::removeModule(ModuleHandle H) { -#if LLVM_VERSION_MAJOR >= 8 - if (H) { - llvm::cantFail(CompileOnDemandLayer->removeModule(H)); - } -#else - llvm::cantFail(OptimizeLayer->removeModule(H)); -#endif -} -#endif - -void RaviJITState::dump() { types_->dump(); } - -static std::atomic_int module_id; - -RaviJITModule::RaviJITModule(RaviJITState *owner) - : owner_(owner) -#if !USE_ORC_JIT - , - module_(nullptr), - engine_(nullptr) -#elif !USE_ORCv2_JIT - , - module_handle_(0) -#endif -{ - int myid = module_id++; - char buf[40]; - snprintf(buf, sizeof buf, "ravi_module_%d", myid); - std::string moduleName(buf); -#if USE_ORCv2_JIT - module_ = std::unique_ptr(new llvm::Module(moduleName, owner->context())); - module_->setDataLayout(owner_->getDataLayout()); -#elif USE_ORC_JIT - module_ = std::unique_ptr(new llvm::Module(moduleName, owner->context())); - module_->setDataLayout(owner_->getTargetMachine().createDataLayout()); -#else - module_ = new llvm::Module(moduleName, owner->context()); -#endif - if (myid == 0) { - // Extra validation to check that the LLVM sizes match Lua sizes - auto layout = std::unique_ptr(new llvm::DataLayout(module())); - // auto valueSize = layout->getTypeAllocSize(owner->types()->ValueT); - // auto valueSizeOf = sizeof(Value); - // auto TvalueSize = layout->getTypeAllocSize(owner->types()->TValueT); - // auto TvalueSizeOf = sizeof(TValue); - // printf("Value %d %d Tvalue %d %d\n", (int)valueSize, (int)valueSizeOf, - // (int)TvalueSize, (int)TvalueSizeOf); - assert(sizeof(Value) == layout->getTypeAllocSize(owner->types()->ValueT)); - assert(sizeof(TValue) == layout->getTypeAllocSize(owner->types()->TValueT)); - assert(sizeof(UTString) == layout->getTypeAllocSize(owner->types()->TStringT)); - assert(sizeof(Udata) == layout->getTypeAllocSize(owner->types()->UdataT)); - assert(sizeof(CallInfo) == layout->getTypeAllocSize(owner->types()->CallInfoT)); - assert(sizeof(lua_State) == layout->getTypeAllocSize(owner->types()->lua_StateT)); - } -#if !USE_ORC_JIT -#if defined(_WIN32) && (!defined(_WIN64) || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7) - // On Windows we get error saying incompatible object format - // Reading posts on mailing lists I found that the issue is that COEFF - // format is not supported and therefore we need to set - // -elf as the object format; LLVM 3.7 onwards COEFF is supported - module_->setTargetTriple(owner->triple()); -#endif -#if LLVM_VERSION_MAJOR > 3 || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 5 - // LLVM 3.6.0 change - std::unique_ptr module(module_); - llvm::EngineBuilder builder(std::move(module)); -#else - llvm::EngineBuilder builder(module_); - builder.setUseMCJIT(true); -#endif - builder.setEngineKind(llvm::EngineKind::JIT); - std::string errStr; - builder.setErrorStr(&errStr); - engine_ = builder.create(); - if (!engine_) { - fprintf(stderr, "FATAL ERROR: could not create ExecutionEngine: %s\n", errStr.c_str()); - abort(); - return; - } -#endif - owner->incr_allocated_modules(); -} - -RaviJITModule::~RaviJITModule() { -#if !USE_ORC_JIT - if (engine_) - delete engine_; - else if (module_) - // if engine was created then we don't need to delete the - // module as it would have been deleted by the engine - delete module_; -#elif !USE_ORCv2_JIT - owner()->removeModule(module_handle_); -#endif - owner_->decr_allocated_modules(); -#if 1 - // fprintf(stderr, "module destroyed\n"); -#endif -} - -int RaviJITModule::addFunction(RaviJITFunction *f) { - int id = functions_.size(); - functions_.push_back(f); - return id; -} - -void RaviJITModule::removeFunction(RaviJITFunction *f) { - lua_assert(functions_[f->getId()] == f); - functions_[f->getId()] = nullptr; -} - -RaviJITFunction::RaviJITFunction(lua_CFunction *p, const std::shared_ptr &module, - llvm::FunctionType *type, llvm::GlobalValue::LinkageTypes linkage, - const std::string &name) - : module_(module), name_(name), function_(nullptr), ptr_(nullptr), func_ptrptr_(p) { - auto M = module_->module(); - lua_assert(M); - function_ = llvm::Function::Create(type, linkage, name, M); - id_ = module_->addFunction(this); -} - -RaviJITFunction::RaviJITFunction(lua_CFunction *p, const std::shared_ptr &module, - const std::string &name) - : module_(module), name_(name), ptr_(nullptr), func_ptrptr_(p) { - auto M = module_->module(); - lua_assert(M); - function_ = M->getFunction(name); - id_ = module_->addFunction(this); -} - -RaviJITFunction::~RaviJITFunction() { - // Remove this function from parent - // fprintf(stderr, "function destroyed\n"); - module_->removeFunction(this); -} - -// This is noop when ORC api is enabled -// Retained for backward compatibility -void RaviJITModule::runpasses(bool dumpAsm) { -#if !USE_ORC_JIT - if (!module_) - return; - -#if LLVM_VERSION_MAJOR > 3 || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7 - using llvm::legacy::FunctionPassManager; - using llvm::legacy::PassManager; -#else - using llvm::FunctionPassManager; - using llvm::PassManager; -#endif - - // We use the PassManagerBuilder to setup optimization - // passes - the PassManagerBuilder allows easy configuration of - // typical C/C++ passes corresponding to O0, O1, O2, and O3 compiler options - // If dumpAsm is true then the generated assembly code will be - // dumped to stderr - - llvm::PassManagerBuilder pmb; - pmb.OptLevel = owner_->get_optlevel(); - pmb.SizeLevel = owner_->get_sizelevel(); - - { - // Create a function pass manager for this engine - std::unique_ptr FPM(new FunctionPassManager(module_)); - -// Set up the optimizer pipeline. Start with registering info about how the -// target lays out data structures. -#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR == 6 - // LLVM 3.6.0 change - module_->setDataLayout(engine_->getDataLayout()); - FPM->add(new llvm::DataLayoutPass()); -#elif LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR == 5 - // LLVM 3.5.0 - auto target_layout = engine_->getTargetMachine()->getDataLayout(); - module_->setDataLayout(target_layout); - FPM->add(new llvm::DataLayoutPass(*engine_->getDataLayout())); -#elif LLVM_VERSION_MAJOR > 3 || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7 -// Apparently no need to set DataLayout -#else -#error Unsupported LLVM version -#endif - pmb.populateFunctionPassManager(*FPM); - FPM->doInitialization(); - for (int i = 0; i < functions_.size(); i++) { - if (functions_[i] == nullptr) - continue; - FPM->run(*functions_[i]->function()); - } - } - - std::string codestr; - { - // In LLVM 3.7 for some reason the string is not saved - // until the stream is destroyed - even though there is a - // flush; so we introduce a scope here to ensure destruction - // of the stream - llvm::raw_string_ostream ostream(codestr); -#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7 - llvm::formatted_raw_ostream formatted_stream(ostream); -#else - llvm::buffer_ostream formatted_stream(ostream); -#endif - - // Also in 3.7 the pass manager seems to hold on to the stream - // so we need to ensure that the stream outlives the pass manager - std::unique_ptr MPM(new PassManager()); -#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR == 6 - MPM->add(new llvm::DataLayoutPass()); -#elif LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR == 5 - MPM->add(new llvm::DataLayoutPass(*engine_->getDataLayout())); -#endif - pmb.populateModulePassManager(*MPM); - - for (int i = 0; dumpAsm && i < 1; i++) { - llvm::TargetMachine *TM = engine_->getTargetMachine(); - if (!TM) { - llvm::errs() << "unable to dump assembly\n"; - break; - } - if (TM->addPassesToEmitFile(*MPM, formatted_stream, -#if LLVM_VERSION_MAJOR >= 7 - nullptr, // DWO output file -#endif - llvm::TargetMachine::CGFT_AssemblyFile)) { - llvm::errs() << "unable to add passes for generating assemblyfile\n"; - break; - } - } - MPM->run(*module_); - -// Note that in 3.7 this flus appears to have no effect -#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR <= 7 - formatted_stream.flush(); -#endif - } - if (dumpAsm && codestr.length() > 0) - llvm::errs() << codestr << "\n"; -#endif -} - -void RaviJITModule::finalize(bool doDump) { - lua_assert(module_); - if (!module_) - return; -#if !USE_ORC_JIT - // Following will generate very verbose dump when machine code is - // produced below - llvm::TargetMachine *TM = engine_->getTargetMachine(); - // TM->setOptLevel(llvm::CodeGenOpt::None); - if (doDump) { - TM->Options.PrintMachineCode = 1; - } - - // Upon creation, MCJIT holds a pointer to the Module object - // that it received from EngineBuilder but it does not immediately - // generate code for this module. Code generation is deferred - // until either the MCJIT::finalizeObject method is called - // explicitly or a function such as MCJIT::getPointerToFunction - // is called which requires the code to have been generated. - engine_->finalizeObject(); -#elif !USE_ORCv2_JIT - // With ORC api, the module gets compiled when it is added - // The optimization passes are run via the callback - module_handle_ = owner()->addModule(std::move(module_)); -#else - llvm::cantFail(owner()->addModule(std::move(module_))); -#endif - for (int i = 0; i < functions_.size(); i++) { - if (functions_[i] == nullptr) - continue; - functions_[i]->setFunctionPtr(); - } -} - -// Retrieve the JITed function from the -// execution engine and store it in ptr_ -// Also associate the JITed function with the -// Lua Proto structure -void RaviJITFunction::setFunctionPtr() { - lua_assert(ptr_ == nullptr); - // function_ may be nullptr if it was obtained by name from the module, so - // we need to check that -#if !USE_ORC_JIT - if (function_) { - ptr_ = engine()->getPointerToFunction(function_); - *func_ptrptr_ = (lua_CFunction)ptr_; - } -#else - if (function_) { - auto symbol = owner()->findSymbol(name()); - if (symbol) { -#if USE_ORCv2_JIT - ptr_ = (void *)(intptr_t)(symbol->getAddress()); -#else - ptr_ = (void *)(intptr_t)llvm::cantFail(symbol.getAddress()); -#endif - *func_ptrptr_ = (lua_CFunction)ptr_; - } - } -#endif -} - -llvm::Function *RaviJITModule::addExternFunction(llvm::FunctionType *type, void *address, const std::string &name) { - auto fn = external_symbols_.find(name); - if (fn != external_symbols_.end()) - return fn->second; - llvm::Function *f = llvm::Function::Create(type, llvm::Function::ExternalLinkage, name, module()); - f->setDoesNotThrow(); - // We should have been able to call - // engine_->addGlobalMapping() but this doesn't work - // See http://lists.cs.uiuc.edu/pipermail/llvmdev/2014-April/071856.html - // See bug report http://llvm.org/bugs/show_bug.cgi?id=20656 - // following will call DynamicLibrary::AddSymbol - owner_->addGlobalSymbol(name, address); - external_symbols_[name] = f; - return f; -} - -void RaviJITModule::dump() { -#if LLVM_VERSION_MAJOR < 5 - if (module_) - module_->dump(); -#endif -} - -// Dumps the machine code -// Will execute the passes as required by currently set -// optimization level; this may or may not match the actual -// JITed code which would have used the optimzation level set at the -// time of compilation -void RaviJITModule::dumpAssembly() { runpasses(true); } - -std::unique_ptr RaviJITStateFactory::newJITState() { - return std::unique_ptr(new RaviJITState()); -} -} // namespace ravi - -// Initialize the JIT State and attach it to the -// Global Lua State -// If a JIT State already exists then this function -// will return -1 -int raviV_initjit(struct lua_State *L) { - global_State *G = G(L); - if (G->ravi_state != NULL) - return -1; - ravi_State *jit = (ravi_State *)calloc(1, sizeof(ravi_State)); - jit->jit = new ravi::RaviJITState(); - jit->code_generator = new ravi::RaviCodeGenerator((ravi::RaviJITState *)jit->jit); - G->ravi_state = jit; - return 0; -} - -// Free up the JIT State -void raviV_close(struct lua_State *L) { - global_State *G = G(L); - if (G->ravi_state == NULL) - return; - delete G->ravi_state->code_generator; - delete G->ravi_state->jit; - free(G->ravi_state); -} - -// Compile a Lua function -// If JIT is turned off then compilation is skipped -// Compilation occurs if either auto compilation is ON (subject to some -// thresholds) -// or if a manual compilation request was made -// Returns true if compilation was successful -int raviV_compile(struct lua_State *L, struct Proto *p, ravi_compile_options_t *options) { - if (p->ravi_jit.jit_function) - return 1; - global_State *G = G(L); - if (G->ravi_state == NULL) - return 0; - if (!G->ravi_state->jit->is_enabled()) { - return 0; - } - if (G->ravi_state->jit->get_compiling_flag()) { - return 0; - } - bool doCompile = (bool)(options && options->manual_request != 0); - if (!doCompile && G->ravi_state->jit->is_auto()) { - if (p->ravi_jit.jit_flags == RAVI_JIT_FLAG_HASFORLOOP) /* function has fornum loop, so compile */ - doCompile = true; - else if (p->sizecode > G->ravi_state->jit->get_mincodesize()) /* function is long so compile */ - doCompile = true; - else { - if (p->ravi_jit.execution_count < G->ravi_state->jit->get_minexeccount()) /* function has been executed many - times so compile */ - p->ravi_jit.execution_count++; - else - doCompile = true; - } - } - if (doCompile) { - auto module = std::make_shared(G->ravi_state->jit); - if (G->ravi_state->code_generator->compile(L, p, module, options)) { - module->runpasses(); - module->finalize(G->ravi_state->jit->get_verbosity() == 3); - } - } - return p->ravi_jit.jit_function != nullptr; -} - -// Compile a bunch of Lua functions -// And put them all in one module -// Returns true if compilation was successful -int raviV_compile_n(struct lua_State *L, struct Proto *p[], int n, ravi_compile_options_t *options) { - global_State *G = G(L); - int count = 0; - if (G->ravi_state->jit->get_compiling_flag()) - return 0; - auto module = std::make_shared(G->ravi_state->jit); - for (int i = 0; i < n; i++) { - if (G->ravi_state->code_generator->compile(L, p[i], module, options)) - count++; - } - if (count) { - module->runpasses(); - module->finalize(G->ravi_state->jit->get_verbosity() == 3); - } - return count > 0; -} - -// Free the JIT compiled function -// Note that this is called by the garbage collector -void raviV_freeproto(struct lua_State *L, struct Proto *p) { - ravi::RaviJITFunction *f = reinterpret_cast(p->ravi_jit.jit_data); - if (f) - delete f; - p->ravi_jit.jit_status = RAVI_JIT_NOT_COMPILED; - p->ravi_jit.jit_function = NULL; - p->ravi_jit.jit_data = NULL; - p->ravi_jit.execution_count = 0; -} - -// Dump the LLVM IR -void raviV_dumpIR(struct lua_State *L, struct Proto *p) { - if (p->ravi_jit.jit_status == RAVI_JIT_COMPILED) /* compiled */ { - ravi::RaviJITFunction *f = reinterpret_cast(p->ravi_jit.jit_data); - if (f) - f->dump(); - } -} - -// Dump the LLVM ASM -void raviV_dumpASM(struct lua_State *L, struct Proto *p) { - if (p->ravi_jit.jit_status == RAVI_JIT_COMPILED) /* compiled */ { - ravi::RaviJITFunction *f = reinterpret_cast(p->ravi_jit.jit_data); - if (f) - f->dumpAssembly(); - } -} - -void raviV_setminexeccount(lua_State *L, int value) { - global_State *G = G(L); - if (!G->ravi_state) - return; - G->ravi_state->jit->set_minexeccount(value); -} -int raviV_getminexeccount(lua_State *L) { - global_State *G = G(L); - if (!G->ravi_state) - return 0; - return G->ravi_state->jit->get_minexeccount(); -} - -void raviV_setmincodesize(lua_State *L, int value) { - global_State *G = G(L); - if (!G->ravi_state) - return; - G->ravi_state->jit->set_mincodesize(value); -} -int raviV_getmincodesize(lua_State *L) { - global_State *G = G(L); - if (!G->ravi_state) - return 0; - return G->ravi_state->jit->get_mincodesize(); -} - -void raviV_setauto(lua_State *L, int value) { - global_State *G = G(L); - if (!G->ravi_state) - return; - G->ravi_state->jit->set_auto(value != 0); -} -int raviV_getauto(lua_State *L) { - global_State *G = G(L); - if (!G->ravi_state) - return 0; - return G->ravi_state->jit->is_auto(); -} - -// Turn on/off the JIT compiler -void raviV_setjitenabled(lua_State *L, int value) { - global_State *G = G(L); - if (!G->ravi_state) - return; - G->ravi_state->jit->set_enabled(value != 0); -} -int raviV_getjitenabled(lua_State *L) { - global_State *G = G(L); - if (!G->ravi_state) - return 0; - return G->ravi_state->jit->is_enabled(); -} - -void raviV_setoptlevel(lua_State *L, int value) { - global_State *G = G(L); - if (!G->ravi_state) - return; - G->ravi_state->jit->set_optlevel(value); -} -int raviV_getoptlevel(lua_State *L) { - global_State *G = G(L); - if (!G->ravi_state) - return 0; - return G->ravi_state->jit->get_optlevel(); -} - -void raviV_setsizelevel(lua_State *L, int value) { - global_State *G = G(L); - if (!G->ravi_state) - return; - G->ravi_state->jit->set_sizelevel(value); -} -int raviV_getsizelevel(lua_State *L) { - global_State *G = G(L); - if (!G->ravi_state) - return 0; - return G->ravi_state->jit->get_sizelevel(); -} - -void raviV_setverbosity(lua_State *L, int value) { - global_State *G = G(L); - if (!G->ravi_state) - return; - G->ravi_state->jit->set_verbosity(value); -} -int raviV_getverbosity(lua_State *L) { - global_State *G = G(L); - if (!G->ravi_state) - return 0; - return G->ravi_state->jit->get_verbosity(); -} - -void raviV_setvalidation(lua_State *L, int value) { - global_State *G = G(L); - if (!G->ravi_state) - return; - G->ravi_state->jit->set_validation(value != 0); -} -int raviV_getvalidation(lua_State *L) { - global_State *G = G(L); - if (!G->ravi_state) - return 0; - return G->ravi_state->jit->get_validation(); -} - - -// Turn on/off the JIT compiler -void raviV_settraceenabled(lua_State *L, int value) { - global_State *G = G(L); - if (!G->ravi_state) - return; - G->ravi_state->jit->set_tracehook_enabled(value != 0); -} -int raviV_gettraceenabled(lua_State *L) { - global_State *G = G(L); - if (!G->ravi_state) - return 0; - return G->ravi_state->jit->is_tracehook_enabled(); -} - -extern "C" int ravi_compile_C(lua_State *L) { return 0; } - -const char *raviV_jit_id(struct lua_State *L) { - return "llvm"; -} - -#define ravi_xstringify(s) ravi_stringify(s) -#define ravi_stringify(s) #s -#define RAVI_OPTION_STRING3 "LLVM-" LLVM_VERSION_STRING " ORC=" ravi_xstringify(USE_ORC_JIT) " v2=" ravi_xstringify(USE_ORCv2_JIT) -#define RAVI_OPTIONS RAVI_OPTION_STRING1 RAVI_OPTION_STRING2 RAVI_OPTION_STRING3 - -const char *raviV_options(struct lua_State *L) { - return RAVI_OPTIONS; -} - diff --git a/src/ravi_llvmload.cpp b/src/ravi_llvmload.cpp deleted file mode 100644 index 3363799..0000000 --- a/src/ravi_llvmload.cpp +++ /dev/null @@ -1,492 +0,0 @@ -/****************************************************************************** -* 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. -******************************************************************************/ -#include "ravi_llvmcodegen.h" - -namespace ravi { - -// R(A+1), ..., R(A+B) := nil -void RaviCodeGenerator::emit_LOADNIL(RaviFunctionDef *def, int A, int B, - int pc) { - emit_debug_trace(def, OP_LOADNIL, pc); -#if 1 - // Inline version, we unroll the loop - emit_load_base(def); - do { - llvm::Value *dest = emit_gep_register(def, A); - emit_store_type_(def, dest, LUA_TNIL); - A++; - } while (B--); -#else - CreateCall3(def->builder, def->raviV_op_loadnilF, def->ci_val, - llvm::ConstantInt::get(def->types->C_intT, A), - llvm::ConstantInt::get(def->types->C_intT, B)); -#endif -} - -// R(A) := tonumber(0) -void RaviCodeGenerator::emit_LOADFZ(RaviFunctionDef *def, int A, int pc) { - emit_debug_trace(def, OP_RAVI_LOADFZ, pc); - emit_load_base(def); - llvm::Value *dest = emit_gep_register(def, A); - // destvalue->n = 0.0 - emit_store_reg_n_withtype( - def, llvm::ConstantFP::get(def->types->lua_NumberT, 0.0), dest); -} - -// R(A) := tointeger(0) -void RaviCodeGenerator::emit_LOADIZ(RaviFunctionDef *def, int A, int pc) { - emit_debug_trace(def, OP_RAVI_LOADIZ, pc); - emit_load_base(def); - llvm::Value *dest = emit_gep_register(def, A); - // dest->i = 0 - emit_store_reg_i_withtype(def, def->types->kluaInteger[0], dest); -} - -// R(A) := (Bool)B; if (C) pc++ -void RaviCodeGenerator::emit_LOADBOOL(RaviFunctionDef *def, int A, int B, int C, - int j, int pc) { - // setbvalue(ra, GETARG_B(i)); - // if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */ - - emit_debug_trace(def, OP_LOADBOOL, pc); - emit_load_base(def); - llvm::Value *dest = emit_gep_register(def, A); - // dest->i = 0 - emit_store_reg_b_withtype(def, llvm::ConstantInt::get(def->types->C_intT, B), - dest); - if (C) { - // Skip next instruction if C - def->builder->CreateBr(def->jmp_targets[j].jmp1); - llvm::BasicBlock *block = - llvm::BasicBlock::Create(def->jitState->context(), "nextblock", def->f); - def->builder->SetInsertPoint(block); - } -} - -// R(A) := R(B) -void RaviCodeGenerator::emit_MOVE(RaviFunctionDef *def, int A, int B, int pc) { - // setobjs2s(L, ra, RB(i)); - - emit_debug_trace(def, OP_MOVE, pc); - // Load pointer to base - emit_load_base(def); - - lua_assert(A != B); - - llvm::Value *src = emit_gep_register(def, B); - llvm::Value *dest = emit_gep_register(def, A); - emit_assign(def, dest, src); -} - -// R(A) := R(B), check R(B) is int -void RaviCodeGenerator::emit_MOVEI(RaviFunctionDef *def, int A, int B, int pc) { - // TValue *rb = RB(i); - // lua_Integer j; - // if (tointeger(rb, &j)) { - // setivalue(ra, j); - // } - // else - // luaG_runerror(L, "integer expected"); - - llvm::IRBuilder<> TmpB(def->entry, def->entry->begin()); - llvm::Value *var = TmpB.CreateAlloca(def->types->lua_IntegerT, nullptr, "i"); - - emit_debug_trace(def, OP_RAVI_MOVEI, pc); - // Load pointer to base - emit_load_base(def); - - llvm::Value *dest = emit_gep_register(def, A); - llvm::Value *src = emit_gep_register(def, B); - - llvm::Value *src_type = emit_load_type(def, src); - - // Compare src->tt == LUA_TNUMINT - llvm::Value *cmp1 = - emit_is_value_of_type(def, src_type, LUA__TNUMINT, "is.src.integer"); - - llvm::BasicBlock *then1 = - llvm::BasicBlock::Create(def->jitState->context(), "if.integer", def->f); - llvm::BasicBlock *else1 = - llvm::BasicBlock::Create(def->jitState->context(), "if.not.integer"); - llvm::BasicBlock *end1 = - llvm::BasicBlock::Create(def->jitState->context(), "done"); - - def->builder->CreateCondBr(cmp1, then1, else1); - def->builder->SetInsertPoint(then1); - - // Already a int - move - llvm::Instruction *tmp = emit_load_reg_i(def, src); - emit_store_local_n(def, tmp, var); - def->builder->CreateBr(end1); - - // we need to convert - def->f->getBasicBlockList().push_back(else1); - def->builder->SetInsertPoint(else1); - // Call luaV_tointeger_() - - llvm::Value *var_isint = - CreateCall2(def->builder, def->luaV_tointegerF, src, var); - llvm::Value *tobool = def->builder->CreateICmpEQ( - var_isint, def->types->kInt[0], "int.conversion.failed"); - - // Did conversion fail? - llvm::BasicBlock *else2 = llvm::BasicBlock::Create( - def->jitState->context(), "if.conversion.failed", def->f); - def->builder->CreateCondBr(tobool, else2, end1); - - // Conversion failed, so raise error - def->builder->SetInsertPoint(else2); - emit_raise_lua_error(def, "integer expected"); - def->builder->CreateBr(end1); - - // Conversion OK - def->f->getBasicBlockList().push_back(end1); - def->builder->SetInsertPoint(end1); - - auto load_var = emit_load_local_n(def, var); - emit_store_reg_i_withtype(def, load_var, dest); -} - -void RaviCodeGenerator::emit_MOVEF(RaviFunctionDef *def, int A, int B, int pc) { - // case OP_RAVI_MOVEF: { - // TValue *rb = RB(i); - // lua_Number j; - // if (tonumber(rb, &j)) { - // setfltvalue(ra, j); - // } - // else - // luaG_runerror(L, "float expected"); - // } break; - - llvm::IRBuilder<> TmpB(def->entry, def->entry->begin()); - llvm::Value *var = TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "n"); - - emit_debug_trace(def, OP_RAVI_MOVEF, pc); - // Load pointer to base - emit_load_base(def); - - llvm::Value *dest = emit_gep_register(def, A); - llvm::Value *src = emit_gep_register(def, B); - - llvm::Value *src_type = emit_load_type(def, src); - - // Compare src->tt == LUA_TNUMFLT - llvm::Value *cmp1 = - emit_is_value_of_type(def, src_type, LUA__TNUMFLT, "is.src.float"); - - llvm::BasicBlock *then1 = - llvm::BasicBlock::Create(def->jitState->context(), "if.float", def->f); - llvm::BasicBlock *else1 = - llvm::BasicBlock::Create(def->jitState->context(), "if.not.float"); - llvm::BasicBlock *end1 = - llvm::BasicBlock::Create(def->jitState->context(), "done"); - - def->builder->CreateCondBr(cmp1, then1, else1); - def->builder->SetInsertPoint(then1); - - // Already a float - copy to var - llvm::Instruction *tmp = emit_load_reg_n(def, src); - emit_store_local_n(def, tmp, var); - def->builder->CreateBr(end1); - - // we need to convert - def->f->getBasicBlockList().push_back(else1); - def->builder->SetInsertPoint(else1); - // Call luaV_tonumber() - - llvm::Value *var_isflt = - CreateCall2(def->builder, def->luaV_tonumberF, src, var); - llvm::Value *tobool = def->builder->CreateICmpEQ( - var_isflt, def->types->kInt[0], "float.conversion.failed"); - - // Did conversion fail? - llvm::BasicBlock *else2 = llvm::BasicBlock::Create( - def->jitState->context(), "if.conversion.failed", def->f); - def->builder->CreateCondBr(tobool, else2, end1); - - // Conversion failed, so raise error - def->builder->SetInsertPoint(else2); - emit_raise_lua_error(def, "number expected"); - def->builder->CreateBr(end1); - - // Conversion OK - def->f->getBasicBlockList().push_back(end1); - def->builder->SetInsertPoint(end1); - - // Set R(A) - auto load_var = emit_load_local_n(def, var); - emit_store_reg_n_withtype(def, load_var, dest); -} - -void RaviCodeGenerator::emit_TOSTRING(RaviFunctionDef *def, int A, int pc) { - emit_debug_trace(def, OP_RAVI_TOSTRING, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Instruction *type = emit_load_type(def, ra); - llvm::Value *isnotnil = emit_is_not_value_of_type(def, type, LUA__TNIL); - // check if string type - llvm::Value *cmp1 = emit_is_not_value_of_type_class(def, type, LUA_TSTRING); - cmp1 = def->builder->CreateAnd(isnotnil, cmp1, "OP_RAVI_TOSTRING_is.not.expected.type"); - llvm::BasicBlock *raise_error = llvm::BasicBlock::Create( - def->jitState->context(), "OP_RAVI_TOSTRING_if.not.expected_type", def->f); - llvm::BasicBlock *done = - llvm::BasicBlock::Create(def->jitState->context(), "OP_RAVI_TOSTRING_done"); - auto brinst1 = def->builder->CreateCondBr(cmp1, raise_error, done); - attach_branch_weights(def, brinst1, 0, 100); - def->builder->SetInsertPoint(raise_error); - - // Conversion failed, so raise error - emit_raise_lua_error(def, "string expected"); - def->builder->CreateBr(done); - - def->f->getBasicBlockList().push_back(done); - def->builder->SetInsertPoint(done); -} - -void RaviCodeGenerator::emit_TOCLOSURE(RaviFunctionDef *def, int A, int pc) { - emit_debug_trace(def, OP_RAVI_TOCLOSURE, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Instruction *type = emit_load_type(def, ra); - llvm::Value *isnotnil = emit_is_not_value_of_type(def, type, LUA__TNIL); - // check if function type - llvm::Value *cmp1 = emit_is_not_value_of_type_class( - def, type, LUA_TFUNCTION); - cmp1 = def->builder->CreateAnd(isnotnil, cmp1, "OP_RAVI_TOCLOSURE_is.not.expected.type"); - llvm::BasicBlock *raise_error = llvm::BasicBlock::Create( - def->jitState->context(), "OP_RAVI_TOCLOSURE_if.not.expected_type", - def->f); - llvm::BasicBlock *done = llvm::BasicBlock::Create(def->jitState->context(), - "OP_RAVI_TOCLOSURE_done"); - auto brinst1 = def->builder->CreateCondBr(cmp1, raise_error, done); - attach_branch_weights(def, brinst1, 0, 100); - def->builder->SetInsertPoint(raise_error); - - // Conversion failed, so raise error - emit_raise_lua_error(def, "closure expected"); - def->builder->CreateBr(done); - - def->f->getBasicBlockList().push_back(done); - def->builder->SetInsertPoint(done); -} - -void RaviCodeGenerator::emit_TOTYPE(RaviFunctionDef *def, int A, int Bx, - int pc) { - emit_debug_trace(def, OP_RAVI_TOTYPE, pc); - // Load pointer to base - emit_load_base(def); - - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_constant(def, Bx); - CreateCall3(def->builder, def->raviV_op_totypeF, def->L, ra, rb); -} - -void RaviCodeGenerator::emit_TOINT(RaviFunctionDef *def, int A, int pc) { - // case OP_RAVI_TOINT: { - // lua_Integer j; - // if (tointeger(ra, &j)) { - // setivalue(ra, j); - // } - // else - // luaG_runerror(L, "integer expected"); - // } break; - - llvm::IRBuilder<> TmpB(def->entry, def->entry->begin()); - llvm::Value *var = TmpB.CreateAlloca(def->types->lua_IntegerT, nullptr, "i"); - - emit_debug_trace(def, OP_RAVI_TOINT, pc); - // Load pointer to base - emit_load_base(def); - - llvm::Value *dest = emit_gep_register(def, A); - llvm::Value *src = dest; - - llvm::Value *src_type = emit_load_type(def, src); - - // Is src->tt != LUA_TNUMINT? - llvm::Value *cmp1 = - emit_is_not_value_of_type(def, src_type, LUA__TNUMINT, "is.not.integer"); - - llvm::BasicBlock *then1 = llvm::BasicBlock::Create(def->jitState->context(), - "if.not.integer", def->f); - llvm::BasicBlock *end1 = - llvm::BasicBlock::Create(def->jitState->context(), "done"); - def->builder->CreateCondBr(cmp1, then1, end1); - def->builder->SetInsertPoint(then1); - - // Call luaV_tointeger_() - llvm::Value *var_isint = - CreateCall2(def->builder, def->luaV_tointegerF, src, var); - llvm::Value *tobool = def->builder->CreateICmpEQ( - var_isint, def->types->kInt[0], "int.conversion.failed"); - - // Did conversion fail? - llvm::BasicBlock *then2 = llvm::BasicBlock::Create( - def->jitState->context(), "if.conversion.failed", def->f); - llvm::BasicBlock *else2 = - llvm::BasicBlock::Create(def->jitState->context(), "conversion.ok"); - def->builder->CreateCondBr(tobool, then2, else2); - def->builder->SetInsertPoint(then2); - - // Conversion failed, so raise error - emit_raise_lua_error(def, "integer expected"); - def->builder->CreateBr(else2); - - // Conversion OK - def->f->getBasicBlockList().push_back(else2); - def->builder->SetInsertPoint(else2); - - auto load_var = emit_load_local_n(def, var); - emit_store_reg_i_withtype(def, load_var, dest); - def->builder->CreateBr(end1); - - def->f->getBasicBlockList().push_back(end1); - def->builder->SetInsertPoint(end1); -} - -void RaviCodeGenerator::emit_TOFLT(RaviFunctionDef *def, int A, int pc) { - // case OP_RAVI_TOFLT: { - // lua_Number j; - // if (tonumber(ra, &j)) { - // setfltvalue(ra, j); - // } - // else - // luaG_runerror(L, "float expected"); - // } break; - - llvm::IRBuilder<> TmpB(def->entry, def->entry->begin()); - llvm::Value *var = TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "n"); - - emit_debug_trace(def, OP_RAVI_TOFLT, pc); - // Load pointer to base - emit_load_base(def); - - llvm::Value *dest = emit_gep_register(def, A); - llvm::Value *src = dest; - - llvm::Value *src_type = emit_load_type(def, src); - - // Is src->tt != LUA_TNUMFLT? - llvm::Value *cmp1 = - emit_is_not_value_of_type(def, src_type, LUA__TNUMFLT, "is.not.float"); - - llvm::BasicBlock *then1 = llvm::BasicBlock::Create(def->jitState->context(), - "if.not.float", def->f); - llvm::BasicBlock *end1 = - llvm::BasicBlock::Create(def->jitState->context(), "done"); - def->builder->CreateCondBr(cmp1, then1, end1); - def->builder->SetInsertPoint(then1); - - // Call luaV_tonumber() - llvm::Value *var_isflt = - CreateCall2(def->builder, def->luaV_tonumberF, src, var); - llvm::Value *tobool = def->builder->CreateICmpEQ( - var_isflt, def->types->kInt[0], "float.conversion.failed"); - - // Did conversion fail? - llvm::BasicBlock *then2 = llvm::BasicBlock::Create( - def->jitState->context(), "if.conversion.failed", def->f); - llvm::BasicBlock *else2 = - llvm::BasicBlock::Create(def->jitState->context(), "conversion.ok"); - def->builder->CreateCondBr(tobool, then2, else2); - def->builder->SetInsertPoint(then2); - - // Conversion failed, so raise error - emit_raise_lua_error(def, "number expected"); - def->builder->CreateBr(else2); - - // Conversion OK - def->f->getBasicBlockList().push_back(else2); - def->builder->SetInsertPoint(else2); - - auto load_var = emit_load_local_n(def, var); - emit_store_reg_n_withtype(def, load_var, dest); - def->builder->CreateBr(end1); - - def->f->getBasicBlockList().push_back(end1); - def->builder->SetInsertPoint(end1); -} - -void RaviCodeGenerator::emit_LOADK(RaviFunctionDef *def, int A, int Bx, - int pc) { - // TValue *rb = k + GETARG_Bx(i); - // setobj2s(L, ra, rb); - - emit_debug_trace(def, OP_LOADK, pc); - // Load pointer to base - emit_load_base(def); - - // LOADK requires a structure assignment - // in LLVM as far as I can tell this requires a call to - // an intrinsic memcpy - llvm::Value *dest = emit_gep_register(def, A); - - TValue *Konst = &def->p->k[Bx]; - switch (Konst->tt_) { - case LUA_TNUMINT: - emit_store_reg_i_withtype( - def, - llvm::ConstantInt::get(def->types->lua_IntegerT, Konst->value_.i), - dest); - break; - case LUA_TNUMFLT: - emit_store_reg_n_withtype( - def, llvm::ConstantFP::get(def->types->lua_NumberT, Konst->value_.n), - dest); - break; - case LUA_TBOOLEAN: - emit_store_reg_b_withtype( - def, llvm::ConstantInt::get(def->types->C_intT, Konst->value_.b), - dest); - break; - default: { - // rb - llvm::Value *src = emit_gep_constant(def, Bx); - - // *ra = *rb - emit_assign(def, dest, src); - } - } -} - -void RaviCodeGenerator::emit_assign(RaviFunctionDef *def, llvm::Value *dest, - llvm::Value *src) { - // Below is more efficient that memcpy() - // destvalue->value->i = srcvalue->value->i; - // destvalue->value->tt = srcvalue->value->tt; - llvm::Value *srcvalue = emit_gep(def, "srcvalue", src, 0, 0, 0); - llvm::Value *destvalue = emit_gep(def, "destvalue", dest, 0, 0, 0); - llvm::Instruction *load = def->builder->CreateLoad(srcvalue); - load->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_nT); - llvm::Instruction *store = def->builder->CreateStore(load, destvalue); - store->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_nT); - - // destvalue->type = srcvalue->type - llvm::Value *srctype = emit_gep(def, "srctype", src, 0, 1); - llvm::Value *desttype = emit_gep(def, "desttype", dest, 0, 1); - load = def->builder->CreateLoad(srctype); - load->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_ttT); - store = def->builder->CreateStore(load, desttype); - store->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_ttT); -} -} \ No newline at end of file diff --git a/src/ravi_llvmrest.cpp b/src/ravi_llvmrest.cpp deleted file mode 100644 index d4c0137..0000000 --- a/src/ravi_llvmrest.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/****************************************************************************** -* 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. -******************************************************************************/ -#include "ravi_llvmcodegen.h" - -namespace ravi { - -void RaviCodeGenerator::emit_CONCAT(RaviFunctionDef *def, int A, int B, int C, - int pc) { - bool traced = emit_debug_trace(def, OP_CONCAT, pc); - // below may invoke metamethod so we need to set savedpc - if (!traced) emit_update_savedpc(def, pc); - CreateCall5(def->builder, def->raviV_op_concatF, def->L, def->ci_val, - llvm::ConstantInt::get(def->types->C_intT, A), - llvm::ConstantInt::get(def->types->C_intT, B), - llvm::ConstantInt::get(def->types->C_intT, C)); -} - -void RaviCodeGenerator::emit_CLOSURE(RaviFunctionDef *def, int A, int Bx, - int pc) { - emit_debug_trace(def, OP_CLOSURE, pc); - CreateCall5(def->builder, def->raviV_op_closureF, def->L, def->ci_val, - def->p_LClosure, llvm::ConstantInt::get(def->types->C_intT, A), - llvm::ConstantInt::get(def->types->C_intT, Bx)); -} - -void RaviCodeGenerator::emit_VARARG(RaviFunctionDef *def, int A, int B, - int pc) { - emit_debug_trace(def, OP_VARARG, pc); - CreateCall5(def->builder, def->raviV_op_varargF, def->L, def->ci_val, - def->p_LClosure, llvm::ConstantInt::get(def->types->C_intT, A), - llvm::ConstantInt::get(def->types->C_intT, B)); -} -} \ No newline at end of file diff --git a/src/ravi_llvmreturn.cpp b/src/ravi_llvmreturn.cpp deleted file mode 100644 index 847809d..0000000 --- a/src/ravi_llvmreturn.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/****************************************************************************** -* 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. -******************************************************************************/ -#include "ravi_llvmcodegen.h" - -namespace ravi { - -void RaviCodeGenerator::emit_RETURN(RaviFunctionDef *def, int A, int B, - int pc) { - - // Here is what OP_RETURN looks like. We only compile steps - // marked with //*. This is because the rest is only relevant in the - // interpreter - - // case OP_RETURN: { - // int b = GETARG_B(i); - //* if (cl->p->sizep > 0) luaF_close(L, base); - //* b = luaD_poscall(L, ra, (b != 0 ? b - 1 : L->top - ra)); - // if (!(ci->callstatus & CIST_REENTRY)) /* 'ci' still the called one */ - //* return b; /* external invocation: return */ - // else { /* invocation via reentry: continue execution */ - // ci = L->ci; - // if (b) L->top = ci->top; - // goto newframe; /* restart luaV_execute over new Lua function */ - // } - // } - - // As Lua inserts redundant OP_RETURN instructions it is - // possible that this is one of them. If this is the case then the - // current block may already be terminated - so we have to insert - // a new block - if (def->builder->GetInsertBlock()->getTerminator()) { - llvm::BasicBlock *return_block = llvm::BasicBlock::Create( - def->jitState->context(), "OP_RETURN_bridge", def->f); - def->builder->SetInsertPoint(return_block); - } - - bool traced = emit_debug_trace(def, OP_RETURN, pc); - -#ifndef RAVI_DEFER_STATEMENT - // Load pointer to base - emit_load_base(def); - - // Get pointer to register A - llvm::Value *ra_ptr = emit_gep_register(def, A); -#endif - - // if (cl->p->sizep > 0) luaF_close(L, base); - // Get pointer to Proto->sizep - llvm::Instruction *psize = emit_load_proto_sizep(def); - - // Test if psize > 0 - 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_closing", def->f); - llvm::BasicBlock *else_block = llvm::BasicBlock::Create( - def->jitState->context(), "OP_RETURN_else_closing"); - def->builder->CreateCondBr(psize_gt_0, then_block, else_block); - def->builder->SetInsertPoint(then_block); - -#ifdef RAVI_DEFER_STATEMENT - // 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); -#endif - // Call luaF_close -#ifdef RAVI_DEFER_STATEMENT - CreateCall3(def->builder, def->luaF_closeF, def->L, def->base_ptr, def->types->kInt[LUA_OK]); -#else - CreateCall2(def->builder, def->luaF_closeF, def->L, def->base_ptr); -#endif - def->builder->CreateBr(else_block); - - def->f->getBasicBlockList().push_back(else_block); - def->builder->SetInsertPoint(else_block); -#ifdef RAVI_DEFER_STATEMENT - emit_load_base(def); // As luaF_close() may have changed the stack - ra_ptr = emit_gep_register(def, A); // load RA -#endif - //* b = luaD_poscall(L, ra, (b != 0 ? b - 1 : L->top - ra)); - llvm::Value *nresults = NULL; - if (B != 0) - nresults = llvm::ConstantInt::get(def->types->C_intT, B - 1); - else - nresults = emit_num_stack_elements(def, ra_ptr); - - llvm::Value *b = - CreateCall4(def->builder, def->luaD_poscallF, def->L, def->ci_val, ra_ptr, nresults); - def->builder->CreateRet(b); -} -} \ No newline at end of file diff --git a/src/ravi_llvmtable.cpp b/src/ravi_llvmtable.cpp deleted file mode 100644 index 87625ed..0000000 --- a/src/ravi_llvmtable.cpp +++ /dev/null @@ -1,981 +0,0 @@ -/****************************************************************************** -* 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. -******************************************************************************/ -#include "ravi_llvmcodegen.h" - -namespace ravi { - -// R(A+1) := R(B); R(A) := R(B)[RK(C)] -void RaviCodeGenerator::emit_SELF(RaviFunctionDef *def, int A, int B, int C, - int pc) { - // StkId rb = RB(i); - // setobjs2s(L, ra + 1, rb); - // Protect(luaV_gettable(L, rb, RKC(i), ra)); - bool traced = emit_debug_trace(def, OP_SELF, pc); - // Below may invoke metamethod so we set savedpc - if (!traced) emit_update_savedpc(def, pc); - emit_load_base(def); - llvm::Value *rb = emit_gep_register(def, B); - llvm::Value *ra1 = emit_gep_register(def, A + 1); - emit_assign(def, ra1, rb); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - CreateCall4(def->builder, def->luaV_gettableF, def->L, rb, rc, ra); -} - -// R(A+1) := R(B); R(A) := R(B)[RK(C)] -void RaviCodeGenerator::emit_SELF_SK(RaviFunctionDef *def, int A, int B, int C, - int pc) { - // StkId rb = RB(i); - // setobjs2s(L, ra + 1, rb); - // Protect(raviV_gettable_sskey(L, rb, RKC(i), ra)); - bool traced = emit_debug_trace(def, OP_RAVI_SELF_SK, pc); - // Below may invoke metamethod so we set savedpc - if (!traced) emit_update_savedpc(def, pc); - emit_load_base(def); - llvm::Value *rb = emit_gep_register(def, B); - llvm::Value *ra1 = emit_gep_register(def, A + 1); - emit_assign(def, ra1, rb); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - CreateCall4(def->builder, def->raviV_gettable_sskeyF, def->L, rb, rc, ra); -} - -// R(A+1) := R(B); R(A) := R(B)[RK(C)] -void RaviCodeGenerator::emit_TABLE_SELF_SK(RaviFunctionDef *def, int A, int B, int C, - int pc, TString *key) { - // StkId rb = RB(i); - // setobjs2s(L, ra + 1, rb); - // TValue *kv = k + INDEXK(GETARG_C(i)); - // TString *key = tsvalue(kv); - // const TValue *v = luaH_getstr(hvalue(rb), key); - // setobj2s(L, ra, v); - emit_debug_trace(def, OP_RAVI_TABLE_SELF_SK, pc); - emit_load_base(def); - llvm::Value *rb = emit_gep_register(def, B); - llvm::Value *ra1 = emit_gep_register(def, A + 1); - emit_assign(def, ra1, rb); - emit_common_GETTABLE_S(def, A, B, C, key); -} - -// R(A) := length of R(B) -void RaviCodeGenerator::emit_LEN(RaviFunctionDef *def, int A, int B, int pc) { - // Protect(luaV_objlen(L, ra, RB(i))); - bool traced = emit_debug_trace(def, OP_LEN, pc); - // Below may invoke metamethod so we set savedpc - if (!traced) emit_update_savedpc(def, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_register(def, B); - CreateCall3(def->builder, def->luaV_objlenF, def->L, ra, rb); -} - -// R(A)[RK(B)] := RK(C) -// This is a more optimized version that calls -// luaH_setint() instead of luaV_settable(). -// This relies on two things: -// a) we know we have a table -// b) we know the key is an integer -void RaviCodeGenerator::emit_SETI(RaviFunctionDef *def, int A, int B, - int C, int pc) { - bool traced = emit_debug_trace(def, OP_RAVI_SETI, pc); - if (!traced) emit_update_savedpc(def, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_register_or_constant(def, B); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - CreateCall4(def->builder, def->raviV_settable_iF, def->L, ra, rb, rc); -} - -// R(A)[RK(B)] := RK(C) -void RaviCodeGenerator::emit_SETTABLE(RaviFunctionDef *def, int A, int B, int C, - int pc) { - // Protect(luaV_settable(L, ra, RKB(i), RKC(i))); - bool traced = emit_debug_trace(def, OP_SETTABLE, pc); - // Below may invoke metamethod so we set savedpc - if (!traced) emit_update_savedpc(def, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_register_or_constant(def, B); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - CreateCall4(def->builder, def->luaV_settableF, def->L, ra, rb, rc); -} - -// R(A)[RK(B)] := RK(C) -void RaviCodeGenerator::emit_SETFIELD(RaviFunctionDef *def, int A, int B, - int C, int pc) { - // Protect(raviV_settable_sskey(L, ra, RKB(i), RKC(i))); - bool traced = emit_debug_trace(def, OP_RAVI_SETFIELD, pc); - // Below may invoke metamethod so we set savedpc - if (!traced) emit_update_savedpc(def, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_register_or_constant(def, B); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - CreateCall4(def->builder, def->raviV_settable_sskeyF, def->L, ra, rb, rc); -} - -// R(A) := R(B)[RK(C)] -void RaviCodeGenerator::emit_GETTABLE(RaviFunctionDef *def, int A, int B, int C, - int pc) { - // Protect(luaV_gettable(L, RB(i), RKC(i), ra)); - bool traced = emit_debug_trace(def, OP_GETTABLE, pc); - // Below may invoke metamethod so we set savedpc - if (!traced) emit_update_savedpc(def, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_register(def, B); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - CreateCall4(def->builder, def->luaV_gettableF, def->L, rb, rc, ra); -} - -// R(A) := R(B)[RK(C)] -void RaviCodeGenerator::emit_GETFIELD(RaviFunctionDef *def, int A, int B, - int C, int pc, TString *key) { - bool traced = emit_debug_trace(def, OP_RAVI_GETFIELD, pc); - // Below may invoke metamethod so we set savedpc - if (!traced) emit_update_savedpc(def, pc); - emit_load_base(def); - llvm::Value *rb = emit_gep_register(def, B); -#if 0 - // Protect(raviV_gettable_sskey(L, RB(i), RKC(i), ra)); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - CreateCall4(def->builder, def->raviV_gettable_sskeyF, def->L, rb, rc, ra); -#else - llvm::Instruction *type = emit_load_type(def, rb); - - // if table type try fast path - llvm::Value *cmp1 = emit_is_value_of_type(def, type, RAVI__TLTABLE, - "GETFIELD_is_table_type"); - llvm::BasicBlock *is_table = llvm::BasicBlock::Create( - def->jitState->context(), "GETFIELD_is_table", def->f); - llvm::BasicBlock *not_table = llvm::BasicBlock::Create( - def->jitState->context(), "GETFIELD_is_not_table"); - llvm::BasicBlock *done = - llvm::BasicBlock::Create(def->jitState->context(), "GETFIELD_done"); - auto brinst1 = def->builder->CreateCondBr(cmp1, is_table, not_table); - attach_branch_weights(def, brinst1, 100, 0); - def->builder->SetInsertPoint(is_table); - - emit_common_GETTABLE_S_(def, A, rb, C, key); - - def->builder->CreateBr(done); - - def->f->getBasicBlockList().push_back(not_table); - def->builder->SetInsertPoint(not_table); - - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - CreateCall4(def->builder, def->raviV_gettable_sskeyF, def->L, rb, rc, ra); - - def->builder->CreateBr(done); - - def->f->getBasicBlockList().push_back(done); - def->builder->SetInsertPoint(done); -#endif -} - -// R(A) := R(B)[RK(C)] -// This is a more optimized version that attempts to do an inline -// array get first and only if that fails it falls back on calling -// luaH_getint(). This relies on two things: -// a) we know we have a table -// b) we know the key is an integer -void RaviCodeGenerator::emit_GETI(RaviFunctionDef *def, int A, int B, - int C, int pc) { - // changed to that target may not be a table - bool traced = emit_debug_trace(def, OP_RAVI_GETI, pc); - if (!traced) emit_update_savedpc(def, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_register(def, B); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - CreateCall4(def->builder, def->raviV_gettable_iF, def->L, rb, rc, ra); - - // FIXME following is no longer valid as RB may not be a table - - // TValue *rb = RB(i); - // TValue *rc = RKC(i); - // lua_Integer idx = ivalue(rc); - // Table *t = hvalue(rb); - // const TValue *v; - // if (l_castS2U(idx - 1) < t->sizearray) - // v = &t->array[idx - 1]; - // else - // v = luaH_getint(t, idx); - // if (!ttisnil(v) || metamethod_absent(t->metatable, TM_INDEX)) { - // setobj2s(L, ra, v); - //} - // else { - // Protect(luaV_finishget(L, rb, rc, ra, v)); - //} - - //emit_debug_trace(def, OP_RAVI_GETTABLE_I, pc); - //emit_load_base(def); - //llvm::Value *ra = emit_gep_register(def, A); - //llvm::Value *rb = emit_gep_register(def, B); - //llvm::Value *rc = emit_gep_register_or_constant(def, C); - //llvm::Instruction *key = emit_load_reg_i(def, rc); - //llvm::Instruction *t = emit_load_reg_h(def, rb); - //llvm::Value *data = emit_table_get_array(def, t); - //llvm::Value *len = emit_table_get_arraysize(def, t); - //// As Lua arrays are 1 based we need to subtract by 1 - //llvm::Value *key_minus_1 = - // def->builder->CreateSub(key, def->types->kluaInteger[1]); - //// As len is unsigned int we need to truncate - //llvm::Value *ukey = - // def->builder->CreateTrunc(key_minus_1, def->types->C_intT); - //// Do an unsigned comparison with length - //llvm::Value *cmp = def->builder->CreateICmpULT(ukey, len); - //llvm::BasicBlock *then_block = - // llvm::BasicBlock::Create(def->jitState->context(), "if.in.range", def->f); - //llvm::BasicBlock *else_block = - // llvm::BasicBlock::Create(def->jitState->context(), "if.not.in.range"); - //llvm::BasicBlock *end_block = - // llvm::BasicBlock::Create(def->jitState->context(), "if.end"); - //def->builder->CreateCondBr(cmp, then_block, else_block); - //def->builder->SetInsertPoint(then_block); - - //// Key is in range so array access possible - //llvm::Value *value1 = def->builder->CreateGEP(data, ukey); - //def->builder->CreateBr(end_block); - - //// Out of range so fall back to luaH_getint() - //def->f->getBasicBlockList().push_back(else_block); - //def->builder->SetInsertPoint(else_block); - //llvm::Value *value2 = CreateCall2(def->builder, def->luaH_getintF, t, key); - //def->builder->CreateBr(end_block); - - //// Merge results from the two branches above - //def->f->getBasicBlockList().push_back(end_block); - //def->builder->SetInsertPoint(end_block); - //llvm::PHINode *phi = def->builder->CreatePHI(def->types->pTValueT, 2); - //phi->addIncoming(value1, then_block); - //phi->addIncoming(value2, else_block); - //emit_finish_GETTABLE(def, phi, t, ra, rb, rc); -} - -void RaviCodeGenerator::emit_finish_GETTABLE(RaviFunctionDef *def, - llvm::Value *phi, llvm::Value *t, - llvm::Value *ra, llvm::Value *rb, - llvm::Value *rc) { - // We need to test if value is not nil - // or table has no metatable - // or if the metatable cached flags indicate metamethod absent - llvm::Value *value_type = emit_load_type(def, phi); - llvm::Value *isnotnil = emit_is_not_value_of_type(def, value_type, LUA__TNIL); - // llvm::Value *metamethod_absent = emit_table_no_metamethod(def, t, - // TM_INDEX); - // llvm::Value *cond = def->builder->CreateOr(isnotnil, metamethod_absent); - llvm::Value *cond = isnotnil; - - llvm::BasicBlock *if_true_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.not.nil", def->f); - llvm::BasicBlock *if_false_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.try.metamethod"); - llvm::BasicBlock *if_end_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.end"); - auto brinst1 = - def->builder->CreateCondBr(cond, if_true_block, if_false_block); - attach_branch_weights(def, brinst1, 100, 0); - def->builder->SetInsertPoint(if_true_block); - - // Fast path - emit_assign(def, ra, phi); - def->builder->CreateBr(if_end_block); - - def->f->getBasicBlockList().push_back(if_false_block); - def->builder->SetInsertPoint(if_false_block); - - // If value is nil Lua requires that an index event be - // generated - so we fall back on slow path for that - CreateCall5(def->builder, def->luaV_finishgetF, def->L, rb, rc, ra, phi); - def->builder->CreateBr(if_end_block); - - // Merge results from the two branches above - def->f->getBasicBlockList().push_back(if_end_block); - def->builder->SetInsertPoint(if_end_block); -} - -// R(A) := R(B)[RK(C)] -// Emit inline code for accessing a table element using a string key -// We try to access the element using the hash part but if the -// key is not in the main position then we fall back on luaH_getstr(). -// IMPORTANT - this emitter should only be called when key is known to -// to be short string -// NOTE: To add support for GETTABUP_SK we now let caller supply the -// rb register as it may be a register or an upvalue reference -// See emit_GETTABUP_SK -void RaviCodeGenerator::emit_common_GETTABLE_S_(RaviFunctionDef *def, int A, - llvm::Value *rb, int C, - TString *key) { - // The code we want to generate is this: - // struct Node *n = hashstr(t, key); - // const struct TValue *k = gkey(n); - // TValue *v; - // if (ttisshrstring(k) && eqshrstr(tsvalue(k), key)) - // v = gval(n); - // else - // v = luaH_getstr(t, key); - // if (!ttisnil(v) || metamethod_absent(t->metatable, TM_INDEX)) { - // setobj2s(L, ra, v); - // } - // else { - // Protect(luaV_finishget(L, rb, rc, ra, v)); - // } - - // A number of macros are involved above do the - // the generated code is somewhat more complex - - llvm::Value *ra = emit_gep_register(def, A); - - // Get the hash table - llvm::Instruction *t = emit_load_reg_h(def, rb); - - // Obtain the offset where the key should be - llvm::Value *offset = emit_table_get_hashstr(def, t, key); - - // Get access to the node array - llvm::Value *node = emit_table_get_nodearray(def, t); - - // Now we need to get to the right element in the node array - // and retrieve the type information which is held there - llvm::Value *ktype = emit_table_get_keytype(def, node, offset); - - // We need to check that the key type is also short string - llvm::Value *is_shortstring = - emit_is_value_of_type(def, ktype, LUA__TSHRSTR, "is_shortstring"); - llvm::BasicBlock *testkey = - llvm::BasicBlock::Create(def->jitState->context(), "testkey"); - llvm::BasicBlock *testok = - llvm::BasicBlock::Create(def->jitState->context(), "testok"); - llvm::BasicBlock *testfail = - llvm::BasicBlock::Create(def->jitState->context(), "testfail"); - llvm::BasicBlock *testend = - llvm::BasicBlock::Create(def->jitState->context(), "testend"); - auto brinst1 = def->builder->CreateCondBr(is_shortstring, testkey, testfail); - attach_branch_weights(def, brinst1, 100, 0); - - // Now we need to compare the keys - def->f->getBasicBlockList().push_back(testkey); - def->builder->SetInsertPoint(testkey); - - // Get the key from the node - llvm::Value *keyvalue = emit_table_get_strkey(def, node, offset); - - // Cast the pointer to a intptr so we can compare - llvm::Value *intptr = - def->builder->CreatePtrToInt(keyvalue, def->types->C_intptr_t); - llvm::Value *ourptr = - llvm::ConstantInt::get(def->types->C_intptr_t, (intptr_t)key); - // Compare the two pointers - // If they match then we found the element - llvm::Value *same = def->builder->CreateICmpEQ(intptr, ourptr); - auto brinst2 = def->builder->CreateCondBr(same, testok, testfail); - attach_branch_weights(def, brinst2, 5, 2); - - // If key found return the value - def->f->getBasicBlockList().push_back(testok); - def->builder->SetInsertPoint(testok); - // Get the value - llvm::Value *value1 = emit_table_get_value(def, node, offset); - llvm::Value *rc1 = emit_gep_register_or_constant(def, C); - def->builder->CreateBr(testend); - - // Not found so call luaH_getstr - def->f->getBasicBlockList().push_back(testfail); - def->builder->SetInsertPoint(testfail); - llvm::Value *rc2 = emit_gep_register_or_constant(def, C); - llvm::Value *value2 = CreateCall2(def->builder, def->luaH_getstrF, t, - emit_load_reg_s(def, rc2)); - def->builder->CreateBr(testend); - - // merge - def->f->getBasicBlockList().push_back(testend); - def->builder->SetInsertPoint(testend); - llvm::PHINode *phi = def->builder->CreatePHI(def->types->pTValueT, 2); - phi->addIncoming(value1, testok); - phi->addIncoming(value2, testfail); - llvm::PHINode *phi2 = def->builder->CreatePHI(def->types->pTValueT, 2); - phi2->addIncoming(rc1, testok); - phi2->addIncoming(rc2, testfail); - emit_finish_GETTABLE(def, phi, t, ra, rb, phi2); -} - -// R(A) := R(B)[RK(C)] -// Emit inline code for accessing a table element using a string key -// We try to access the element using the hash part but if the -// key is not in the main position then we fall back on luaH_getstr(). -// IMPORTANT - this emitter should only be called when key is known to -// to be short string -void RaviCodeGenerator::emit_common_GETTABLE_S(RaviFunctionDef *def, int A, - int B, int C, TString *key) { - // The code we want to generate is this: - // struct Node *n = hashstr(t, key); - // const struct TValue *k = gkey(n); - // TValue *v; - // if (ttisshrstring(k) && eqshrstr(tsvalue(k), key)) - // v = gval(n); - // else - // v = luaH_getstr(t, key); - // if (!ttisnil(v) || metamethod_absent(t->metatable, TM_INDEX)) { - // setobj2s(L, ra, v); - // } - // else { - // Protect(luaV_finishget(L, rb, rc, ra, v)); - // } - - // A number of macros are involved above do the - // the generated code is somewhat more complex - - llvm::Value *rb = emit_gep_register(def, B); - emit_common_GETTABLE_S_(def, A, rb, C, key); -} - -// R(A) := R(B)[RK(C)] -// Emit inline code for accessing a table element using a string key -// We try to access the element using the hash part but if the -// key is not in the main position then we fall back on luaH_getstr(). -// IMPORTANT - this emitter should only be called when key is known to -// to be short string -void RaviCodeGenerator::emit_GETTABLE_S(RaviFunctionDef *def, int A, int B, - int C, int pc, TString *key) { - // The code we want to generate is this: - // struct Node *n = hashstr(t, key); - // const struct TValue *k = gkey(n); - // if (ttisshrstring(k) && eqshrstr(tsvalue(k), key)) - // return gval(n); - // return luaH_getstr(t, key); - - emit_debug_trace(def, OP_RAVI_TABLE_GETFIELD, pc); - emit_load_base(def); - emit_common_GETTABLE_S(def, A, B, C, key); -} - -void RaviCodeGenerator::emit_FARRAY_GET(RaviFunctionDef *def, int A, int B, - int C, bool omitArrayGetRangeCheck, - int pc) { - //#define raviH_get_float_inline(L, t, key, v) - //{ unsigned ukey = (unsigned)((key)); - // lua_Number *data = (lua_Number *)t->data; - // if (ukey < t->len) { - // setfltvalue(v, data[ukey]); - // }else - // luaG_runerror(L, "array out of bounds"); - //} - - // TValue *rb = RB(i); - // TValue *rc = RKC(i); - // lua_Integer idx = ivalue(rc); - // Table *t = hvalue(rb); - // raviH_get_float_inline(L, t, idx, ra); - - emit_debug_trace(def, OP_RAVI_FARRAY_GET, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_register(def, B); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - llvm::Instruction *key = emit_load_reg_i(def, rc); - llvm::Instruction *t = emit_load_reg_arr(def, rb); - llvm::Instruction *data = emit_load_reg_h_floatarray(def, t); - llvm::BasicBlock *then_block = nullptr; - llvm::BasicBlock *else_block = nullptr; - llvm::BasicBlock *end_block = nullptr; - if (!omitArrayGetRangeCheck) { - llvm::Instruction *len = emit_load_ravi_arraylength(def, t); - llvm::Value *ulen = - def->builder->CreateZExt(len, def->types->lua_UnsignedT, "ulen"); - - llvm::Value *cmp = def->builder->CreateICmpULT(key, ulen); - then_block = llvm::BasicBlock::Create(def->jitState->context(), - "if.in.range", def->f); - else_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.not.in.range"); - end_block = llvm::BasicBlock::Create(def->jitState->context(), "if.end"); - auto brinst1 = def->builder->CreateCondBr(cmp, then_block, else_block); - attach_branch_weights(def, brinst1, 100, 0); - def->builder->SetInsertPoint(then_block); - } - - llvm::Value *ptr = def->builder->CreateGEP(data, key); - llvm::Instruction *value = def->builder->CreateLoad(ptr); - value->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_pdoubleT); - emit_store_reg_n_withtype(def, value, ra); - - if (!omitArrayGetRangeCheck) { - def->builder->CreateBr(end_block); - - def->f->getBasicBlockList().push_back(else_block); - def->builder->SetInsertPoint(else_block); - - emit_raise_lua_error(def, "array out of bounds"); - def->builder->CreateBr(end_block); - - def->f->getBasicBlockList().push_back(end_block); - def->builder->SetInsertPoint(end_block); - } -} - -void RaviCodeGenerator::emit_IARRAY_GET(RaviFunctionDef *def, int A, int B, - int C, bool omitArrayGetRangeCheck, - int pc) { - //#define raviH_get_int_inline(L, t, key, v) - //{ unsigned ukey = (unsigned)((key)); - // lua_Integer *data = (lua_Integer *)t->data; - // if (ukey < t->len) { - // setivalue(v, data[ukey]); - // } else - // luaG_runerror(L, "array out of bounds"); - //} - - // TValue *rb = RB(i); - // TValue *rc = RKC(i); - // lua_Integer idx = ivalue(rc); - // Table *t = hvalue(rb); - // raviH_get_int_inline(L, t, idx, ra); - - emit_debug_trace(def, OP_RAVI_IARRAY_GET, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_register(def, B); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - llvm::Instruction *key = emit_load_reg_i(def, rc); - llvm::Instruction *t = emit_load_reg_arr(def, rb); - llvm::Instruction *data = emit_load_reg_h_intarray(def, t); - - llvm::BasicBlock *then_block = nullptr; - llvm::BasicBlock *else_block = nullptr; - llvm::BasicBlock *end_block = nullptr; - if (!omitArrayGetRangeCheck) { - llvm::Instruction *len = emit_load_ravi_arraylength(def, t); - llvm::Value *ulen = - def->builder->CreateZExt(len, def->types->lua_UnsignedT, "ulen"); - - llvm::Value *cmp = def->builder->CreateICmpULT(key, ulen); - then_block = llvm::BasicBlock::Create(def->jitState->context(), - "if.in.range", def->f); - else_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.not.in.range"); - end_block = llvm::BasicBlock::Create(def->jitState->context(), "if.end"); - auto brinst1 = def->builder->CreateCondBr(cmp, then_block, else_block); - attach_branch_weights(def, brinst1, 100, 0); - def->builder->SetInsertPoint(then_block); - } - - llvm::Value *ptr = def->builder->CreateGEP(data, key); - llvm::Instruction *value = def->builder->CreateLoad(ptr); - value->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_plonglongT); - emit_store_reg_i_withtype(def, value, ra); - - if (!omitArrayGetRangeCheck) { - def->builder->CreateBr(end_block); - - def->f->getBasicBlockList().push_back(else_block); - def->builder->SetInsertPoint(else_block); - - emit_raise_lua_error(def, "array out of bounds"); - def->builder->CreateBr(end_block); - - def->f->getBasicBlockList().push_back(end_block); - def->builder->SetInsertPoint(end_block); - } -} - -void RaviCodeGenerator::emit_IARRAY_SET(RaviFunctionDef *def, int A, int B, - int C, bool known_int, int pc) { - //#define raviH_set_int_inline(L, t, key, value) - //{ unsigned ukey = (unsigned)((key)); - // lua_Integer *data = (lua_Integer *)t->data; - // if (ukey < t->len) { - // data[ukey] = value; - // } else - // raviH_set_int(L, t, ukey, value); - //} - - // Table *t = hvalue(ra); - // TValue *rb = RKB(i); - // TValue *rc = RKC(i); - // lua_Integer idx = ivalue(rb); - // lua_Integer value = ivalue(rc); - // raviH_set_int_inline(L, t, idx, value); - - emit_debug_trace(def, known_int ? OP_RAVI_IARRAY_SETI : OP_RAVI_IARRAY_SET, - pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_register_or_constant(def, B); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - llvm::Instruction *key = emit_load_reg_i(def, rb); - llvm::Instruction *value = - known_int ? emit_load_reg_i(def, rc) : emit_tointeger(def, rc); - llvm::Instruction *t = emit_load_reg_arr(def, ra); - llvm::Instruction *data = emit_load_reg_h_intarray(def, t); - llvm::Instruction *len = emit_load_ravi_arraylength(def, t); - llvm::Value *ulen = - def->builder->CreateZExt(len, def->types->lua_UnsignedT, "ulen"); - - llvm::Value *cmp = def->builder->CreateICmpULT(key, ulen); - llvm::BasicBlock *then_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.in.range", def->f); - llvm::BasicBlock *else_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.not.in.range"); - llvm::BasicBlock *end_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.end"); - def->builder->CreateCondBr(cmp, then_block, else_block); - def->builder->SetInsertPoint(then_block); - - llvm::Value *ptr = def->builder->CreateGEP(data, key); - - llvm::Instruction *storeinst = def->builder->CreateStore(value, ptr); - storeinst->setMetadata(llvm::LLVMContext::MD_tbaa, - def->types->tbaa_plonglongT); - def->builder->CreateBr(end_block); - - def->f->getBasicBlockList().push_back(else_block); - def->builder->SetInsertPoint(else_block); - - CreateCall4(def->builder, def->raviH_set_intF, def->L, t, key, value); - def->builder->CreateBr(end_block); - - def->f->getBasicBlockList().push_back(end_block); - def->builder->SetInsertPoint(end_block); -} - -void RaviCodeGenerator::emit_FARRAY_SET(RaviFunctionDef *def, int A, int B, - int C, bool known_float, int pc) { - //#define raviH_set_float_inline(L, t, key, value) - //{ unsigned ukey = (unsigned)((key)); - // lua_Number *data = (lua_Number *)t->data; - // if (ukey < t->len) { - // data[ukey] = value; - // } else - // raviH_set_float(L, t, ukey, value); - // } - - // Table *t = hvalue(ra); - // TValue *rb = RKB(i); - // TValue *rc = RKC(i); - // lua_Integer idx = ivalue(rb); - // if (ttisfloat(rc)) { - // raviH_set_float_inline(L, t, idx, fltvalue(rc)); - //} - // else { - // raviH_set_float_inline(L, t, idx, ((lua_Number)ivalue(rc))); - //} - - emit_debug_trace( - def, known_float ? OP_RAVI_FARRAY_SETF : OP_RAVI_FARRAY_SET, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rb = emit_gep_register_or_constant(def, B); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - llvm::Instruction *key = emit_load_reg_i(def, rb); - llvm::Instruction *value = - known_float ? emit_load_reg_n(def, rc) : emit_tofloat(def, rc); - llvm::Instruction *t = emit_load_reg_arr(def, ra); - llvm::Instruction *data = emit_load_reg_h_floatarray(def, t); - llvm::Instruction *len = emit_load_ravi_arraylength(def, t); - llvm::Value *ulen = - def->builder->CreateZExt(len, def->types->lua_UnsignedT, "ulen"); - - llvm::Value *cmp = def->builder->CreateICmpULT(key, ulen); - llvm::BasicBlock *then_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.in.range", def->f); - llvm::BasicBlock *else_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.not.in.range"); - llvm::BasicBlock *end_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.end"); - def->builder->CreateCondBr(cmp, then_block, else_block); - def->builder->SetInsertPoint(then_block); - - llvm::Value *ptr = def->builder->CreateGEP(data, key); - - llvm::Instruction *storeinst = def->builder->CreateStore(value, ptr); - storeinst->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_pdoubleT); - def->builder->CreateBr(end_block); - - def->f->getBasicBlockList().push_back(else_block); - def->builder->SetInsertPoint(else_block); - - CreateCall4(def->builder, def->raviH_set_floatF, def->L, t, key, value); - def->builder->CreateBr(end_block); - - def->f->getBasicBlockList().push_back(end_block); - def->builder->SetInsertPoint(end_block); -} - -// R(A) := UpValue[B] -void RaviCodeGenerator::emit_GETUPVAL(RaviFunctionDef *def, int A, int B, - int pc) { - // int b = GETARG_B(i); - // setobj2s(L, ra, cl->upvals[b]->v); - emit_debug_trace(def, OP_GETUPVAL, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *upval_ptr = emit_gep_upvals(def, B); - llvm::Instruction *upval = emit_load_pupval(def, upval_ptr); - llvm::Value *v = emit_load_upval_v(def, upval); - emit_assign(def, ra, v); -} - -// UpValue[B] := R(A) -void RaviCodeGenerator::emit_SETUPVAL_Specific(RaviFunctionDef *def, int A, - int B, int pc, OpCode op, - llvm::Function *f) { - emit_debug_trace(def, op, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - CreateCall4(def->builder, f, def->L, def->p_LClosure, ra, - llvm::ConstantInt::get(def->types->C_intT, B)); -} - -// UpValue[B] := R(A) -void RaviCodeGenerator::emit_SETUPVAL(RaviFunctionDef *def, int A, int B, - int pc) { - // UpVal *uv = cl->upvals[GETARG_B(i)]; - // setobj(L, uv->v, ra); - // luaC_upvalbarrier(L, uv); - - emit_debug_trace(def, OP_SETUPVAL, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *upval_ptr = emit_gep_upvals(def, B); - llvm::Instruction *upval = emit_load_pupval(def, upval_ptr); - llvm::Value *v = emit_load_upval_v(def, upval); - emit_assign(def, v, ra); - - llvm::Value *type = emit_load_type(def, v); - llvm::Value *is_collectible = - def->builder->CreateAnd(type, - llvm::ConstantInt::get(def->types->lua_LuaTypeT, BIT_ISCOLLECTABLE)); - - llvm::Value *value = emit_gep_upval_value(def, upval); - llvm::Value *cmp = def->builder->CreateICmpNE(v, value, "v.ne.value"); - llvm::Value *tobool = def->builder->CreateICmpEQ( - is_collectible, - llvm::ConstantInt::get(def->types->lua_LuaTypeT, 0), - "not.collectible"); - llvm::Value *orcond = - def->builder->CreateOr(cmp, tobool, "v.ne.value.or.not.collectible"); - - llvm::BasicBlock *then = - llvm::BasicBlock::Create(def->jitState->context(), "if.then", def->f); - llvm::BasicBlock *end = - llvm::BasicBlock::Create(def->jitState->context(), "if.end"); - - def->builder->CreateCondBr(orcond, end, then); - def->builder->SetInsertPoint(then); - - CreateCall2(def->builder, def->luaC_upvalbarrierF, def->L, upval); - def->builder->CreateBr(end); - - def->f->getBasicBlockList().push_back(end); - def->builder->SetInsertPoint(end); -} - -// R(A) := UpValue[B][RK(C)] -void RaviCodeGenerator::emit_GETTABUP(RaviFunctionDef *def, int A, int B, int C, - int pc) { - // int b = GETARG_B(i); - // Protect(luaV_gettable(L, cl->upvals[b]->v, RKC(i), ra)); - bool traced = emit_debug_trace(def, OP_GETTABUP, pc); - // Below may invoke metamethod so we set savedpc - if (!traced) emit_update_savedpc(def, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - - llvm::Value *upval_ptr = emit_gep_upvals(def, B); - llvm::Instruction *upval = emit_load_pupval(def, upval_ptr); - llvm::Value *v = emit_load_upval_v(def, upval); - CreateCall4(def->builder, def->luaV_gettableF, def->L, v, rc, ra); -} - -// R(A) := UpValue[B][RK(C)] -void RaviCodeGenerator::emit_GETTABUP_SK(RaviFunctionDef *def, int A, int B, - int C, int pc) { - // int b = GETARG_B(i); - // Protect(luaV_gettable(L, cl->upvals[b]->v, RKC(i), ra)); - bool traced = emit_debug_trace(def, OP_RAVI_GETTABUP_SK, pc); - // Below may invoke metamethod so we set savedpc - if (!traced) emit_update_savedpc(def, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - - llvm::Value *upval_ptr = emit_gep_upvals(def, B); - llvm::Instruction *upval = emit_load_pupval(def, upval_ptr); - llvm::Value *v = emit_load_upval_v(def, upval); - CreateCall4(def->builder, def->raviV_gettable_sskeyF, def->L, v, rc, ra); -} - -// UpValue[A][RK(B)] := RK(C) -void RaviCodeGenerator::emit_SETTABUP(RaviFunctionDef *def, int A, int B, int C, - int pc) { - // int a = GETARG_A(i); - // Protect(luaV_settable(L, cl->upvals[a]->v, RKB(i), RKC(i))); - - bool traced = emit_debug_trace(def, OP_SETTABUP, pc); - if (!traced) emit_update_savedpc(def, pc); - emit_load_base(def); - llvm::Value *rb = emit_gep_register_or_constant(def, B); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - - llvm::Value *upval_ptr = emit_gep_upvals(def, A); - llvm::Instruction *upval = emit_load_pupval(def, upval_ptr); - llvm::Value *v = emit_load_upval_v(def, upval); - CreateCall4(def->builder, def->luaV_settableF, def->L, v, rb, rc); -} - -// UpValue[A][RK(B)] := RK(C) -void RaviCodeGenerator::emit_SETTABUP_SK(RaviFunctionDef *def, int A, int B, - int C, int pc) { - // int a = GETARG_A(i); - // Protect(luaV_settable(L, cl->upvals[a]->v, RKB(i), RKC(i))); - - bool traced = emit_debug_trace(def, OP_RAVI_SETFIELD, pc); - if (!traced) emit_update_savedpc(def, pc); - emit_load_base(def); - llvm::Value *rb = emit_gep_register_or_constant(def, B); - llvm::Value *rc = emit_gep_register_or_constant(def, C); - - llvm::Value *upval_ptr = emit_gep_upvals(def, A); - llvm::Instruction *upval = emit_load_pupval(def, upval_ptr); - llvm::Value *v = emit_load_upval_v(def, upval); - CreateCall4(def->builder, def->raviV_settable_sskeyF, def->L, v, rb, rc); -} - -void RaviCodeGenerator::emit_NEWARRAYINT(RaviFunctionDef *def, int A, int pc) { - emit_debug_trace(def, OP_RAVI_NEW_IARRAY, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - CreateCall3(def->builder, def->raviV_op_newarrayintF, def->L, def->ci_val, - ra); -} - -void RaviCodeGenerator::emit_NEWARRAYFLOAT(RaviFunctionDef *def, int A, - int pc) { - emit_debug_trace(def, OP_RAVI_NEW_FARRAY, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - CreateCall3(def->builder, def->raviV_op_newarrayfloatF, def->L, def->ci_val, - ra); -} - -void RaviCodeGenerator::emit_NEWTABLE(RaviFunctionDef *def, int A, int B, int C, - int pc) { - // case OP_NEWTABLE: { - // int b = GETARG_B(i); - // int c = GETARG_C(i); - // Table *t = luaH_new(L); - // sethvalue(L, ra, t); - // if (b != 0 || c != 0) - // luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); - // checkGC(L, ra + 1); - // } break; - - emit_debug_trace(def, OP_NEWTABLE, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - CreateCall5(def->builder, def->raviV_op_newtableF, def->L, def->ci_val, ra, - def->types->kInt[B], def->types->kInt[C]); -} - -void RaviCodeGenerator::emit_SETLIST(RaviFunctionDef *def, int A, int B, int C, - int pc) { - emit_debug_trace(def, OP_SETLIST, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - CreateCall5(def->builder, def->raviV_op_setlistF, def->L, def->ci_val, ra, - def->types->kInt[B], def->types->kInt[C]); -} - -void RaviCodeGenerator::emit_TOARRAY(RaviFunctionDef *def, int A, - int array_type_expected, - const char *errmsg, int pc) { - OpCode op = OP_RAVI_TOTAB; - LuaTypeCode expectedType = RAVI__TLTABLE; - switch (array_type_expected) { - case RAVI_TARRAYINT: - op = OP_RAVI_TOIARRAY; - expectedType = RAVI__TIARRAY; - break; - case RAVI_TARRAYFLT: - op = OP_RAVI_TOFARRAY; - expectedType = RAVI__TFARRAY; - break; - case RAVI_TTABLE: - default: break; - } - - emit_debug_trace(def, op, pc); - emit_load_base(def); - llvm::Value *ra = emit_gep_register(def, A); - llvm::Instruction *type = emit_load_type(def, ra); - - // type != expectedType - llvm::Value *cmp1 = emit_is_not_value_of_type(def, type, expectedType, - "is.not.expected.type"); - llvm::BasicBlock *raise_error = llvm::BasicBlock::Create( - def->jitState->context(), "if.not.expected_type", def->f); - llvm::BasicBlock *done = - llvm::BasicBlock::Create(def->jitState->context(), "done"); - auto brinst1 = def->builder->CreateCondBr(cmp1, raise_error, done); - attach_branch_weights(def, brinst1, 0, 100); - def->builder->SetInsertPoint(raise_error); - - // Conversion failed, so raise error - emit_raise_lua_error(def, errmsg); - def->builder->CreateBr(done); - - def->f->getBasicBlockList().push_back(done); - def->builder->SetInsertPoint(done); -} - -void RaviCodeGenerator::emit_MOVEIARRAY(RaviFunctionDef *def, int A, int B, - int pc) { - emit_debug_trace(def, OP_RAVI_MOVEIARRAY, pc); - emit_TOARRAY(def, B, RAVI_TARRAYINT, "integer[] expected", pc); - llvm::Value *src = emit_gep_register(def, B); - llvm::Value *dest = emit_gep_register(def, A); - emit_assign(def, dest, src); -} - -void RaviCodeGenerator::emit_MOVEFARRAY(RaviFunctionDef *def, int A, int B, - int pc) { - emit_debug_trace(def, OP_RAVI_MOVEFARRAY, pc); - emit_TOARRAY(def, B, RAVI_TARRAYFLT, "number[] expected", pc); - llvm::Value *src = emit_gep_register(def, B); - llvm::Value *dest = emit_gep_register(def, A); - emit_assign(def, dest, src); -} - -void RaviCodeGenerator::emit_MOVETAB(RaviFunctionDef *def, int A, int B, - int pc) { - emit_debug_trace(def, OP_RAVI_MOVETAB, pc); - emit_TOARRAY(def, B, RAVI_TTABLE, "table expected", pc); - llvm::Value *src = emit_gep_register(def, B); - llvm::Value *dest = emit_gep_register(def, A); - emit_assign(def, dest, src); -} -} diff --git a/src/ravi_llvmtforcall.cpp b/src/ravi_llvmtforcall.cpp deleted file mode 100644 index 8329fe2..0000000 --- a/src/ravi_llvmtforcall.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/****************************************************************************** -* 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. -******************************************************************************/ -#include "ravi_llvmcodegen.h" - -namespace ravi { - -void RaviCodeGenerator::emit_TFORCALL(RaviFunctionDef *def, int A, int B, int C, - int j, int jA, int pc) { - - // case OP_TFORCALL: { - // StkId cb = ra + 3; /* call base */ - // setobjs2s(L, cb + 2, ra + 2); - // setobjs2s(L, cb + 1, ra + 1); - // setobjs2s(L, cb, ra); - // L->top = cb + 3; /* func. + 2 args (state and index) */ - // Protect(luaD_call(L, cb, GETARG_C(i), 1)); - // L->top = ci->top; - // i = *(ci->u.l.savedpc++); /* go to next instruction */ - // ra = RA(i); - // lua_assert(GET_OPCODE(i) == OP_TFORLOOP); - // goto l_tforloop; - // } - // case OP_TFORLOOP: { - // l_tforloop: - // if (!ttisnil(ra + 1)) { /* continue loop? */ - // setobjs2s(L, ra, ra + 1); /* save control variable */ - // ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - // } - // } break; - - bool traced = emit_debug_trace(def, OP_TFORCALL, pc); - // Below may invoke metamethod so we set savedpc - if (!traced)emit_update_savedpc(def, pc); - // Load pointer to base - emit_load_base(def); - - // Get pointer to register A - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *ra1 = emit_gep_register(def, A + 1); - llvm::Value *ra2 = emit_gep_register(def, A + 2); - llvm::Value *cb = emit_gep_register(def, A + 3); - llvm::Value *cb1 = emit_gep_register(def, A + 4); - llvm::Value *cb2 = emit_gep_register(def, A + 5); - - emit_assign(def, cb2, ra2); - emit_assign(def, cb1, ra1); - emit_assign(def, cb, ra); - - // L->top = cb + 3; /* func. + 2 args (state and index) */ - emit_set_L_top_toreg(def, A + 6); - - // Protect(luaD_call(L, cb, GETARG_C(i))); - CreateCall3(def->builder, def->luaD_callF, def->L, cb, def->types->kInt[C]); - // reload base - emit_load_base(def); - // L->top = ci->top; - emit_refresh_L_top(def, def->ci_val); - ra = emit_gep_register(def, jA); - ra1 = emit_gep_register(def, jA + 1); - llvm::Value *type = emit_load_type(def, ra1); - - // Test if type != LUA_TNIL (0) - llvm::Value *isnotnil = - emit_is_not_value_of_type(def, type, LUA__TNIL, "is.not.nil"); - llvm::BasicBlock *then_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.not.nil", def->f); - llvm::BasicBlock *else_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.nil"); - def->builder->CreateCondBr(isnotnil, then_block, else_block); - def->builder->SetInsertPoint(then_block); - - emit_assign(def, ra, ra1); - // Do the jump - def->builder->CreateBr(def->jmp_targets[j].jmp1); - - // Add the else block and make it current so that the next instruction flows - // here - def->f->getBasicBlockList().push_back(else_block); - def->builder->SetInsertPoint(else_block); -} - -void RaviCodeGenerator::emit_TFORLOOP(RaviFunctionDef *def, int A, int j, - int pc) { - // case OP_TFORLOOP: { - // l_tforloop: - // if (!ttisnil(ra + 1)) { /* continue loop? */ - // setobjs2s(L, ra, ra + 1); /* save control variable */ - // ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - // } - // } break; - - emit_debug_trace(def, OP_TFORLOOP, pc); - // Load pointer to base - emit_load_base(def); - - // Get pointer to register A - llvm::Value *ra = emit_gep_register(def, A); - llvm::Value *ra1 = emit_gep_register(def, A + 1); - llvm::Value *type = emit_load_type(def, ra1); - - // Test if type != LUA_TNIL (0) - llvm::Value *isnotnil = - emit_is_not_value_of_type(def, type, LUA__TNIL, "is.not.nil"); - llvm::BasicBlock *then_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.not.nil", def->f); - llvm::BasicBlock *else_block = - llvm::BasicBlock::Create(def->jitState->context(), "if.nil"); - def->builder->CreateCondBr(isnotnil, then_block, else_block); - def->builder->SetInsertPoint(then_block); - - emit_assign(def, ra, ra1); - // Do the jump - def->builder->CreateBr(def->jmp_targets[j].jmp1); - - // Add the else block and make it current so that the next instruction flows - // here - def->f->getBasicBlockList().push_back(else_block); - def->builder->SetInsertPoint(else_block); -} -} \ No newline at end of file diff --git a/src/ravi_llvmtypes.cpp b/src/ravi_llvmtypes.cpp deleted file mode 100644 index d53306c..0000000 --- a/src/ravi_llvmtypes.cpp +++ /dev/null @@ -1,1411 +0,0 @@ -/****************************************************************************** - * 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. - ******************************************************************************/ -#include "ravi_llvmcodegen.h" - -namespace ravi { - -/* Adds the bits that are defined in macro CommonHeader in lobject.h */ -void LuaLLVMTypes::addCommonGCHeader(std::vector &elements) { - /* Common Header for all collectable objects (in macro form, to be - included in other objects) - #define CommonHeader GCObject *next; lu_byte tt; lu_byte marked - */ - elements.push_back(pGCObjectT); - elements.push_back(lu_byteT); - elements.push_back(lu_byteT); -} - -LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) { - C_voidT = llvm::Type::getVoidTy(context); - - C_floatT = llvm::Type::getFloatTy(context); - C_doubleT = llvm::Type::getDoubleTy(context); - -#ifdef LUA_32BITS - // issue #93 add support for 32-bit Lua - lua_NumberT = C_floatT; - static_assert(std::is_floating_point::value && - sizeof(lua_Number) == sizeof(float), - "lua_Number is not a float"); - static_assert(sizeof(lua_Integer) == sizeof(lua_Number) && - sizeof(lua_Integer) == sizeof(int32_t), - "lua_Integer size (32-bit) does not match lua_Number"); -#else - lua_NumberT = C_doubleT; - static_assert(std::is_floating_point::value && - sizeof(lua_Number) == sizeof(double), - "lua_Number is not a double"); - static_assert(sizeof(lua_Integer) == sizeof(lua_Number) && - sizeof(lua_Integer) == sizeof(int64_t), - "lua_Integer size (64-bit) does not match lua_Number"); -#endif - - plua_NumberT = llvm::PointerType::get(lua_NumberT, 0); - pplua_NumberT = llvm::PointerType::get(plua_NumberT, 0); - - static_assert(std::is_integral::value, - "lua_Integer is not an integer type"); - lua_IntegerT = llvm::Type::getIntNTy(context, sizeof(lua_Integer) * 8); - plua_IntegerT = llvm::PointerType::get(lua_IntegerT, 0); - pplua_IntegerT = llvm::PointerType::get(plua_IntegerT, 0); - - static_assert(sizeof(lua_Integer) == sizeof(lua_Unsigned), - "lua_Integer and lua_Unsigned are of different size"); - lua_UnsignedT = lua_IntegerT; - - C_intptr_t = llvm::Type::getIntNTy(context, sizeof(intptr_t) * 8); - C_size_t = llvm::Type::getIntNTy(context, sizeof(size_t) * 8); - C_psize_t = llvm::PointerType::get(C_size_t, 0); - C_ptrdiff_t = llvm::Type::getIntNTy(context, sizeof(ptrdiff_t) * 8); - C_int64_t = llvm::Type::getIntNTy(context, sizeof(int64_t) * 8); - C_intT = llvm::Type::getIntNTy(context, sizeof(int) * 8); - C_pintT = llvm::PointerType::get(C_intT, 0); - C_shortT = llvm::Type::getIntNTy(context, sizeof(short) * 8); - - static_assert(sizeof(size_t) == sizeof(lu_mem), - "lu_mem size is not same as size_t"); - lu_memT = C_size_t; - - static_assert(sizeof(ptrdiff_t) == sizeof(l_mem), - "l_mem size is not same as ptrdiff_t"); - l_memT = C_ptrdiff_t; - - tmsT = C_intT; - - static_assert(sizeof(L_Umaxalign) == sizeof(double), - "L_Umaxalign is not same size as double"); - L_UmaxalignT = C_doubleT; - - static_assert(sizeof(lu_byte) == sizeof(char), - "lu_byte is not same size as char"); - lu_byteT = llvm::Type::getInt8Ty(context); - C_pcharT = llvm::Type::getInt8PtrTy(context); - - static_assert(sizeof(Instruction) == sizeof(int), - "Instruction is not same size as int"); - InstructionT = C_intT; - pInstructionT = llvm::PointerType::get(InstructionT, 0); - - ravitype_tT = llvm::Type::getIntNTy(context, sizeof(ravitype_t) * 8); - - lua_StateT = llvm::StructType::create(context, "struct.lua_State"); - plua_StateT = llvm::PointerType::get(lua_StateT, 0); - - lua_LuaTypeT = C_shortT; // Type for Lua typecode - - lua_KContextT = C_ptrdiff_t; - - std::vector elements; - elements.push_back(plua_StateT); - lua_CFunctionT = llvm::FunctionType::get(C_intT, elements, false); - plua_CFunctionT = llvm::PointerType::get(lua_CFunctionT, 0); - - jitFunctionT = lua_CFunctionT; - - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(C_intT); - elements.push_back(lua_KContextT); - lua_KFunctionT = llvm::FunctionType::get(C_intT, elements, false); - plua_KFunctionT = llvm::PointerType::get(lua_KFunctionT, 0); - - elements.clear(); - elements.push_back(llvm::Type::getInt8PtrTy(context)); - elements.push_back(llvm::Type::getInt8PtrTy(context)); - elements.push_back(C_size_t); - elements.push_back(C_size_t); - lua_AllocT = llvm::FunctionType::get(llvm::Type::getInt8PtrTy(context), - elements, false); - plua_AllocT = llvm::PointerType::get(lua_AllocT, 0); - - lua_DebugT = llvm::StructType::create(context, "struct.lua_Debug"); - plua_DebugT = llvm::PointerType::get(lua_DebugT, 0); - - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(plua_DebugT); - lua_HookT = llvm::FunctionType::get(llvm::Type::getInt8PtrTy(context), - elements, false); - plua_HookT = llvm::PointerType::get(lua_HookT, 0); - - // struct GCObject { - // GCObject *next; - // lu_byte tt; - // lu_byte marked - // }; - GCObjectT = llvm::StructType::create(context, "struct.GCObject"); - pGCObjectT = llvm::PointerType::get(GCObjectT, 0); - elements.clear(); - addCommonGCHeader(elements); - GCObjectT->setBody(elements); - - static_assert(sizeof(Value) == sizeof(lua_Number) && - sizeof(Value) == sizeof(lua_Integer), - "Value type is larger than lua_Number"); - static_assert(sizeof(TValue) == sizeof(lua_Number) * 2, - "TValue type is not 2*sizeof(lua_Number)"); - // In LLVM unions should be set to the largest member - // So in the case of a Value this is the double type - // union Value { - // GCObject *gc; /* collectable objects */ - // void *p; /* light userdata */ - // int b; /* booleans */ - // lua_CFunction f; /* light C functions */ - // lua_Integer i; /* integer numbers */ - // lua_Number n; /* float numbers */ - // }; - ValueT = llvm::StructType::create(context, "union.Value"); - elements.clear(); - elements.push_back(lua_NumberT); - ValueT->setBody(elements); - - // NOTE: Following structure changes when NaN tagging is enabled - // struct TValue { - // union Value value_; - // lu_byte tt_; - // }; - TValueT = llvm::StructType::create(context, "struct.TValue"); - elements.clear(); - elements.push_back(ValueT); - elements.push_back(lua_LuaTypeT); - TValueT->setBody(elements); - pTValueT = llvm::PointerType::get(TValueT, 0); - - StkIdT = pTValueT; - - ///* - //** Header for string value; string bytes follow the end of this structure - //** (aligned according to 'UTString'; see next). - //*/ - - // typedef struct TString { - // GCObject *next; - // lu_byte tt; - // lu_byte marked - // lu_byte extra; /* reserved words for short strings; "has hash" for longs - // */ - // lu_byte shrlen; /* length for short strings */ - // unsigned int hash; - // union { - // size_t lnglen; /* length for long strings */ - // struct TString *hnext; /* linked list for hash table */ - // } u; - // } TString; - - ///* - //** Ensures that address after this type is always fully aligned. - //*/ - // typedef union UTString { - // L_Umaxalign dummy; /* ensures maximum alignment for strings */ - // TString tsv; - //} UTString; - TStringT = llvm::StructType::create(context, "struct.TString"); - pTStringT = llvm::PointerType::get(TStringT, 0); - ppTStringT = llvm::PointerType::get(pTStringT, 0); - elements.clear(); - addCommonGCHeader(elements); - elements.push_back(lu_byteT); /* extra */ - elements.push_back(lu_byteT); /* shrlen */ - elements.push_back(C_intT); /* hash */ - elements.push_back(C_size_t); /* len (as this is the larger member) */ - TStringT->setBody(elements); - - // Table - TableT = llvm::StructType::create(context, "struct.Table"); - pTableT = llvm::PointerType::get(TableT, 0); - ppTableT = llvm::PointerType::get(pTableT, 0); - - ///* - //** Header for userdata; memory area follows the end of this structure - //** (aligned according to 'UUdata'; see next). - //*/ - // typedef struct Udata { - // GCObject *next; - // lu_byte tt; - // lu_byte marked - // LuaType ttuv_; /* user value's tag */ - // struct Table *metatable; - // size_t len; /* number of bytes */ - // union Value user_; /* user value */ - //} Udata; - UdataT = llvm::StructType::create(context, "struct.Udata"); - elements.clear(); - addCommonGCHeader(elements); - elements.push_back(lua_LuaTypeT); /* ttuv_ */ - elements.push_back(pTableT); /* metatable */ - elements.push_back(C_size_t); /* len */ - elements.push_back(ValueT); /* user_ */ - UdataT->setBody(elements); - - ///* - //** Description of an upvalue for function prototypes - //*/ - // typedef struct Upvaldesc { - // TString *name; /* upvalue name (for debug information) */ - // ravitype_t type; - // lu_byte instack; /* whether it is in stack */ - // lu_byte idx; /* index of upvalue (in stack or in outer function's list) - // */ - //}Upvaldesc; - UpvaldescT = llvm::StructType::create(context, "struct.Upvaldesc"); - // FIXME (issue #136) this structure is changing hence better to keep it - // opaque - // elements.clear(); - // elements.push_back(pTStringT); /* name */ - // elements.push_back(ravitype_tT); /* type */ - // elements.push_back(lu_byteT); /* instack */ - // elements.push_back(lu_byteT); /* idx */ - // UpvaldescT->setBody(elements); - pUpvaldescT = llvm::PointerType::get(UpvaldescT, 0); - - ///* - //** Description of a local variable for function prototypes - //** (used for debug information) - //*/ - // typedef struct LocVar { - // TString *varname; - // int startpc; /* first point where variable is active */ - // int endpc; /* first point where variable is dead */ - // ravitype_t ravi_type; /* RAVI type of the variable - RAVI_TANY if unknown - // */ - //} LocVar; - LocVarT = llvm::StructType::create(context, "struct.LocVar"); - // FIXME (issue #136) this structure is changing hence better to keep it - // opaque - // elements.clear(); - // elements.push_back(pTStringT); /* varname */ - // elements.push_back(C_intT); /* startpc */ - // elements.push_back(C_intT); /* endpc */ - // elements.push_back(ravitype_tT); /* ravi_type */ - // LocVarT->setBody(elements); - pLocVarT = llvm::PointerType::get(LocVarT, 0); - - LClosureT = llvm::StructType::create(context, "struct.LClosure"); - pLClosureT = llvm::PointerType::get(LClosureT, 0); - ppLClosureT = llvm::PointerType::get(pLClosureT, 0); - pppLClosureT = llvm::PointerType::get(ppLClosureT, 0); - - RaviJITProtoT = llvm::StructType::create(context, "struct.RaviJITProto"); - elements.clear(); - elements.push_back(lu_byteT); /* jit_status*/ - elements.push_back(lu_byteT); /* jit_flags */ - elements.push_back(C_shortT); /* execution_count */ - elements.push_back(C_pcharT); /* jit_data */ - elements.push_back(plua_CFunctionT); /* jit_function */ - RaviJITProtoT->setBody(elements); - - ///* - //** Function Prototypes - //*/ - // typedef struct Proto { - // CommonHeader; - // lu_byte numparams; /* number of fixed parameters */ - // lu_byte is_vararg; - // lu_byte maxstacksize; /* maximum stack used by this function */ - // int sizeupvalues; /* size of 'upvalues' */ - // int sizek; /* size of 'k' */ - // int sizecode; - // int sizelineinfo; - // int sizep; /* size of 'p' */ - // int sizelocvars; - // int linedefined; - // int lastlinedefined; - // TValue *k; /* constants used by the function */ - // Instruction *code; - // struct Proto **p; /* functions defined inside the function */ - // int *lineinfo; /* map from opcodes to source lines (debug information) */ - // LocVar *locvars; /* information about local variables (debug information) - // */ - // Upvaldesc *upvalues; /* upvalue information */ - // struct LClosure *cache; /* last created closure with this prototype */ - // TString *source; /* used for debug information */ - // GCObject *gclist; - // /* RAVI */ - // RaviJITProto ravi_jit; - //} Proto; - - ProtoT = llvm::StructType::create(context, "struct.Proto"); - pProtoT = llvm::PointerType::get(ProtoT, 0); - ppProtoT = llvm::PointerType::get(pProtoT, 0); - elements.clear(); - addCommonGCHeader(elements); - elements.push_back(lu_byteT); /* numparams */ - elements.push_back(lu_byteT); /* is_vararg */ - elements.push_back(lu_byteT); /* maxstacksize */ - elements.push_back(C_intT); /* sizeupvalues */ - elements.push_back(C_intT); /* sizek */ - elements.push_back(C_intT); /* sizecode */ - elements.push_back(C_intT); /* sizelineinfo */ - elements.push_back(C_intT); /* sizep */ - elements.push_back(C_intT); /* sizelocvars */ - elements.push_back(C_intT); /* linedefined */ - elements.push_back(C_intT); /* lastlinedefined */ - elements.push_back(pTValueT); /* k */ - elements.push_back(pInstructionT); /* code */ - elements.push_back(ppProtoT); /* p */ - elements.push_back(llvm::PointerType::get(C_intT, 0)); /* lineinfo */ - elements.push_back(pLocVarT); /* locvars */ - elements.push_back(pUpvaldescT); /* upvalues */ - elements.push_back(pLClosureT); /* cache */ - elements.push_back(pTStringT); /* source */ - elements.push_back(pGCObjectT); /* gclist */ - elements.push_back(RaviJITProtoT); /* ravi_jit */ - ProtoT->setBody(elements); - - ///* - //** Lua Upvalues - //*/ - // typedef struct UpVal UpVal; - UpValT = llvm::StructType::create(context, "struct.UpVal"); - pUpValT = llvm::PointerType::get(UpValT, 0); - - ///* - //** Closures - //*/ - - //#define ClosureHeader CommonHeader; lu_byte nupvalues; GCObject *gclist - - // typedef struct CClosure { - // ClosureHeader; - // lua_CFunction f; - // TValue upvalue[1]; /* list of upvalues */ - //} CClosure; - - CClosureT = llvm::StructType::create(context, "struct.CClosure"); - elements.clear(); - addCommonGCHeader(elements); - elements.push_back(lu_byteT); /* nupvalues */ - elements.push_back(pGCObjectT); /* gclist */ - elements.push_back(plua_CFunctionT); /* f */ - elements.push_back(llvm::ArrayType::get(TValueT, 1)); - CClosureT->setBody(elements); - pCClosureT = llvm::PointerType::get(CClosureT, 0); - - // typedef struct LClosure { - // ClosureHeader; - // struct Proto *p; - // UpVal *upvals[1]; /* list of upvalues */ - //} LClosure; - elements.clear(); - addCommonGCHeader(elements); - elements.push_back(lu_byteT); /* nupvalues */ - elements.push_back(pGCObjectT); /* gclist */ - elements.push_back(pProtoT); /* p */ - elements.push_back(llvm::ArrayType::get(pUpValT, 1)); - LClosureT->setBody(elements); - - ///* - //** Tables - //*/ - - // NOTE following structure changes when NaN Tagging is enabled - - // typedef union TKey { - // struct { - // TValuefields; - // int next; /* for chaining (offset for next node) */ - // } nk; - // TValue tvk; - //} TKey; - TKeyT = llvm::StructType::create(context, "struct.TKey"); - elements.clear(); - elements.push_back(ValueT); - elements.push_back(lua_LuaTypeT); - elements.push_back(C_intT); /* next */ - TKeyT->setBody(elements); - pTKeyT = llvm::PointerType::get(TKeyT, 0); - - // typedef struct Node { - // TValue i_val; - // TKey i_key; - //} Node; - NodeT = llvm::StructType::create(context, "struct.Node"); - elements.clear(); - elements.push_back(TValueT); /* i_val */ - elements.push_back(TKeyT); /* i_key */ - NodeT->setBody(elements); - pNodeT = llvm::PointerType::get(NodeT, 0); - - //struct RaviArray { - // CommonHeader; - // lu_byte flags; - // unsigned int len; /* array length, holds real length which is 1+Lua length */ - // unsigned int size; /* size of data, in arrays (not slices) if == RAVI_ARRAY_MAX_INLINE then it means we are using inline storage */ - // union { - // lua_Number numarray[RAVI_ARRAY_MAX_INLINE]; - // lua_Integer intarray[RAVI_ARRAY_MAX_INLINE]; - // struct RaviArray* parent; /* Only set if this is a slice, parent must be a slice or a fixed length array */ - // }; - // char* data; /* Pointer to data. In case of slices points in parent->data. In case of arrays this may point to heap or internal data */ - // struct Table* metatable; - //} - RaviArrayT = llvm::StructType::create(context, "struct.RaviArray"); - elements.clear(); - addCommonGCHeader(elements); - elements.push_back(lu_byteT); /* flags */ - elements.push_back(C_intT); /* len - 4 */ - elements.push_back(C_intT); /* size */ - elements.push_back(llvm::ArrayType::get(lua_NumberT, RAVI_ARRAY_MAX_INLINE)); /* numarray: Assumption: lua_Number and lua_Integer have same size */ - elements.push_back(C_pcharT); /* data - 7 */ - elements.push_back(pTableT); /* metatable*/ - RaviArrayT->setBody(elements); - pRaviArrayT = llvm::PointerType::get(RaviArrayT, 0); - ppRaviArrayT = llvm::PointerType::get(pRaviArrayT, 0); - - - // typedef struct Table { - // CommonHeader; - // lu_byte flags; /* 1<

setBody(elements); - - // struct lua_longjmp; /* defined in ldo.c */ - lua_longjumpT = llvm::StructType::create(context, "struct.lua_longjmp"); - plua_longjumpT = llvm::PointerType::get(lua_longjumpT, 0); - - // lzio.h - // typedef struct Mbuffer { - // char *buffer; - // size_t n; - // size_t buffsize; - //} Mbuffer; - MbufferT = llvm::StructType::create(context, "struct.Mbuffer"); - elements.clear(); - elements.push_back(llvm::Type::getInt8PtrTy(context)); /* buffer */ - elements.push_back(C_size_t); /* n */ - elements.push_back(C_size_t); /* buffsize */ - MbufferT->setBody(elements); - - // typedef struct stringtable { - // TString **hash; - // int nuse; /* number of elements */ - // int size; - //} stringtable; - stringtableT = llvm::StructType::create(context, "struct.stringtable"); - elements.clear(); - elements.push_back(ppTStringT); /* hash */ - elements.push_back(C_intT); /* nuse */ - elements.push_back(C_intT); /* size */ - stringtableT->setBody(elements); - - ///* - //** Information about a call. - //** When a thread yields, 'func' is adjusted to pretend that the - //** top function has only the yielded values in its stack; in that - //** case, the actual 'func' value is saved in field 'extra'. - //** When a function calls another with a continuation, 'extra' keeps - //** the function index so that, in case of errors, the continuation - //** function can be called with the correct top. - //*/ - // typedef struct CallInfo { - // StkId func; /* function index in the stack */ - // StkId top; /* top for this function */ - // struct CallInfo *previous, *next; /* dynamic call link */ - // union { - // struct { /* only for Lua functions */ - // StkId base; /* base for this function */ - // const Instruction *savedpc; - // } l; - // struct { /* only for C functions */ - // lua_KFunction k; /* continuation in case of yields */ - // ptrdiff_t old_errfunc; - // lua_KContext ctx; /* context info. in case of yields */ - // } c; - // } u; - // ptrdiff_t extra; - // short nresults; /* expected number of results from this function */ - // unsigned short callstatus; - // unsigned short stacklevel; /* Ravi extension - stack level, bottom level - // is 0 */ - // lu_byte jitstatus; /* Only valid if Lua function - if 1 means JITed - RAVI - // extension */ - //} CallInfo; - - elements.clear(); - elements.push_back(StkIdT); /* base */ - elements.push_back(pInstructionT); /* savedpc */ - elements.push_back( - C_ptrdiff_t); /* dummy to make this same size as the other member */ - CallInfo_lT = llvm::StructType::create(elements); - - elements.clear(); - elements.push_back(plua_KFunctionT); /* k */ - elements.push_back(C_ptrdiff_t); /* old_errfunc */ - elements.push_back(lua_KContextT); /* ctx */ - CallInfo_cT = llvm::StructType::create(elements); - - CallInfoT = llvm::StructType::create(context, "struct.CallInfo"); - pCallInfoT = llvm::PointerType::get(CallInfoT, 0); - elements.clear(); - elements.push_back(StkIdT); /* func */ - elements.push_back(StkIdT); /* top */ - elements.push_back(pCallInfoT); /* previous */ - elements.push_back(pCallInfoT); /* next */ - elements.push_back( - CallInfo_lT); /* u.l - as we will typically access the lua call details - */ - elements.push_back(C_ptrdiff_t); /* extra */ - elements.push_back(C_shortT); /* nresults */ - elements.push_back(C_shortT); /* callstatus */ - elements.push_back(C_shortT); /* stacklevel RAVI extension */ - elements.push_back(lu_byteT); /* jitstatus RAVI extension*/ - elements.push_back(lu_byteT); /* magic */ - CallInfoT->setBody(elements); - - // typedef struct ravi_State ravi_State; - - ravi_StateT = llvm::StructType::create(context, "struct.ravi_State"); - pravi_StateT = llvm::PointerType::get(ravi_StateT, 0); - - ///* - //** 'global state', shared by all threads of this state - //*/ - // typedef struct global_State { - // lua_Alloc frealloc; /* function to reallocate memory */ - // void *ud; /* auxiliary data to 'frealloc' */ - // lu_mem totalbytes; /* number of bytes currently allocated - GCdebt */ - // l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ - // lu_mem GCmemtrav; /* memory traversed by the GC */ - // lu_mem GCestimate; /* an estimate of the non-garbage memory in use */ - // stringtable strt; /* hash table for strings */ - // TValue l_registry; - // unsigned int seed; /* randomized seed for hashes */ - // lu_byte currentwhite; - // lu_byte gcstate; /* state of garbage collector */ - // lu_byte gckind; /* kind of GC running */ - // lu_byte gcrunning; /* true if GC is running */ - // GCObject *allgc; /* list of all collectable objects */ - // GCObject **sweepgc; /* current position of sweep in list */ - // GCObject *finobj; /* list of collectable objects with finalizers */ - // GCObject *gray; /* list of gray objects */ - // GCObject *grayagain; /* list of objects to be traversed atomically */ - // GCObject *weak; /* list of tables with weak values */ - // GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ - // GCObject *allweak; /* list of all-weak tables */ - // GCObject *tobefnz; /* list of userdata to be GC */ - // GCObject *fixedgc; /* list of objects not to be collected */ - // struct lua_State *twups; /* list of threads with open upvalues */ - // Mbuffer buff; /* temporary buffer for string concatenation */ - // unsigned int gcfinnum; /* number of finalizers to call in each GC step */ - // int gcpause; /* size of pause between successive GCs */ - // int gcstepmul; /* GC 'granularity' */ - // lua_CFunction panic; /* to be called in unprotected errors */ - // struct lua_State *mainthread; - // const lua_Number *version; /* pointer to version number */ - // TString *memerrmsg; /* memory-error message */ - // TString *tmname[TM_N]; /* array with tag-method names */ - // struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */ - // TString *strcache[STRCACHE_SIZE][1]; /* cache for strings in API */ - // /* RAVI */ - // ravi_State *ravi_state; - //} global_State; - - global_StateT = llvm::StructType::create(context, "struct.global_State"); - pglobal_StateT = llvm::PointerType::get(global_StateT, 0); - - ///* - //** 'per thread' state - //*/ - // struct lua_State { - // CommonHeader; - // lu_byte status; - // StkId top; /* first free slot in the stack */ - // global_State *l_G; - // CallInfo *ci; /* call info for current function */ - // const Instruction *oldpc; /* last pc traced */ - // StkId stack_last; /* last free slot in the stack */ - // StkId stack; /* stack base */ - // UpVal *openupval; /* list of open upvalues in this stack */ - // GCObject *gclist; - // struct lua_State *twups; /* list of threads with open upvalues */ - // struct lua_longjmp *errorJmp; /* current error recover point */ - // CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ - // lua_Hook hook; - // ptrdiff_t errfunc; /* current error handling function (stack index) */ - // int stacksize; - // int basehookcount; - // int hookcount; - // unsigned short nny; /* number of non-yieldable calls in stack */ - // unsigned short nCcalls; /* number of nested C calls */ - // lu_byte hookmask; - // lu_byte allowhook; - // unsigned short nci; /* number of items in 'ci' list */ - // lu_byte magic; - //}; - elements.clear(); - addCommonGCHeader(elements); - elements.push_back(lu_byteT); /* status */ - elements.push_back(StkIdT); /* top */ - elements.push_back(pglobal_StateT); /* l_G */ - elements.push_back(pCallInfoT); /* ci */ - elements.push_back(pInstructionT); /* oldpc */ - elements.push_back(StkIdT); /* stack_last */ - elements.push_back(StkIdT); /* stack */ - elements.push_back(pUpValT); /* openupval */ - elements.push_back(pGCObjectT); /* gclist */ - elements.push_back(plua_StateT); /* twups */ - elements.push_back(plua_longjumpT); /* errorJmp */ - elements.push_back(CallInfoT); /* base_ci */ - elements.push_back(plua_HookT); /* hook */ - elements.push_back(C_ptrdiff_t); /* errfunc */ - elements.push_back(C_intT); /* stacksize */ - elements.push_back(C_intT); /* basehookcount */ - elements.push_back(C_intT); /* hookcount */ - elements.push_back(C_shortT); /* nny */ - elements.push_back(C_shortT); /* nCcalls */ - elements.push_back(lu_byteT); /* hookmask */ - elements.push_back(lu_byteT); /* allowhook */ - elements.push_back(C_shortT); - elements.push_back(lu_byteT); - lua_StateT->setBody(elements); - - // struct UpVal { - // struct TValue *v; /* points to stack or to its own value */ -#ifdef RAVI_DEFER_STATEMENT - // unsigned int refcount; /* reference counter */ - // unsigned int flags; /* Used to mark deferred values */ -#else - // unsigned long long refcount; /* reference counter */ -#endif - // union { - // struct { /* (when open) */ - // struct UpVal *next; /* linked list */ - // int touched; /* mark to avoid cycles with dead threads */ - // } open; - // struct TValue value; /* the value (when closed) */ - // } u; - //}; - elements.clear(); - elements.push_back(pTValueT); -#ifdef RAVI_DEFER_STATEMENT - elements.push_back(C_intT); - elements.push_back(C_intT); -#else - elements.push_back(C_size_t); -#endif - elements.push_back(TValueT); - UpValT->setBody(elements); - - // int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres); - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(pCallInfoT); - elements.push_back(StkIdT); - elements.push_back(C_intT); - luaD_poscallT = llvm::FunctionType::get(C_intT, elements, false); - - // void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(pUpValT); - luaC_upvalbarrierT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - - // int luaD_precall (lua_State *L, StkId func, int nresults, int op_call); - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(StkIdT); - elements.push_back(C_intT); - elements.push_back(C_intT); - luaD_precallT = llvm::FunctionType::get(C_intT, elements, false); - - // void luaD_call (lua_State *L, StkId func, int nResults); - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(StkIdT); - elements.push_back(C_intT); - luaD_callT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - - // int luaV_execute(lua_State L); - elements.clear(); - elements.push_back(plua_StateT); - luaV_executeT = llvm::FunctionType::get(C_intT, elements, false); - -#ifdef RAVI_DEFER_STATEMENT - // int luaF_close (lua_State *L, StkId level, int status) -#else - // void luaF_close (lua_State *L, StkId level) -#endif - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(StkIdT); -#ifdef RAVI_DEFER_STATEMENT - elements.push_back(C_intT); - luaF_closeT = - llvm::FunctionType::get(C_intT, elements, false); -#else - luaF_closeT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); -#endif - - // int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(pTValueT); -#ifdef RAVI_DEFER_STATEMENT - // void raviV_op_defer(lua_State *L, TValue *ra); - raviV_op_deferT = llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); -#endif - elements.push_back(pTValueT); - luaV_equalobjT = llvm::FunctionType::get(C_intT, elements, false); - - // int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) - luaV_lessthanT = llvm::FunctionType::get(C_intT, elements, false); - - // int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) - luaV_lessequalT = llvm::FunctionType::get(C_intT, elements, false); - - // void raviV_op_totype(lua_State *L, TValue *ra, TValue *rb); - raviV_op_totypeT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - - // l_noret luaG_runerror (lua_State *L, const char *fmt, ...) - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(C_pcharT); - luaG_runerrorT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, true); - - // int luaV_forlimit (const TValue *obj, lua_Integer *p, lua_Integer step, - // int *stopnow) - elements.clear(); - elements.push_back(pTValueT); - elements.push_back(plua_IntegerT); - elements.push_back(lua_IntegerT); - elements.push_back(C_pintT); - luaV_forlimitT = llvm::FunctionType::get(C_intT, elements, false); - - // int luaV_tonumber_ (const TValue *obj, lua_Number *n) - elements.clear(); - elements.push_back(pTValueT); - elements.push_back(plua_NumberT); - luaV_tonumberT = llvm::FunctionType::get(C_intT, elements, false); - - // int luaV_tointeger_ (const TValue *obj, lua_Integer *p) - elements.clear(); - elements.push_back(pTValueT); - elements.push_back(plua_IntegerT); - luaV_tointegerT = llvm::FunctionType::get(C_intT, elements, false); - - // void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(pTValueT); - elements.push_back(pTValueT); - luaV_objlenT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - - // void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) - elements.push_back(pTValueT); - luaV_gettableT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - // void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) - luaV_settableT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - raviV_gettable_sskeyT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - raviV_settable_sskeyT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - raviV_gettable_iT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - raviV_settable_iT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - - // void luaV_finishget (lua_State *L, const TValue *t, TValue *key, - // StkId val, const TValue *slot); - elements.push_back(pTValueT); - luaV_finishgetT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - - // void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, - // StkId res, TMS event); - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(pTValueT); - elements.push_back(pTValueT); - elements.push_back(pTValueT); - elements.push_back(tmsT); - luaT_trybinTMT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - - // void raviV_op_loadnil(CallInfo *ci, int a, int b) - elements.clear(); - elements.push_back(pCallInfoT); - elements.push_back(C_intT); - elements.push_back(C_intT); - raviV_op_loadnilT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - - // void raviV_op_newarrayint(lua_State *L, CallInfo *ci, TValue *ra) - // void raviV_op_newarrayfloat(lua_State *L, CallInfo *ci, TValue *ra) - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(pCallInfoT); - elements.push_back(pTValueT); - raviV_op_newarrayintT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - raviV_op_newarrayfloatT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - - // void raviV_op_newtable(lua_State *L, CallInfo *ci, TValue *ra, int b, int - // c) - // void raviV_op_setlist(lua_State *L, CallInfo *ci, TValue *ra, int b, int c) - elements.push_back(C_intT); - elements.push_back(C_intT); - raviV_op_newtableT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - raviV_op_setlistT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - - // lua_Integer luaV_idiv (lua_State *L, lua_Integer m, lua_Integer n) - // lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(lua_IntegerT); - elements.push_back(lua_IntegerT); - luaV_modT = llvm::FunctionType::get(lua_IntegerT, elements, false); - luaV_idivT = llvm::FunctionType::get(lua_IntegerT, elements, false); - - // void raviV_op_concat(lua_State *L, CallInfo *ci, int a, int b, int c) - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(pCallInfoT); - elements.push_back(C_intT); - elements.push_back(C_intT); - elements.push_back(C_intT); - raviV_op_concatT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - - // void raviV_op_closure(lua_State *L, CallInfo *ci, LClosure *cl, int a, int - // Bx) - // void raviV_op_vararg(lua_State *L, CallInfo *ci, LClosure *cl, int a, int - // b) - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(pCallInfoT); - elements.push_back(pLClosureT); - elements.push_back(C_intT); - elements.push_back(C_intT); - raviV_op_closureT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - raviV_op_varargT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - - // void raviV_op_setupvali(lua_State *L, LClosure *cl, TValue *ra, int b); - // void raviV_op_setupvalf(lua_State *L, LClosure *cl, TValue *ra, int b); - // void raviV_op_setupvalai(lua_State *L, LClosure *cl, TValue *ra, int b); - // void raviV_op_setupvalaf(lua_State *L, LClosure *cl, TValue *ra, int b); - // void raviV_op_setupvalt(lua_State *L, LClosure *cl, TValue *ra, int b); - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(pLClosureT); - elements.push_back(pTValueT); - elements.push_back(C_intT); - raviV_op_setupvaliT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - raviV_op_setupvalfT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - raviV_op_setupvalaiT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - raviV_op_setupvalafT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - raviV_op_setupvaltT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - - // void raviV_op_bor(lua_State *L, TValue *ra, TValue *rb, TValue *rc); - // void raviV_op_bxor(lua_State *L, TValue *ra, TValue *rb, TValue *rc); - // void raviV_op_band(lua_State *L, TValue *ra, TValue *rb, TValue *rc); - // void raviV_op_bnot(lua_State *L, TValue *ra, TValue *rb); - // void raviV_op_shl(lua_State *L, TValue *ra, TValue *rb, TValue *rc); - // void raviV_op_shr(lua_State *L, TValue *ra, TValue *rb, TValue *rc); - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(pTValueT); - elements.push_back(pTValueT); - raviV_op_bnotT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - elements.push_back(pTValueT); - raviV_op_shlT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - raviV_op_shrT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - raviV_op_borT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - raviV_op_bxorT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - raviV_op_bandT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - raviV_op_addT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - raviV_op_subT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - raviV_op_mulT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - raviV_op_divT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - - // const TValue *luaH_getint(Table *t, lua_Integer key); - elements.clear(); - elements.push_back(pTableT); - elements.push_back(lua_IntegerT); - luaH_getintT = llvm::FunctionType::get(pTValueT, elements, false); - - // void luaH_setint(lua_State *L, Table *t, lua_Integer key, TValue *value); - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(pTableT); - elements.push_back(lua_IntegerT); - elements.push_back(pTValueT); - luaH_setintT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - - // const TValue *luaH_getstr(Table *t, TString *key); - elements.clear(); - elements.push_back(pTableT); - elements.push_back(pTStringT); - luaH_getstrT = llvm::FunctionType::get(pTValueT, elements, false); - - // void raviH_set_int(lua_State *L, RaviArray *t, lua_Unsigned key, lua_Integer - // value); - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(pRaviArrayT); - elements.push_back(lua_UnsignedT); - elements.push_back(lua_IntegerT); - raviH_set_intT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - - // void raviH_set_float(lua_State *L, RaviArray *t, lua_Unsigned key, lua_Number - // value); - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(pRaviArrayT); - elements.push_back(lua_UnsignedT); - elements.push_back(lua_NumberT); - raviH_set_floatT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - -#if 0 - // DEBUG tools - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(pTValueT); - ravi_dump_valueT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(C_pcharT); - ravi_dump_stackT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - ravi_dump_stacktopT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - -#endif - elements.clear(); - elements.push_back(plua_StateT); - elements.push_back(C_intT); - elements.push_back(C_intT); - ravi_debug_traceT = - llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); - - for (int j = 0; j < kInt.size(); j++) - kInt[j] = llvm::ConstantInt::get(C_intT, j); - for (int j = 0; j < kluaInteger.size(); j++) - kluaInteger[j] = llvm::ConstantInt::get(lua_IntegerT, j); - kFalse = llvm::ConstantInt::getFalse(llvm::Type::getInt1Ty(context)); - - // Do what Clang does - //! 5 = metadata !{metadata !"Simple C/C++ TBAA"} - tbaa_root = mdbuilder.createTBAARoot("Simple C / C++ TBAA"); - - //! 4 = metadata !{metadata !"omnipotent char", metadata !5, i64 0} - tbaa_charT = - mdbuilder.createTBAAScalarTypeNode("omnipotent char", tbaa_root, 0); - tbaa_pcharT = mdbuilder.createTBAAStructTagNode(tbaa_charT, tbaa_charT, 0); - - //! 3 = metadata !{metadata !"any pointer", metadata !4, i64 0} - tbaa_pointerT = - mdbuilder.createTBAAScalarTypeNode("any pointer", tbaa_charT, 0); - tbaa_ppointerT = - mdbuilder.createTBAAStructTagNode(tbaa_pointerT, tbaa_pointerT, 0); - - //! 10 = metadata !{metadata !"short", metadata !4, i64 0} - tbaa_shortT = mdbuilder.createTBAAScalarTypeNode("short", tbaa_charT, 0); - tbaa_pshortT = mdbuilder.createTBAAStructTagNode(tbaa_shortT, tbaa_shortT, 0); - - //! 11 = metadata !{metadata !"int", metadata !4, i64 0} - tbaa_intT = mdbuilder.createTBAAScalarTypeNode("int", tbaa_charT, 0); - tbaa_pintT = mdbuilder.createTBAAStructTagNode(tbaa_intT, tbaa_intT, 0); - - //! 9 = metadata !{metadata !"long long", metadata !4, i64 0} - tbaa_longlongT = - mdbuilder.createTBAAScalarTypeNode("long long", tbaa_charT, 0); - tbaa_plonglongT = - mdbuilder.createTBAAStructTagNode(tbaa_longlongT, tbaa_longlongT, 0); - - tbaa_doubleT = mdbuilder.createTBAAScalarTypeNode("double", tbaa_charT, 0); - tbaa_pdoubleT = - mdbuilder.createTBAAStructTagNode(tbaa_doubleT, tbaa_doubleT, 0); - - //! 14 = metadata !{metadata !"CallInfoL", metadata !3, i64 0, metadata !3, - //! i64 - // 4, metadata !9, i64 8} - std::vector> nodes; - nodes.push_back(std::pair(tbaa_pointerT, 0)); - nodes.push_back(std::pair(tbaa_pointerT, 4)); - nodes.push_back(std::pair(tbaa_longlongT, 8)); - tbaa_CallInfo_lT = mdbuilder.createTBAAStructTypeNode("CallInfo_l", nodes); - - //! 13 = metadata !{metadata !"CallInfoLua", - // metadata !3, i64 0, metadata !3, i64 4, metadata !3, i64 8, - // metadata !3, i64 12, metadata !14, i64 16, metadata !9, i64 - // 32, - // metadata !10, i64 40, metadata !4, i64 42} - nodes.clear(); - nodes.push_back( - std::pair(tbaa_pointerT, 0)); // func - nodes.push_back( - std::pair(tbaa_pointerT, 4)); // top - nodes.push_back( - std::pair(tbaa_pointerT, 8)); // previous - nodes.push_back( - std::pair(tbaa_pointerT, 12)); // next - nodes.push_back( - std::pair(tbaa_CallInfo_lT, 16)); // l - nodes.push_back( - std::pair(tbaa_longlongT, 32)); // extra - nodes.push_back( - std::pair(tbaa_shortT, 40)); // nresults - nodes.push_back( - std::pair(tbaa_shortT, 42)); // callstatus - nodes.push_back( - std::pair(tbaa_shortT, 44)); // stacklevel - nodes.push_back( - std::pair(tbaa_charT, 46)); // jitstatus - tbaa_CallInfoT = mdbuilder.createTBAAStructTypeNode("CallInfo", nodes); - - //! 7 = metadata !{metadata !"lua_State", - // metadata !3, i64 0, metadata !4, i64 4, metadata !4, i64 5, - // metadata !4, i64 6, metadata !3, i64 8, metadata !3, i64 12, - // metadata !3, i64 16, metadata !3, i64 20, metadata !3, i64 - // 24, - // metadata !3, i64 28, metadata !3, i64 32, metadata !3, i64 - // 36, - // metadata !3, i64 40, metadata !3, i64 44, metadata !8, i64 - // 48, - // metadata !3, i64 104, metadata !9, i64 112, metadata !11, - // i64 120, - // metadata !11, i64 124, metadata !11, i64 128, metadata !10, - // i64 132, - // metadata !10, i64 134, metadata !4, i64 136, metadata !4, - // i64 137} - nodes.clear(); - nodes.push_back(std::pair(tbaa_pointerT, 0)); - nodes.push_back(std::pair(tbaa_charT, 4)); - nodes.push_back(std::pair(tbaa_charT, 5)); - nodes.push_back(std::pair(tbaa_charT, 6)); - nodes.push_back(std::pair(tbaa_pointerT, 8)); - nodes.push_back(std::pair(tbaa_pointerT, 12)); - nodes.push_back(std::pair(tbaa_pointerT, 16)); - nodes.push_back(std::pair(tbaa_pointerT, 20)); - nodes.push_back(std::pair(tbaa_pointerT, 24)); - nodes.push_back(std::pair(tbaa_pointerT, 28)); - nodes.push_back(std::pair(tbaa_pointerT, 32)); - nodes.push_back(std::pair(tbaa_pointerT, 36)); - nodes.push_back(std::pair(tbaa_pointerT, 40)); - nodes.push_back(std::pair(tbaa_pointerT, 44)); - nodes.push_back(std::pair(tbaa_CallInfoT, 48)); - nodes.push_back(std::pair(tbaa_pointerT, 92)); - nodes.push_back(std::pair(tbaa_longlongT, 96)); - nodes.push_back(std::pair(tbaa_intT, 104)); - nodes.push_back(std::pair(tbaa_intT, 108)); - nodes.push_back(std::pair(tbaa_intT, 112)); - nodes.push_back(std::pair(tbaa_shortT, 114)); - nodes.push_back(std::pair(tbaa_shortT, 116)); - nodes.push_back(std::pair(tbaa_charT, 118)); - nodes.push_back(std::pair(tbaa_charT, 119)); - nodes.push_back(std::pair(tbaa_shortT, 120)); - tbaa_luaStateT = mdbuilder.createTBAAStructTypeNode("lua_State", nodes); - - tbaa_luaState_ciT = - mdbuilder.createTBAAStructTagNode(tbaa_luaStateT, tbaa_pointerT, 16); - tbaa_luaState_ci_baseT = - mdbuilder.createTBAAStructTagNode(tbaa_CallInfoT, tbaa_pointerT, 16); - tbaa_CallInfo_funcT = - mdbuilder.createTBAAStructTagNode(tbaa_CallInfoT, tbaa_pointerT, 0); - tbaa_CallInfo_func_LClosureT = - mdbuilder.createTBAAStructTagNode(tbaa_pointerT, tbaa_pointerT, 0); - tbaa_CallInfo_topT = - mdbuilder.createTBAAStructTagNode(tbaa_CallInfoT, tbaa_pointerT, 4); - tbaa_CallInfo_savedpcT = - mdbuilder.createTBAAStructTagNode(tbaa_CallInfoT, tbaa_pointerT, 20); - tbaa_CallInfo_callstatusT = - mdbuilder.createTBAAStructTagNode(tbaa_CallInfoT, tbaa_shortT, 42); - tbaa_CallInfo_jitstatusT = - mdbuilder.createTBAAStructTagNode(tbaa_CallInfoT, tbaa_charT, 46); - - //! 20 = metadata !{metadata !"Proto", - // metadata !3, i64 0, metadata !4, i64 4, metadata !4, i64 5, - // metadata !4, i64 6, metadata !4, i64 7, metadata !4, i64 8, - // metadata !11, i64 12, metadata !11, i64 16, metadata !11, - // i64 20, - // metadata !11, i64 24, metadata !11, i64 28, metadata !11, - // i64 32, - // metadata !11, i64 36, metadata !11, i64 40, metadata !3, - // i64 44, - // metadata !3, i64 48, metadata !3, i64 52, metadata !3, i64 - // 56, - // metadata !3, i64 60, metadata !3, i64 64, metadata !3, i64 - // 68, - // metadata !3, i64 72, metadata !3, i64 76} - nodes.clear(); - nodes.push_back( - std::pair(tbaa_pointerT, 0)); // next - nodes.push_back(std::pair(tbaa_charT, 4)); // tt - nodes.push_back( - std::pair(tbaa_charT, 5)); // marked - nodes.push_back( - std::pair(tbaa_charT, 6)); // numparams - nodes.push_back( - std::pair(tbaa_charT, 7)); // is_vararg - nodes.push_back( - std::pair(tbaa_charT, 8)); // maxstacksize - nodes.push_back( - std::pair(tbaa_intT, 12)); // sizeupvalues - nodes.push_back(std::pair(tbaa_intT, 16)); // sizek - nodes.push_back( - std::pair(tbaa_intT, 20)); // sizecode - nodes.push_back( - std::pair(tbaa_intT, 24)); // sizelineinfo - nodes.push_back(std::pair(tbaa_intT, 28)); // sizep - nodes.push_back( - std::pair(tbaa_intT, 32)); // sizelocvars - nodes.push_back( - std::pair(tbaa_intT, 36)); // linedefined - nodes.push_back( - std::pair(tbaa_intT, 40)); // lastlinedefined - nodes.push_back(std::pair(tbaa_pointerT, 44)); // k - nodes.push_back( - std::pair(tbaa_pointerT, 48)); // code - nodes.push_back(std::pair(tbaa_pointerT, 52)); // p - nodes.push_back( - std::pair(tbaa_pointerT, 56)); // lineinfo - nodes.push_back( - std::pair(tbaa_pointerT, 60)); // locvars - nodes.push_back( - std::pair(tbaa_pointerT, 64)); // upvalues - nodes.push_back( - std::pair(tbaa_pointerT, 68)); // cache - nodes.push_back( - std::pair(tbaa_pointerT, 72)); // source - nodes.push_back( - std::pair(tbaa_pointerT, 76)); // gclist - nodes.push_back( - std::pair(tbaa_charT, 80)); // ravi_jit - tbaa_ProtoT = mdbuilder.createTBAAStructTypeNode("Proto", nodes); - - //! 18 = metadata !{metadata !"LClosure", - // metadata !3, i64 0, metadata !4, i64 4, metadata !4, i64 5, - // metadata !4, i64 6, metadata !3, i64 8, metadata !3, i64 - // 12, - // metadata !4, i64 16} - nodes.clear(); - nodes.push_back(std::pair(tbaa_pointerT, 0)); - nodes.push_back(std::pair(tbaa_charT, 4)); - nodes.push_back(std::pair(tbaa_charT, 5)); - nodes.push_back(std::pair(tbaa_charT, 6)); - nodes.push_back(std::pair(tbaa_pointerT, 8)); - nodes.push_back(std::pair(tbaa_pointerT, 12)); - nodes.push_back(std::pair(tbaa_pointerT, 16)); - tbaa_LClosureT = mdbuilder.createTBAAStructTypeNode("LClosure", nodes); - - tbaa_LClosure_pT = - mdbuilder.createTBAAStructTagNode(tbaa_LClosureT, tbaa_pointerT, 12); - tbaa_LClosure_upvalsT = - mdbuilder.createTBAAStructTagNode(tbaa_LClosureT, tbaa_pointerT, 16); - - tbaa_Proto_kT = - mdbuilder.createTBAAStructTagNode(tbaa_ProtoT, tbaa_pointerT, 44); - tbaa_Proto_sizepT = - mdbuilder.createTBAAStructTagNode(tbaa_ProtoT, tbaa_intT, 28); - tbaa_Proto_codeT = - mdbuilder.createTBAAStructTagNode(tbaa_ProtoT, tbaa_pointerT, 48); - - nodes.clear(); - nodes.push_back(std::pair(tbaa_longlongT, 0)); - nodes.push_back(std::pair(tbaa_shortT, 8)); - tbaa_TValueT = mdbuilder.createTBAAStructTypeNode("TValue", nodes); - - tbaa_TValue_nT = - mdbuilder.createTBAAStructTagNode(tbaa_TValueT, tbaa_longlongT, 0); - tbaa_TValue_hT = - mdbuilder.createTBAAStructTagNode(tbaa_pointerT, tbaa_pointerT, 0); - tbaa_TValue_ttT = - mdbuilder.createTBAAStructTagNode(tbaa_TValueT, tbaa_shortT, 8); - - tbaa_luaState_topT = - mdbuilder.createTBAAStructTagNode(tbaa_luaStateT, tbaa_pointerT, 8); - - nodes.clear(); - nodes.push_back(std::pair(tbaa_pointerT, 0)); -#ifdef RAVI_DEFER_STATEMENT - nodes.push_back(std::pair(tbaa_intT, 4)); - nodes.push_back(std::pair(tbaa_intT, 4)); -#else - nodes.push_back(std::pair(tbaa_longlongT, 8)); -#endif - nodes.push_back(std::pair(tbaa_TValueT, 16)); - tbaa_UpValT = mdbuilder.createTBAAStructTypeNode("UpVal", nodes); - tbaa_UpVal_vT = - - mdbuilder.createTBAAStructTagNode(tbaa_UpValT, tbaa_pointerT, 0); - - // !{!"RaviArray", !5, i64 0, !6, i64 4, !6, i64 5, !6, i64 6, !11, i64 8, !11, i64 12, !6, i64 16, !5, i64 40, !5, i64 44} - nodes.clear(); - nodes.push_back(std::pair(tbaa_pointerT, 0)); /* next */ - nodes.push_back(std::pair(tbaa_charT, 4)); /* tt */ - nodes.push_back(std::pair(tbaa_charT, 5)); /* marked */ - nodes.push_back(std::pair(tbaa_charT, 6)); /* flags */ - nodes.push_back(std::pair(tbaa_intT, 8)); /* len */ - nodes.push_back(std::pair(tbaa_intT, 12)); /* size */ - nodes.push_back(std::pair(tbaa_charT, 16)); /* numarray */ - nodes.push_back(std::pair(tbaa_pointerT, 40)); /* data */ - nodes.push_back(std::pair(tbaa_pointerT, 44)); /* metatable */ - tbaa_RaviArrayT = mdbuilder.createTBAAStructTypeNode("RaviArray", nodes); - - // Table TBAA struct type - nodes.clear(); - nodes.push_back( - std::pair(tbaa_pointerT, 0)); /* next */ - nodes.push_back(std::pair(tbaa_charT, 4)); /* tt */ - nodes.push_back( - std::pair(tbaa_charT, 5)); /* marked */ - nodes.push_back( - std::pair(tbaa_charT, 6)); /* flags */ - nodes.push_back( - std::pair(tbaa_charT, 7)); /* lsizenode */ - nodes.push_back( - std::pair(tbaa_intT, 8)); /* size array */ - nodes.push_back( - std::pair(tbaa_pointerT, 12)); /* array */ - nodes.push_back( - std::pair(tbaa_pointerT, 16)); /* node */ - nodes.push_back( - std::pair(tbaa_pointerT, 20)); /* lastfree */ - nodes.push_back( - std::pair(tbaa_pointerT, 24)); /* metatable */ - nodes.push_back( - std::pair(tbaa_pointerT, 28)); /* gclist */ -#if RAVI_USE_NEWHASH - nodes.push_back( - std::pair(tbaa_intT, 32)); /* hmask */ -#endif - tbaa_TableT = mdbuilder.createTBAAStructTypeNode("Table", nodes); - - tbaa_Table_flags = - mdbuilder.createTBAAStructTagNode(tbaa_TableT, tbaa_charT, 6); - tbaa_Table_lsizenode = - mdbuilder.createTBAAStructTagNode(tbaa_TableT, tbaa_charT, 7); - tbaa_Table_sizearray = - mdbuilder.createTBAAStructTagNode(tbaa_TableT, tbaa_intT, 8); - tbaa_Table_array = - mdbuilder.createTBAAStructTagNode(tbaa_TableT, tbaa_pointerT, 12); - tbaa_Table_node = - mdbuilder.createTBAAStructTagNode(tbaa_TableT, tbaa_pointerT, 16); - tbaa_Table_metatable = - mdbuilder.createTBAAStructTagNode(tbaa_TableT, tbaa_pointerT, 24); -#if RAVI_USE_NEWHASH - tbaa_Table_hmask = - mdbuilder.createTBAAStructTagNode(tbaa_TableT, tbaa_intT, 32); -#endif - - tbaa_RaviArray_dataT = - mdbuilder.createTBAAStructTagNode(tbaa_RaviArrayT, tbaa_pointerT, 40); - tbaa_RaviArray_lenT = - mdbuilder.createTBAAStructTagNode(tbaa_RaviArrayT, tbaa_intT, 8); - tbaa_RaviArray_typeT = - mdbuilder.createTBAAStructTagNode(tbaa_RaviArrayT, tbaa_charT, 4); -} - -void LuaLLVMTypes::dump() { -#if LLVM_VERSION_MAJOR < 5 - GCObjectT->dump(); - fputs("\n", stdout); - TValueT->dump(); - fputs("\n", stdout); - TStringT->dump(); - fputs("\n", stdout); - UdataT->dump(); - fputs("\n", stdout); - UpvaldescT->dump(); - fputs("\n", stdout); - LocVarT->dump(); - fputs("\n", stdout); - RaviJITProtoT->dump(); - fputs("\n", stdout); - ProtoT->dump(); - fputs("\n", stdout); - CClosureT->dump(); - fputs("\n", stdout); - LClosureT->dump(); - fputs("\n", stdout); - TKeyT->dump(); - fputs("\n", stdout); - NodeT->dump(); - fputs("\n", stdout); - TableT->dump(); - fputs("\n", stdout); - MbufferT->dump(); - fputs("\n", stdout); - stringtableT->dump(); - fputs("\n", stdout); - CallInfoT->dump(); - fputs("\n", stdout); - lua_StateT->dump(); - fputs("\n", stdout); -#endif -} -} // namespace ravi \ No newline at end of file