diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..e15f476 --- /dev/null +++ b/.clang-format @@ -0,0 +1,135 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: false +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + - Regex: '.*' + Priority: 1 + SortPriority: 0 +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentCaseLabels: false +IndentGotoLabels: true +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +Standard: Latest +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseCRLF: false +UseTab: Never \ No newline at end of file diff --git a/.dev/format.sh b/.dev/format.sh new file mode 100755 index 0000000..cc0a0fd --- /dev/null +++ b/.dev/format.sh @@ -0,0 +1,34 @@ +#! /usr/bin/env sh + +# NOTE: This script was taken from PointCloudLibrary/pcl and adapted for ImpalaJIT + +# sample command line usage: $0 clang-format(version >= 6.0) $IMPALA_SOURCE_DIR +# $ sh ./.dev/format.sh `which clang-format` ./ +# $ sh format.sh `which clang-format` ../ + +format() { + # don't use a directory with whitespace + local whitelist="compiler/engine compiler/code-gen" + + local IMPALA_DIR="${2}" + local formatter="${1}" + + if [ ! -f "${formatter}" ]; then + echo "Could not find a clang-format. Please specify one as the first argument" + exit 166 + fi + + # check for self + if [ ! -f "${IMPALA_DIR}/.dev/format.sh" ]; then + echo "Please ensure that IMPALA_SOURCE_DIR is passed as the second argument" + exit 166 + fi + + for dir in ${whitelist}; do + path=${IMPALA_DIR}/${dir} + find ${path} -type f -iname *.[ch] -o -iname *.[ch]pp -o -iname *.[ch]xx \ + -iname *.cu | xargs -n1 ${formatter} -i -style=file + done +} + +format $@ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..a4e5d51 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,82 @@ +name: CMake + +on: push + +env: + BUILD_TYPE: Release + +jobs: + testing: + runs-on: ubuntu-18.04 + strategy: + matrix: + llvm_version: [10, 11] + + steps: + - name: Setup CMake + uses: jwlawson/actions-setup-cmake@v1.9 + with: + cmake-version: '3.16.x' + + - name: Install GTest + run: | + sudo apt-get install libgtest-dev + cd /usr/src/gtest + sudo cmake CMakeLists.txt -Dgtest_disable_pthreads=ON + sudo make + sudo make install + + - name: Install LLVM ${{ matrix.llvm_version }} + run: | + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh ${{ matrix.llvm_version }} + sudo apt-get -y install zlib1g-dev + + - uses: actions/checkout@v2 + + - name: Configure CMake + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DTESTS=ON + + - name: Build + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j2 + + - name: Test + working-directory: ${{github.workspace}}/build + run: ctest -C ${{env.BUILD_TYPE}} + + - name: Test Installed + run: | + cd ${{github.workspace}}/build + sudo make install + cd ${{github.workspace}}/tests/install_test + mkdir build && cd build + cmake .. + make + ./install_test + + format: + runs-on: ubuntu-18.04 + env: + CLANG_FORMAT_VERSION: 10 + steps: + - name: Install Clang Format ${{env.CLANG_FORMAT_VERSION}} + run: | + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh ${{env.CLANG_FORMAT_VERSION}} + sudo apt-get remove clang-format* + sudo apt-get -y install clang-format-${{env.CLANG_FORMAT_VERSION}} zlib1g-dev + sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-${{env.CLANG_FORMAT_VERSION}} 10 + + - name: Show Clang Format Version + run: clang-format --version + + - uses: actions/checkout@v2 + + - name: Check Formating + run: | + ./.dev/format.sh $(which clang-format) . + git diff > formatting.patch + cat formatting.patch + if [ -s ./formatting.patch ]; then (exit 166); fi diff --git a/.gitignore b/.gitignore index 8b402c2..0d0dbad 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ minilua build lib/* +cmake-build-* +.vscode diff --git a/.gitmodules b/.gitmodules index 395886d..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "3rd_party/LuaJIT"] - path = 3rd_party/LuaJIT - url = https://github.com/LuaJIT/LuaJIT.git diff --git a/3rd_party/LuaJIT b/3rd_party/LuaJIT deleted file mode 160000 index bd7e42e..0000000 --- a/3rd_party/LuaJIT +++ /dev/null @@ -1 +0,0 @@ -Subproject commit bd7e42e57482950a70f63d9f3ce0bb76bd2b0945 diff --git a/CMake/pkg-config.pc.in b/CMake/pkg-config.pc.in deleted file mode 100644 index c579515..0000000 --- a/CMake/pkg-config.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -Name: ${_PKG_CONFIG_PROJECT_NAME} -Description: ${_PKG_CONFIG_DESCRIPTION} -URL: ${_PKG_CONFIG_URL} -Version: ${_PKG_CONFIG_VERSION} - -prefix=${_PKG_CONFIG_PREFIX} -libdir=${_PKG_CONFIG_LIBDIR} -includedir=${_PKG_CONFIG_INCLUDEDIR} - -Libs: ${_PKG_CONFIG_LIBS} -Cflags: ${_PKG_CONFIG_CFLAGS} diff --git a/CMakeLists.txt b/CMakeLists.txt index ce0042e..a58d474 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,110 +17,102 @@ cmake_minimum_required(VERSION 2.6) +project(ImpalaJIT) -option( SHARED_LIB "Compile the shared library" OFF ) -option( STATIC_LIB "Compile the static library" ON ) -option( TESTS "Enable Tests" OFF ) +option(SHARED_LIB "Compile the shared library" ON) +option(TESTS "Enable Tests" OFF) + +set(source_files compiler/frontend/parser.cc + compiler/frontend/scanner.cc + compiler/driver.cc + compiler/function_context.cc + compiler/include/nodes/node.h + impalajit.cc + compiler/semantic_analysis/semantic_analyzer.cc + compiler/code-gen/code_generator.cpp + compiler/code-gen/codegen_visitor.cpp + compiler/code-gen/pretty_printer.cpp + compiler/engine/engine.cpp + compiler/engine/optimizer.cpp + compiler/engine/std_math_lib.cpp) + +# Note: this is due to an old cmake style. One can use a version range starting from cmake@3.19 +find_package(LLVM 11.1 QUIET) +if (NOT LLVM_FOUND) + find_package(LLVM 11.0 QUIET) +endif() +if (NOT LLVM_FOUND) + find_package(LLVM 10.0 REQUIRED) +endif() + +LLVM_MAP_COMPONENTS_TO_LIBNAMES(LLVM_LIBS core orcjit native) +message(STATUS "LLVM: ${LLVM_VERSION}") + + +if(SHARED_LIB) + add_library(impalajit SHARED ${source_files}) +else() + add_library(impalajit STATIC ${source_files}) +endif() + +target_include_directories(impalajit PRIVATE include + include/impalajit + compiler/include + compiler/include/nodes + compiler/include/types + compiler/frontend/include + compiler/semantic_analysis/include + compiler/code-gen/include + compiler/engine) + + +target_compile_options(impalajit PRIVATE -std=c++14 -O3 -fPIC) +target_link_libraries(impalajit PUBLIC -rdynamic -lm) + +# assume that llvm components are given as static libraries +target_link_libraries(impalajit PRIVATE ${LLVM_LIBS}) +target_include_directories(impalajit PRIVATE ${LLVM_INCLUDE_DIRS}) +target_compile_definitions(impalajit PRIVATE ${LLVM_DEFINITIONS}) + + +if (TESTS) + enable_testing() + add_subdirectory(tests) +endif() -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++98 -O3") +set(IMPALA_CMAKE_FILES lib/cmake/impalajit-llvm) +install(TARGETS impalajit DESTINATION lib + EXPORT ImpalaJIT-LLVMTargets + INCLUDES DESTINATION include) -project(ImpalaJIT) +install(EXPORT ImpalaJIT-LLVMTargets + NAMESPACE llvm:: + DESTINATION ${IMPALA_CMAKE_FILES}) -set(include_dirs - include - include/impalajit - compiler/include - compiler/include/nodes - compiler/include/types - compiler/frontend/include - compiler/semantic_analysis/include - compiler/code-gen/include - compiler/code-gen/assembly/include - ) - -include_directories(${include_dirs}) - - -set(source_files ${source_files} - compiler/frontend/parser.cc - compiler/frontend/scanner.cc - compiler/driver.cc - compiler/function_context.cc - compiler/include/nodes/node.h - impalajit.cc - compiler/include/nodes/expression_nodes.h - compiler/include/nodes/compare_nodes.h - compiler/include/nodes/conditional_nodes.h - compiler/include/nodes/boolean_nodes.h - compiler/include/nodes/assignment_nodes.h - compiler/semantic_analysis/semantic_analyzer.cc - compiler/code-gen/include/ptr_map_container.hh - compiler/code-gen/include/calculation_helper.hh - compiler/code-gen/code_generator.cc - compiler/code-gen/assembly/assembly__sse_4_1.cc) - -##### pkg-config ##### -find_package( PkgConfig ) -if( PKG_CONFIG_FOUND ) - # Detect private libs and directories - - set( _PKG_CONFIG_PROJECT_NAME ${PROJECT_NAME} ) - set( _PKG_CONFIG_DESCRIPTION "JIT Compilation to realize flexible data access" ) - set( _PKG_CONFIG_URL "https://github.com/Manuel1605/ImpalaJIT" ) - set( _PKG_CONFIG_VERSION "0.9" ) - - set( _PKG_CONFIG_PREFIX ${CMAKE_INSTALL_PREFIX} ) - set( _PKG_CONFIG_LIBDIR "\${prefix}/lib" ) - set( _PKG_CONFIG_INCLUDEDIR "\${prefix}/include" ) - - set( _PKG_CONFIG_LIBS "${CMAKE_LIBRARY_PATH_FLAG}\${libdir} ${CMAKE_LINK_LIBRARY_FLAG}impalajit" ) - - set( _PKG_CONFIG_LIBS_PRIVATE "${_PKG_CONFIG_LIBDIRS_PRIVATE} ${_PKG_CONFIG_LIBS_PRIVATE}" ) - set( _PKG_CONFIG_CFLAGS "-I\${includedir}" ) - - # Where to install the pkg-config file? - set( _PKG_CONFIG_DIR ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig ) - - # Configure the pkgconfig file - configure_file( CMake/pkg-config.pc.in impalajit.pc ) - - # Install the pkg file - install( FILES ${CMAKE_CURRENT_BINARY_DIR}/impalajit.pc DESTINATION lib/pkgconfig ) -endif( PKG_CONFIG_FOUND ) - -if( SHARED_LIB ) - add_library( impalajit SHARED ${source_files}) - target_link_libraries( impalajit ${math_library} ) -endif( SHARED_LIB ) - -if( STATIC_LIB ) - add_library( impalajit-static STATIC ${source_files} ) - set_target_properties( impalajit-static - PROPERTIES OUTPUT_NAME impalajit ) -endif( STATIC_LIB ) - -# Tests -if( TESTS ) - enable_testing() - add_subdirectory( tests ) -endif( TESTS ) - -# install target -if( SHARED_LIB ) - install( TARGETS impalajit - DESTINATION lib ) -endif( SHARED_LIB ) -if( STATIC_LIB ) - install( TARGETS impalajit-static - DESTINATION lib ) -endif( STATIC_LIB ) -install( FILES include/impalajit.hh - DESTINATION include ) -install( FILES include/impalajit.f90 - DESTINATION include ) -install( FILES include/impalajit/types.hh - DESTINATION include/impalajit ) +install(FILES + include/impalajit.hh + include/impalajit.f90 + DESTINATION + include) + +install(FILES + include/impalajit/types.hh + DESTINATION + include/impalajit) +include(CMakePackageConfigHelpers) +configure_package_config_file(share/ImpalaJITConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/ImpalaJIT-LLVMConfig.cmake + INSTALL_DESTINATION ${IMPALA_CMAKE_FILES}) + +write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/ImpalaJIT-LLVMConfigVersion.cmake + VERSION 1.0.0 + COMPATIBILITY SameMajorVersion) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ImpalaJIT-LLVMConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/ImpalaJIT-LLVMConfigVersion.cmake + DESTINATION ${IMPALA_CMAKE_FILES}) # uninstall target @@ -128,6 +120,7 @@ configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) + add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) @@ -136,5 +129,3 @@ add_custom_target(uninstall add_custom_target(generate COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/generate.cmake WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) - - diff --git a/README.md b/README.md index 538aee2..bac2129 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,24 @@ # ImpalaJIT A lightweight JIT compiler for flexible data access in simulation applications -## Building ImpalaJIT -1. mkdir build -2. cd build -3. cmake ../ -4. make +### Dependencies +- LLVM between versions 10.0 and 11.1 - build +- Z3 - run-time -## Generating Parser, Scanner and ASM +### Building +``` +mkdir build +cd build +cmake .. -DCMAKE_INSTALL_PREFIX= +make -j +``` + +### Installing +``` +make install +``` + +### Generating Parser, Scanner and ASM This step is only necessary if you have modified one of the following files:
[parser.yy](compiler/parser.yy)
[scanner.ll](compiler/scanner.ll)
@@ -16,13 +27,9 @@ Prerequisites for the generate task are:
Bison (Tested with version 3.0.4): https://www.gnu.org/software/bison/
Flex (Tested with version 2.6.0): https://github.com/westes/flex
-* make generate - -## Installing ImpalaJIT -* make install - -## Uninstalling ImpalaJIT -* make uninstall +``` +make generate +``` -## License -ImpalaJIT is release under the MIT License (see [COPYING](COPYING)) \ No newline at end of file +### License +ImpalaJIT is release under the MIT License diff --git a/compiler/code-gen/assembly/assembly__sse_4_1.cc b/compiler/code-gen/assembly/assembly__sse_4_1.cc deleted file mode 100644 index 4260cbe..0000000 --- a/compiler/code-gen/assembly/assembly__sse_4_1.cc +++ /dev/null @@ -1,645 +0,0 @@ -/* -** This file has been pre-processed with DynASM. -** http://luajit.org/dynasm.html -** DynASM version 1.4.0, DynASM x64 version 1.4.0 -** DO NOT EDIT! The original file is in "compiler/code-gen/assembly/assembly__sse_4_1.dasc". -*/ - -#line 1 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" -/** - * Copyright 2017 Manuel Fasching - * Distributed under the MIT License - * - * 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 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 -#include -#include -#include -#include - -#define LAST_XMM_REG 15 - - -//|.arch x64 -#if DASM_VERSION != 10400 -#error "Version mismatch between DynASM and included encoding engine" -#endif -#line 32 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - -//|.section code, data -#define DASM_SECTION_CODE 0 -#define DASM_SECTION_DATA 1 -#define DASM_MAXSECTION 2 -#line 34 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - -//|.globals lbl_ -enum { - lbl__MAX -}; -#line 36 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" -//|.actionlist impala_actions -static const unsigned char impala_actions[577] = { - 85,65,84,72,137,229,255,72,129,252,236,239,255,72,184,237,237,72,137,132, - 253,36,233,252,243,64,15,126,132,253,240,140,36,233,255,72,184,237,237,72, - 137,132,253,36,233,255,102,64,15,214,133,253,240,140,233,255,76,139,148,253, - 36,233,76,137,149,233,255,252,243,64,15,126,192,240,132,240,52,255,252,243, - 64,15,126,133,253,240,140,233,255,102,64,15,214,132,253,240,140,36,233,255, - 76,139,149,233,76,137,148,253,36,233,255,249,255,252,233,245,255,252,242, - 64,15,194,192,240,132,240,52,235,102,64,15,56,23,192,240,133,240,53,255,252, - 242,64,15,194,132,253,240,140,36,233,235,102,64,15,56,23,192,240,133,240, - 53,255,15,133,245,255,15,132,245,255,252,242,64,15,88,192,240,132,240,52, - 255,252,242,64,15,88,132,253,240,140,36,233,255,102,64,15,214,132,253,240, - 140,36,233,252,243,64,15,126,132,253,240,140,36,233,252,242,64,15,88,132, - 253,240,140,36,233,102,64,15,214,132,253,240,140,36,233,252,243,64,15,126, - 132,253,240,140,36,233,255,252,242,64,15,92,192,240,132,240,52,255,252,242, - 64,15,92,132,253,240,140,36,233,255,102,64,15,214,132,253,240,140,36,233, - 252,243,64,15,126,132,253,240,140,36,233,252,242,64,15,92,132,253,240,140, - 36,233,102,64,15,214,132,253,240,140,36,233,252,243,64,15,126,132,253,240, - 140,36,233,255,252,242,64,15,89,192,240,132,240,52,255,252,242,64,15,89,132, - 253,240,140,36,233,255,102,64,15,214,132,253,240,140,36,233,252,243,64,15, - 126,132,253,240,140,36,233,252,242,64,15,89,132,253,240,140,36,233,102,64, - 15,214,132,253,240,140,36,233,252,243,64,15,126,132,253,240,140,36,233,255, - 252,242,64,15,94,192,240,132,240,52,255,252,242,64,15,94,132,253,240,140, - 36,233,255,102,64,15,214,132,253,240,140,36,233,252,243,64,15,126,132,253, - 240,140,36,233,252,242,64,15,94,132,253,240,140,36,233,102,64,15,214,132, - 253,240,140,36,233,252,243,64,15,126,132,253,240,140,36,233,255,76,139,148, - 253,36,233,76,137,148,253,36,233,255,73,137,228,255,72,131,228,252,240,255, - 72,131,252,236,32,255,72,184,237,237,255,252,255,208,255,76,137,228,255,252, - 243,64,15,126,192,240,140,255,102,15,214,132,253,36,233,255,76,139,156,253, - 36,233,76,137,156,253,36,233,255,252,243,64,15,126,192,240,44,255,252,243, - 15,126,132,253,36,233,255,72,137,252,236,65,92,93,195,255 -}; - -#line 37 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - -#include - -#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) -#define MAP_ANONYMOUS MAP_ANON -#endif - - -Assembly__SSE_4_1::~Assembly__SSE_4_1() -{ - dasm_free(&d); -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::initialize(int parameterCount) { - dasm_init(&d, DASM_MAXSECTION); - - void* labels[lbl__MAX]; - dasm_setupglobal(&d, labels, lbl__MAX); - - dasm_setup(&d, impala_actions); - - dasm_growpc(&d, 0); - - Dst = &d; - - // First 8 arguments are passed in registers - stackPos = parameterCount >= 8 ? 7 : parameterCount-1; -} -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::prologue(){ - //| push rbp - //| push r12 - //| mov rbp, rsp - dasm_put(Dst, 0); -#line 75 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::growPC(unsigned npc) -{ - dasm_growpc(&d, npc); -} - -void Assembly__SSE_4_1::reserveMemoryForLocalVariables(int variableCount) -{ - //| sub rsp, variableCount*8 - dasm_put(Dst, 7, variableCount*8); -#line 88 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" -} -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::pushConstantToStack(double value){ - stackPos++; - union { - double floatingPointValue; - int64_t integerValue; - }; - - // DynASM is only able to accept imm64 values, when the mov64 instruction is used. - // So we have to mask the floating point value as a 64 byte int. It's the only way - // to load a floating point constant in a register... - floatingPointValue = value; - - if(stackPos <= LAST_XMM_REG) { - //| mov64 rax, integerValue - //| mov qword[rsp-rspOffset()-8], rax - //| movq xmm(stackPos), qword [rsp-rspOffset()-8] - dasm_put(Dst, 13, (unsigned int)(integerValue), (unsigned int)((integerValue)>>32), -rspOffset()-8, (stackPos), -rspOffset()-8); -#line 108 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else { - //| mov64 rax, integerValue - //| mov qword[rsp-rspOffset()], rax - dasm_put(Dst, 35, (unsigned int)(integerValue), (unsigned int)((integerValue)>>32), -rspOffset()); -#line 112 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::storeLocalVariable(int index) { - if(stackPos <= LAST_XMM_REG) { - //| movq qword [rbp-8-index*8], xmm(stackPos) - dasm_put(Dst, 46, (stackPos), -8-index*8); -#line 121 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else{ - //| mov r10, qword [rsp-rspOffset()] - //| mov qword [rbp-8-index*8], r10 - dasm_put(Dst, 56, -rspOffset(), -8-index*8); -#line 125 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - - stackPos--; -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::pushParameterToStack(int index) { - stackPos++; - // See x64 calling conventions. Paramters 1-8 are passed in registers - - if(stackPos <= LAST_XMM_REG) { - if(index <= 7){ - //| movq xmm(stackPos), xmm(index) - dasm_put(Dst, 67, (stackPos), (index)); -#line 140 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else { - //| movq xmm(stackPos), qword [rbp+8+(index-7)*8] - dasm_put(Dst, 78, (stackPos), 8+(index-7)*8); -#line 143 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - } - else{ - if(index <= 7){ - //| movq qword[rsp-rspOffset()], xmm(index) - dasm_put(Dst, 89, (index), -rspOffset()); -#line 148 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else { - //| mov r10, qword [rbp+8+(index-7)*8] - //| mov qword[rsp-rspOffset()], r10 - dasm_put(Dst, 100, 8+(index-7)*8, -rspOffset()); -#line 152 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - } - -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::replaceParameter(int index) { - // See x64 calling conventions. Paramters 1-8 are passed in registers - if(stackPos <= LAST_XMM_REG) { - if(index <= 7){ - //| movq xmm(index), xmm(stackPos) - dasm_put(Dst, 67, (index), (stackPos)); -#line 165 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else { - //| movq qword [rbp+8+(index-7)*8], xmm(stackPos) - dasm_put(Dst, 46, (stackPos), 8+(index-7)*8); -#line 168 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - } - else{ - if(index <= 7){ - //| movq xmm(index), qword[rsp-rspOffset()] - dasm_put(Dst, 23, (index), -rspOffset()); -#line 173 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else { - //| mov r10, qword[rsp-rspOffset()] - //| mov qword [rbp+8+(index-7)*8], r10 - dasm_put(Dst, 56, -rspOffset(), 8+(index-7)*8); -#line 177 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - } - stackPos--; -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::pushLocalVariableToStack(int index) { - stackPos++; - if(stackPos <= LAST_XMM_REG) { - //| movq xmm(stackPos), qword [rbp-8-index*8] - dasm_put(Dst, 78, (stackPos), -8-index*8); -#line 189 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else{ - //| mov r10, qword [rbp-8-index*8] - //| mov qword[rsp-rspOffset()], r10 - dasm_put(Dst, 100, -8-index*8, -rspOffset()); -#line 193 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::addDynamicLabel(unsigned labelNumber) { - //| =>labelNumber: - dasm_put(Dst, 111, labelNumber); -#line 202 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::jumpForwardToDynamicLabel(unsigned labelNumber) { - //| jmp =>labelNumber - dasm_put(Dst, 113, labelNumber); -#line 209 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::conditionalJumpForwardToDynamicLabel(unsigned labelNumber, bool condition, CompareOperatorType operator_){ - if(stackPos <= LAST_XMM_REG) { - //| cmpsd xmm(stackPos), xmm(stackPos-1), operator_ - //| ptest xmm(stackPos), xmm(stackPos) - dasm_put(Dst, 117, (stackPos), (stackPos-1), operator_, (stackPos), (stackPos)); -#line 218 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else if (stackPos == LAST_XMM_REG+1){ - //Backup one xmm register - //| movq qword[rsp-rspOffset()-8], xmm(0) - dasm_put(Dst, 89, (0), -rspOffset()-8); -#line 222 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - - // Load value in registers for comparison - //| movq xmm(0), qword[rsp-rspOffset()] - dasm_put(Dst, 23, (0), -rspOffset()); -#line 225 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - - //| cmpsd xmm(0), xmm(LAST_XMM_REG), operator_ - //| ptest xmm(0), xmm(0) - dasm_put(Dst, 117, (0), (LAST_XMM_REG), operator_, (0), (0)); -#line 228 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - - // Restore register - //| movq xmm(0), qword[rsp-rspOffset()-8] - dasm_put(Dst, 23, (0), -rspOffset()-8); -#line 231 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else{ - // Backup one registers - //| movq qword[rsp-rspOffset()-8], xmm(0) - dasm_put(Dst, 89, (0), -rspOffset()-8); -#line 235 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - - // Load values in registers for comparison - //| movq xmm(0), qword[rsp-rspOffset()] - dasm_put(Dst, 23, (0), -rspOffset()); -#line 238 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - - //| cmpsd xmm(0), qword[rsp-rspOffset()+8], operator_ - //| ptest xmm(0), xmm(0) - dasm_put(Dst, 139, (0), -rspOffset()+8, operator_, (0), (0)); -#line 241 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - - //Restore register - //| movq xmm(0), qword[rsp-rspOffset()-8] - dasm_put(Dst, 23, (0), -rspOffset()-8); -#line 244 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - - } - if(condition){ - //| jnz => labelNumber - dasm_put(Dst, 162, labelNumber); -#line 248 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else{ - //| jz => labelNumber - dasm_put(Dst, 166, labelNumber); -#line 251 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - //Conditions are not needed anymore - stackPos=stackPos-2; -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::calculateAddition(){ - if(stackPos <= LAST_XMM_REG) { - //| addsd xmm(stackPos-1), xmm(stackPos) - dasm_put(Dst, 170, (stackPos-1), (stackPos)); -#line 262 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else if(stackPos == LAST_XMM_REG+1){ - //| addsd xmm(LAST_XMM_REG), qword[rsp-rspOffset()] - dasm_put(Dst, 181, (LAST_XMM_REG), -rspOffset()); -#line 265 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else{ - //| movq qword[rsp-rspOffset()-8], xmm(0) - //| movq xmm(0), qword[rsp-rspOffset()+8] - //| addsd xmm(0), qword[rsp-rspOffset()] - //| movq qword[rsp-rspOffset()+8], xmm(0) - //| movq xmm(0), qword[rsp-rspOffset()-8] - dasm_put(Dst, 193, (0), -rspOffset()-8, (0), -rspOffset()+8, (0), -rspOffset(), (0), -rspOffset()+8, (0), -rspOffset()-8); -#line 272 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - stackPos--; -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::calculateSubtraction(){ - if(stackPos <= LAST_XMM_REG) { - //| subsd xmm(stackPos-1), xmm(stackPos) - dasm_put(Dst, 247, (stackPos-1), (stackPos)); -#line 282 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else if(stackPos == LAST_XMM_REG+1){ - //| subsd xmm(LAST_XMM_REG), qword[rsp-rspOffset()] - dasm_put(Dst, 258, (LAST_XMM_REG), -rspOffset()); -#line 285 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else{ - //| movq qword[rsp-rspOffset()-8], xmm(0) - //| movq xmm(0), qword[rsp-rspOffset()+8] - //| subsd xmm(0), qword[rsp-rspOffset()] - //| movq qword[rsp-rspOffset()+8], xmm(0) - //| movq xmm(0), qword[rsp-rspOffset()-8] - dasm_put(Dst, 270, (0), -rspOffset()-8, (0), -rspOffset()+8, (0), -rspOffset(), (0), -rspOffset()+8, (0), -rspOffset()-8); -#line 292 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - stackPos--; -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::calculateMultiplication(){ - if(stackPos <= LAST_XMM_REG) { - //| mulsd xmm(stackPos-1), xmm(stackPos) - dasm_put(Dst, 324, (stackPos-1), (stackPos)); -#line 302 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else if(stackPos == LAST_XMM_REG+1){ - //| mulsd xmm(LAST_XMM_REG), qword[rsp-rspOffset()] - dasm_put(Dst, 335, (LAST_XMM_REG), -rspOffset()); -#line 305 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else{ - //| movq qword[rsp-rspOffset()-8], xmm(0) - //| movq xmm(0), qword[rsp-rspOffset()+8] - //| mulsd xmm(0), qword[rsp-rspOffset()] - //| movq qword[rsp-rspOffset()+8], xmm(0) - //| movq xmm(0), qword[rsp-rspOffset()-8] - dasm_put(Dst, 347, (0), -rspOffset()-8, (0), -rspOffset()+8, (0), -rspOffset(), (0), -rspOffset()+8, (0), -rspOffset()-8); -#line 312 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - stackPos--; -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::calculateDivision(){ - if(stackPos <= LAST_XMM_REG) { - //| divsd xmm(stackPos-1), xmm(stackPos) - dasm_put(Dst, 401, (stackPos-1), (stackPos)); -#line 322 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else if(stackPos == LAST_XMM_REG+1){ - //| divsd xmm(LAST_XMM_REG), qword[rsp-rspOffset()] - dasm_put(Dst, 412, (LAST_XMM_REG), -rspOffset()); -#line 325 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else{ - //| movq qword[rsp-rspOffset()-8], xmm(0) - //| movq xmm(0), qword[rsp-rspOffset()+8] - //| divsd xmm(0), qword[rsp-rspOffset()] - //| movq qword[rsp-rspOffset()+8], xmm(0) - //| movq xmm(0), qword[rsp-rspOffset()-8] - dasm_put(Dst, 424, (0), -rspOffset()-8, (0), -rspOffset()+8, (0), -rspOffset(), (0), -rspOffset()+8, (0), -rspOffset()-8); -#line 332 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - stackPos--; -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::callExternalFunction(externalFunction functionPtr, unsigned numberOfArguments){ - - //Backup the stack. Function arguments will be replaced by a result - //and therefor excluded from the backup. - //I assume, that there is no external function, which has more than 8 arguments... - for(int i=0; i<=stackPos-numberOfArguments+1; i++){ - int backupOffset = rspOffset() + (i+1)*8; - if(i<=LAST_XMM_REG){ - //| movq qword [rsp-backupOffset], xmm(i) - dasm_put(Dst, 89, (i), -backupOffset); -#line 348 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else { - int localRspOffset = (i-LAST_XMM_REG)*8; - //| mov r10, qword [rsp-localRspOffset] - //| mov qword [rsp-backupOffset], r10 - dasm_put(Dst, 478, -localRspOffset, -backupOffset); -#line 353 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - } - - - //Load parameters to register - for(int i=stackPos-numberOfArguments+1; i<=stackPos; i++){ - int argumentRegisterNumber = i-(stackPos-numberOfArguments+1); - if(i<=LAST_XMM_REG){ - //| movq xmm(argumentRegisterNumber), xmm(i) - dasm_put(Dst, 67, (argumentRegisterNumber), (i)); -#line 362 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else { - int localRspOffset = (i-LAST_XMM_REG)*8; - //| movq xmm(argumentRegisterNumber), qword[rsp-localRspOffset] - dasm_put(Dst, 23, (argumentRegisterNumber), -localRspOffset); -#line 366 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - } - - - // Save frame pointer in non-volatile register - //| mov r12, rsp - dasm_put(Dst, 491); -#line 372 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - - // Subtract rpn stack - if(stackPos > LAST_XMM_REG){ - //| sub rsp, rspOffset() - dasm_put(Dst, 7, rspOffset()); -#line 376 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - // Subtract amount of register backup - //| sub rsp, (stackPos-numberOfArguments+1)*8 - dasm_put(Dst, 7, (stackPos-numberOfArguments+1)*8); -#line 379 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - - // Align frame pointer on 16 bit - //| and rsp, -16 - dasm_put(Dst, 495); -#line 382 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - - // Add Shadow space (32bit) - // Not sure, if this is still needed. - //| sub rsp, 32 - dasm_put(Dst, 501); -#line 386 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - - // Move address of function to register - //| mov64 rax, (uintptr_t) functionPtr - dasm_put(Dst, 507, (unsigned int)((uintptr_t) functionPtr), (unsigned int)(((uintptr_t) functionPtr)>>32)); -#line 389 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - - // Call function - //| call rax - dasm_put(Dst, 512); -#line 392 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - - // Restore rsp - //| mov rsp, r12 - dasm_put(Dst, 516); -#line 395 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - - - //Put function result on top of stack - if((stackPos-numberOfArguments+1) <= LAST_XMM_REG){ - //| movq xmm(stackPos-numberOfArguments+1), xmm0 - dasm_put(Dst, 520, (stackPos-numberOfArguments+1)); -#line 400 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else { - int localRspOffset = ((stackPos-numberOfArguments+1)-LAST_XMM_REG)*8; - //| movq qword[rsp-localRspOffset], xmm0 - dasm_put(Dst, 529, -localRspOffset); -#line 404 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - - - //Restore old stack - for(int i=stackPos-numberOfArguments; i>=0; i--){ - if(i<=LAST_XMM_REG){ - //| movq xmm(i), qword [rsp-rspOffset()-(i+1)*8] - dasm_put(Dst, 23, (i), -rspOffset()-(i+1)*8); -#line 411 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else { - int localRspOffset = ((stackPos-numberOfArguments+1)-LAST_XMM_REG)*8; - //| mov r11, qword [rsp-rspOffset()-(i+1)*8] - //| mov qword[rsp-localRspOffset+(stackPos-i)*8], r11 - dasm_put(Dst, 537, -rspOffset()-(i+1)*8, -localRspOffset+(stackPos-i)*8); -#line 416 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - } - //Function parameters are not needed anymore - //Set the stackPos accordingly - stackPos = stackPos-numberOfArguments+1; -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::extractResult(){ - if(stackPos <= LAST_XMM_REG){ - //| movq xmm0, xmm(stackPos) - dasm_put(Dst, 550, (stackPos)); -#line 429 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } - else { - //| movq xmm0, qword[rsp-rspOffset()] - dasm_put(Dst, 559, -rspOffset()); -#line 432 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" - } -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::epilogue(){ - //| mov rsp, rbp - //| pop r12 - //| pop rbp - //| ret - dasm_put(Dst, 568); -#line 443 "compiler/code-gen/assembly/assembly__sse_4_1.dasc" -} - -/** - * @see assembly.hh - */ -dasm_gen_func Assembly__SSE_4_1::linkAndEncode(){ - size_t sz; - void* buf; - dasm_link(Dst, &sz); - buf = mmap(0, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - dasm_encode(Dst, buf); - mprotect(buf, sz, PROT_READ | PROT_EXEC); - return (dasm_gen_func) buf; -} - -int Assembly__SSE_4_1::rspOffset(){ - if((stackPos-LAST_XMM_REG) <= 0){ - return 0; - } - return (stackPos-LAST_XMM_REG)*8; -} - -void Assembly__SSE_4_1::pushStackPos(){ - stackPosStack.push(stackPos); -} - -void Assembly__SSE_4_1::popStackPos(){ - stackPos = stackPosStack.top(); - stackPosStack.pop(); -} diff --git a/compiler/code-gen/assembly/assembly__sse_4_1.dasc b/compiler/code-gen/assembly/assembly__sse_4_1.dasc deleted file mode 100644 index d88a9f2..0000000 --- a/compiler/code-gen/assembly/assembly__sse_4_1.dasc +++ /dev/null @@ -1,472 +0,0 @@ -/** - * Copyright 2017 Manuel Fasching - * Distributed under the MIT License - * - * 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 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 -#include -#include -#include -#include - -#define LAST_XMM_REG 15 - - -|.arch x64 - -|.section code, data - -|.globals lbl_ -|.actionlist impala_actions - -#include - -#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) -#define MAP_ANONYMOUS MAP_ANON -#endif - - -Assembly__SSE_4_1::~Assembly__SSE_4_1() -{ - dasm_free(&d); -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::initialize(int parameterCount) { - dasm_init(&d, DASM_MAXSECTION); - - void* labels[lbl__MAX]; - dasm_setupglobal(&d, labels, lbl__MAX); - - dasm_setup(&d, impala_actions); - - dasm_growpc(&d, 0); - - Dst = &d; - - // First 8 arguments are passed in registers - stackPos = parameterCount >= 8 ? 7 : parameterCount-1; -} -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::prologue(){ - | push rbp - | push r12 - | mov rbp, rsp -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::growPC(unsigned npc) -{ - dasm_growpc(&d, npc); -} - -void Assembly__SSE_4_1::reserveMemoryForLocalVariables(int variableCount) -{ - | sub rsp, variableCount*8 -} -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::pushConstantToStack(double value){ - stackPos++; - union { - double floatingPointValue; - int64_t integerValue; - }; - - // DynASM is only able to accept imm64 values, when the mov64 instruction is used. - // So we have to mask the floating point value as a 64 byte int. It's the only way - // to load a floating point constant in a register... - floatingPointValue = value; - - if(stackPos <= LAST_XMM_REG) { - | mov64 rax, integerValue - | mov qword[rsp-rspOffset()-8], rax - | movq xmm(stackPos), qword [rsp-rspOffset()-8] - } - else { - | mov64 rax, integerValue - | mov qword[rsp-rspOffset()], rax - } -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::storeLocalVariable(int index) { - if(stackPos <= LAST_XMM_REG) { - | movq qword [rbp-8-index*8], xmm(stackPos) - } - else{ - | mov r10, qword [rsp-rspOffset()] - | mov qword [rbp-8-index*8], r10 - } - - stackPos--; -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::pushParameterToStack(int index) { - stackPos++; - // See x64 calling conventions. Paramters 1-8 are passed in registers - - if(stackPos <= LAST_XMM_REG) { - if(index <= 7){ - | movq xmm(stackPos), xmm(index) - } - else { - | movq xmm(stackPos), qword [rbp+8+(index-7)*8] - } - } - else{ - if(index <= 7){ - | movq qword[rsp-rspOffset()], xmm(index) - } - else { - | mov r10, qword [rbp+8+(index-7)*8] - | mov qword[rsp-rspOffset()], r10 - } - } - -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::replaceParameter(int index) { - // See x64 calling conventions. Paramters 1-8 are passed in registers - if(stackPos <= LAST_XMM_REG) { - if(index <= 7){ - | movq xmm(index), xmm(stackPos) - } - else { - | movq qword [rbp+8+(index-7)*8], xmm(stackPos) - } - } - else{ - if(index <= 7){ - | movq xmm(index), qword[rsp-rspOffset()] - } - else { - | mov r10, qword[rsp-rspOffset()] - | mov qword [rbp+8+(index-7)*8], r10 - } - } - stackPos--; -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::pushLocalVariableToStack(int index) { - stackPos++; - if(stackPos <= LAST_XMM_REG) { - | movq xmm(stackPos), qword [rbp-8-index*8] - } - else{ - | mov r10, qword [rbp-8-index*8] - | mov qword[rsp-rspOffset()], r10 - } - -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::addDynamicLabel(unsigned labelNumber) { - | =>labelNumber: -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::jumpForwardToDynamicLabel(unsigned labelNumber) { - | jmp =>labelNumber -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::conditionalJumpForwardToDynamicLabel(unsigned labelNumber, bool condition, CompareOperatorType operator_){ - if(stackPos <= LAST_XMM_REG) { - | cmpsd xmm(stackPos), xmm(stackPos-1), operator_ - | ptest xmm(stackPos), xmm(stackPos) - } - else if (stackPos == LAST_XMM_REG+1){ - //Backup one xmm register - | movq qword[rsp-rspOffset()-8], xmm(0) - - // Load value in registers for comparison - | movq xmm(0), qword[rsp-rspOffset()] - - | cmpsd xmm(0), xmm(LAST_XMM_REG), operator_ - | ptest xmm(0), xmm(0) - - // Restore register - | movq xmm(0), qword[rsp-rspOffset()-8] - } - else{ - // Backup one registers - | movq qword[rsp-rspOffset()-8], xmm(0) - - // Load values in registers for comparison - | movq xmm(0), qword[rsp-rspOffset()] - - | cmpsd xmm(0), qword[rsp-rspOffset()+8], operator_ - | ptest xmm(0), xmm(0) - - //Restore register - | movq xmm(0), qword[rsp-rspOffset()-8] - - } - if(condition){ - | jnz => labelNumber - } - else{ - | jz => labelNumber - } - //Conditions are not needed anymore - stackPos=stackPos-2; -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::calculateAddition(){ - if(stackPos <= LAST_XMM_REG) { - | addsd xmm(stackPos-1), xmm(stackPos) - } - else if(stackPos == LAST_XMM_REG+1){ - | addsd xmm(LAST_XMM_REG), qword[rsp-rspOffset()] - } - else{ - | movq qword[rsp-rspOffset()-8], xmm(0) - | movq xmm(0), qword[rsp-rspOffset()+8] - | addsd xmm(0), qword[rsp-rspOffset()] - | movq qword[rsp-rspOffset()+8], xmm(0) - | movq xmm(0), qword[rsp-rspOffset()-8] - } - stackPos--; -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::calculateSubtraction(){ - if(stackPos <= LAST_XMM_REG) { - | subsd xmm(stackPos-1), xmm(stackPos) - } - else if(stackPos == LAST_XMM_REG+1){ - | subsd xmm(LAST_XMM_REG), qword[rsp-rspOffset()] - } - else{ - | movq qword[rsp-rspOffset()-8], xmm(0) - | movq xmm(0), qword[rsp-rspOffset()+8] - | subsd xmm(0), qword[rsp-rspOffset()] - | movq qword[rsp-rspOffset()+8], xmm(0) - | movq xmm(0), qword[rsp-rspOffset()-8] - } - stackPos--; -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::calculateMultiplication(){ - if(stackPos <= LAST_XMM_REG) { - | mulsd xmm(stackPos-1), xmm(stackPos) - } - else if(stackPos == LAST_XMM_REG+1){ - | mulsd xmm(LAST_XMM_REG), qword[rsp-rspOffset()] - } - else{ - | movq qword[rsp-rspOffset()-8], xmm(0) - | movq xmm(0), qword[rsp-rspOffset()+8] - | mulsd xmm(0), qword[rsp-rspOffset()] - | movq qword[rsp-rspOffset()+8], xmm(0) - | movq xmm(0), qword[rsp-rspOffset()-8] - } - stackPos--; -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::calculateDivision(){ - if(stackPos <= LAST_XMM_REG) { - | divsd xmm(stackPos-1), xmm(stackPos) - } - else if(stackPos == LAST_XMM_REG+1){ - | divsd xmm(LAST_XMM_REG), qword[rsp-rspOffset()] - } - else{ - | movq qword[rsp-rspOffset()-8], xmm(0) - | movq xmm(0), qword[rsp-rspOffset()+8] - | divsd xmm(0), qword[rsp-rspOffset()] - | movq qword[rsp-rspOffset()+8], xmm(0) - | movq xmm(0), qword[rsp-rspOffset()-8] - } - stackPos--; -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::callExternalFunction(externalFunction functionPtr, unsigned numberOfArguments){ - - //Backup the stack. Function arguments will be replaced by a result - //and therefor excluded from the backup. - //I assume, that there is no external function, which has more than 8 arguments... - for(int i=0; i<=stackPos-numberOfArguments+1; i++){ - int backupOffset = rspOffset() + (i+1)*8; - if(i<=LAST_XMM_REG){ - | movq qword [rsp-backupOffset], xmm(i) - } - else { - int localRspOffset = (i-LAST_XMM_REG)*8; - | mov r10, qword [rsp-localRspOffset] - | mov qword [rsp-backupOffset], r10 - } - } - - - //Load parameters to register - for(int i=stackPos-numberOfArguments+1; i<=stackPos; i++){ - int argumentRegisterNumber = i-(stackPos-numberOfArguments+1); - if(i<=LAST_XMM_REG){ - | movq xmm(argumentRegisterNumber), xmm(i) - } - else { - int localRspOffset = (i-LAST_XMM_REG)*8; - | movq xmm(argumentRegisterNumber), qword[rsp-localRspOffset] - } - } - - - // Save frame pointer in non-volatile register - | mov r12, rsp - - // Subtract rpn stack - if(stackPos > LAST_XMM_REG){ - | sub rsp, rspOffset() - } - // Subtract amount of register backup - | sub rsp, (stackPos-numberOfArguments+1)*8 - - // Align frame pointer on 16 bit - | and rsp, -16 - - // Add Shadow space (32bit) - // Not sure, if this is still needed. - | sub rsp, 32 - - // Move address of function to register - | mov64 rax, (uintptr_t) functionPtr - - // Call function - | call rax - - // Restore rsp - | mov rsp, r12 - - - //Put function result on top of stack - if((stackPos-numberOfArguments+1) <= LAST_XMM_REG){ - | movq xmm(stackPos-numberOfArguments+1), xmm0 - } - else { - int localRspOffset = ((stackPos-numberOfArguments+1)-LAST_XMM_REG)*8; - | movq qword[rsp-localRspOffset], xmm0 - } - - - //Restore old stack - for(int i=stackPos-numberOfArguments; i>=0; i--){ - if(i<=LAST_XMM_REG){ - | movq xmm(i), qword [rsp-rspOffset()-(i+1)*8] - } - else { - int localRspOffset = ((stackPos-numberOfArguments+1)-LAST_XMM_REG)*8; - | mov r11, qword [rsp-rspOffset()-(i+1)*8] - | mov qword[rsp-localRspOffset+(stackPos-i)*8], r11 - } - } - //Function parameters are not needed anymore - //Set the stackPos accordingly - stackPos = stackPos-numberOfArguments+1; -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::extractResult(){ - if(stackPos <= LAST_XMM_REG){ - | movq xmm0, xmm(stackPos) - } - else { - | movq xmm0, qword[rsp-rspOffset()] - } -} - -/** - * @see assembly.hh - */ -void Assembly__SSE_4_1::epilogue(){ - | mov rsp, rbp - | pop r12 - | pop rbp - | ret -} - -/** - * @see assembly.hh - */ -dasm_gen_func Assembly__SSE_4_1::linkAndEncode(){ - size_t sz; - void* buf; - dasm_link(Dst, &sz); - buf = mmap(0, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - dasm_encode(Dst, buf); - mprotect(buf, sz, PROT_READ | PROT_EXEC); - return (dasm_gen_func) buf; -} - -int Assembly__SSE_4_1::rspOffset(){ - if((stackPos-LAST_XMM_REG) <= 0){ - return 0; - } - return (stackPos-LAST_XMM_REG)*8; -} - -void Assembly__SSE_4_1::pushStackPos(){ - stackPosStack.push(stackPos); -} - -void Assembly__SSE_4_1::popStackPos(){ - stackPos = stackPosStack.top(); - stackPosStack.pop(); -} \ No newline at end of file diff --git a/compiler/code-gen/assembly/include/assembly.hh b/compiler/code-gen/assembly/include/assembly.hh deleted file mode 100644 index ff888fd..0000000 --- a/compiler/code-gen/assembly/include/assembly.hh +++ /dev/null @@ -1,192 +0,0 @@ -/** - * Copyright 2017 Manuel Fasching - * Distributed under the MIT License - * - * 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 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 IMPALAJIT_ASSEMBLY_HH -#define IMPALAJIT_ASSEMBLY_HH - -#include -#include -#include -#include -#include -/** - * Base class for assembly implementations. Child classes - * should implement these functions for different architectures. - */ -class Assembly { - -public: - - /** - * Initializes the dynasm context - * @param parameterCount The amount of passed parameters - */ - virtual void initialize(int parameterCount) = 0; - - /** - * First assembly instruction in function. - * Usually something like: - * push rbp - * mov rbp, rsp - * This sets up our stack frame - * - * @param parameterCount The amount of passed parameters - */ - virtual void prologue()= 0; - - /** - * Restore the original base and frame pointer. - * This is required, since the caller function probably wants to proceed. - * Basically it reverts the things made in prologue - */ - virtual void epilogue()= 0; - - /** - * Dynamically increase the amount of available dynamic labels - * This function can be called multiple times. - * - * @param npc The new amount of available dynamic lables - */ - virtual void growPC(unsigned npc)= 0; - - /** - * Moves the frame pointer downwards and reserves space for local variables. - * - * @param variableCount The amount of local variables - */ - virtual void reserveMemoryForLocalVariables(int variableCount)=0; - - /** - * Pushes a parameter onto the rpn stack. - * TODO: Rename to avoid confusion with call stack - * - * @param index The index of the parameter - */ - virtual void pushParameterToStack(int index)= 0; - - /** - * Pushes a local variable onto the rpn stack. - * TODO: Rename to avoid confusion with call stack - * - * @param index The index of the variable - */ - virtual void pushLocalVariableToStack(int index)= 0; - - /** - * Replaces the value of an parameter. - * - * @param index The index of the parameter - */ - virtual void replaceParameter(int index)= 0; - - /** - * Pushes a constant value onto the rpn stack. - * This function will allocate memory space for the - * constant. - * - * @param value The constant value - */ - virtual void pushConstantToStack(double value)= 0; - - /** - * Pushes the top value of the rpn stack onto the call stack. - */ - virtual void storeLocalVariable(int index)= 0; - - /** - * Performs a simple addition. - */ - virtual void calculateAddition()= 0; - - /** - * Performs a simple addition. - */ - virtual void calculateSubtraction()= 0; - - /** - * Performs a simple multiplication. - */ - virtual void calculateMultiplication()= 0; - - /** - * Performs a simple division. - */ - virtual void calculateDivision()= 0; - - /** - * Function call. Arguments are passed in register xmm0 - xmm(numberOfArguments-1) - * Due to this function the -mno-red-zone flag is necessary. - * GNU (and maybe intel, did not check) considers us as a leaf function. So, the "red-zone" - * optimization is true for us. This would prevent us from calling other functions. - * TODO: Currently only 8 arguments can be passed. Additional arguments must be added to the call stack - * TODO: Check if the "red-zone" optimization can be disabled for functions - * - * @param functionPtr pointer to function which should get called - * @param numberOfArguments number of arguments which should get passed to called function - */ - virtual void callExternalFunction(externalFunction functionPtr, unsigned NumberOfArguments)= 0; - - /** - * Adds a dynamic label - * @param labelNumber - */ - virtual void addDynamicLabel(unsigned labelNumber)= 0; - - /** - * Compares the top 2 values of the rpn stack and performs a conditional jump to the specified label. - * This is used for if else statements - * - * @param labelNumber the number of the dynamic label - * @param condition wheter the condition must be true or false - * @param operator_ compare operator. Currently implemented: GT, LT, EQ, NE, GTE, LTE - */ - virtual void conditionalJumpForwardToDynamicLabel(unsigned labelNumber, bool condition, CompareOperatorType operator_)= 0; - - /** - * Pushes the current stack position onto a stack - */ - virtual void pushStackPos()=0; - - /** - * Pops the current stack position and restores the stackPos - */ - virtual void popStackPos()=0; - - /** - * Put execution result to register xmm0. - * According to x64 calling conventions the return value of a function is expected in reg xmm0. - */ - virtual void extractResult()= 0; - - /** - * Generate machine executable code - * - * @return A pointer to the machine executable code - */ - virtual dasm_gen_func linkAndEncode()= 0; - -protected: - dasm_State* d; - dasm_State** Dst; - void** labels; - int stackPos; // The head of the rpn stack - std::stack stackPosStack; -}; - -#endif //IMPALAJIT_ASSEMBLY_HH \ No newline at end of file diff --git a/compiler/code-gen/assembly/include/assembly__sse_4_1.hh b/compiler/code-gen/assembly/include/assembly__sse_4_1.hh deleted file mode 100644 index eb1adec..0000000 --- a/compiler/code-gen/assembly/include/assembly__sse_4_1.hh +++ /dev/null @@ -1,154 +0,0 @@ -/** - * Copyright 2017 Manuel Fasching - * Distributed under the MIT License - * - * 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 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 IMPALAJIT_ASSEMBLY_SSE_4_1_HH -#define IMPALAJIT_ASSEMBLY_SSE_4_1_HH - -#include - -/** - * This class uses only SSE_4_1 instructions. - * AMD should doing well with it. NOT TESTED - * - * @see Assembly - */ -class Assembly__SSE_4_1 : public Assembly { -public: - /** - * Destructor. Calls the cleanup function of dynasm. - */ - virtual ~Assembly__SSE_4_1(); - - /** - * @see assembly.hh - */ - virtual void initialize(int parameterCount); - - /** - * @see assembly.hh - */ - virtual void prologue(); - - /** - * @see assembly.hh - */ - virtual void epilogue(); - - /** - * @see assembly.hh - */ - virtual void growPC(unsigned npc); - - /** - * @see assembly.hh - */ - virtual void reserveMemoryForLocalVariables(int variableCount); - - /** - * @see assembly.hh - */ - virtual void pushParameterToStack(int index); - - /** - * @see assembly.hh - */ - virtual void pushLocalVariableToStack(int index); - - /** - * @see assembly.hh - */ - virtual void replaceParameter(int index); - - /** - * @see assembly.hh - */ - virtual void pushConstantToStack(double value); - - /** - * @see assembly.hh - */ - virtual void storeLocalVariable(int index); - - /** - * @see assembly.hh - */ - virtual void calculateAddition(); - - /** - * @see assembly.hh - */ - virtual void calculateSubtraction(); - - /** - * @see assembly.hh - */ - virtual void calculateMultiplication(); - - /** - * @see assembly.hh - */ - virtual void calculateDivision(); - - /** - * @see assembly.hh - */ - virtual void callExternalFunction(externalFunction functionPtr, unsigned NumberOfArguments); - - /** - * @see assembly.hh - */ - virtual void addDynamicLabel(unsigned labelNumber); - - /** - * @see assembly.hh - */ - virtual void jumpForwardToDynamicLabel(unsigned labelNumber); - - /** - * @see assembly.hh - */ - virtual void conditionalJumpForwardToDynamicLabel(unsigned labelNumber, bool condition, CompareOperatorType operator_); - - /** - * @see assembly.hh - */ - virtual void pushStackPos(); - - /** - * @see assembly.hh - */ - virtual void popStackPos(); - - /** - * @see assembly.hh - */ - virtual void extractResult(); - - /** - * @see assembly.hh - */ - virtual dasm_gen_func linkAndEncode(); -private: - /** - * @return the rsp offset of the rpn stack - */ - int rspOffset(); -}; - -#endif //IMPALAJIT_ASSEMBLY_SSE_4_1_HH \ No newline at end of file diff --git a/compiler/code-gen/assembly/include/dasm_arm.h b/compiler/code-gen/assembly/include/dasm_arm.h deleted file mode 100644 index 0fa69ac..0000000 --- a/compiler/code-gen/assembly/include/dasm_arm.h +++ /dev/null @@ -1,456 +0,0 @@ -/* -** DynASM ARM encoding engine. -** Copyright (C) 2005-2016 Mike Pall. All rights reserved. -** Released under the MIT license. See dynasm.lua for full copyright notice. -*/ - -#include -#include -#include -#include - -#define DASM_ARCH "arm" - -#ifndef DASM_EXTERN -#define DASM_EXTERN(a,b,c,d) 0 -#endif - -/* Action definitions. */ -enum { - DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, - /* The following actions need a buffer position. */ - DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, - /* The following actions also have an argument. */ - DASM_REL_PC, DASM_LABEL_PC, - DASM_IMM, DASM_IMM12, DASM_IMM16, DASM_IMML8, DASM_IMML12, DASM_IMMV8, - DASM__MAX -}; - -/* Maximum number of section buffer positions for a single dasm_put() call. */ -#define DASM_MAXSECPOS 25 - -/* DynASM encoder status codes. Action list offset or number are or'ed in. */ -#define DASM_S_OK 0x00000000 -#define DASM_S_NOMEM 0x01000000 -#define DASM_S_PHASE 0x02000000 -#define DASM_S_MATCH_SEC 0x03000000 -#define DASM_S_RANGE_I 0x11000000 -#define DASM_S_RANGE_SEC 0x12000000 -#define DASM_S_RANGE_LG 0x13000000 -#define DASM_S_RANGE_PC 0x14000000 -#define DASM_S_RANGE_REL 0x15000000 -#define DASM_S_UNDEF_LG 0x21000000 -#define DASM_S_UNDEF_PC 0x22000000 - -/* Macros to convert positions (8 bit section + 24 bit index). */ -#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) -#define DASM_POS2BIAS(pos) ((pos)&0xff000000) -#define DASM_SEC2POS(sec) ((sec)<<24) -#define DASM_POS2SEC(pos) ((pos)>>24) -#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) - -/* Action list type. */ -typedef const unsigned int *dasm_ActList; - -/* Per-section structure. */ -typedef struct dasm_Section { - int *rbuf; /* Biased buffer pointer (negative section bias). */ - int *buf; /* True buffer pointer. */ - size_t bsize; /* Buffer size in bytes. */ - int pos; /* Biased buffer position. */ - int epos; /* End of biased buffer position - max single put. */ - int ofs; /* Byte offset into section. */ -} dasm_Section; - -/* Core structure holding the DynASM encoding state. */ -struct dasm_State { - size_t psize; /* Allocated size of this structure. */ - dasm_ActList actionlist; /* Current actionlist pointer. */ - int *lglabels; /* Local/global chain/pos ptrs. */ - size_t lgsize; - int *pclabels; /* PC label chains/pos ptrs. */ - size_t pcsize; - void **globals; /* Array of globals (bias -10). */ - dasm_Section *section; /* Pointer to active section. */ - size_t codesize; /* Total size of all code sections. */ - int maxsection; /* 0 <= sectionidx < maxsection. */ - int status; /* Status code. */ - dasm_Section sections[1]; /* All sections. Alloc-extended. */ -}; - -/* The size of the core structure depends on the max. number of sections. */ -#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) - - -/* Initialize DynASM state. */ -void dasm_init(Dst_DECL, int maxsection) -{ - dasm_State *D; - size_t psz = 0; - int i; - Dst_REF = NULL; - DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); - D = Dst_REF; - D->psize = psz; - D->lglabels = NULL; - D->lgsize = 0; - D->pclabels = NULL; - D->pcsize = 0; - D->globals = NULL; - D->maxsection = maxsection; - for (i = 0; i < maxsection; i++) { - D->sections[i].buf = NULL; /* Need this for pass3. */ - D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); - D->sections[i].bsize = 0; - D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ - } -} - -/* Free DynASM state. */ -void dasm_free(Dst_DECL) -{ - dasm_State *D = Dst_REF; - int i; - for (i = 0; i < D->maxsection; i++) - if (D->sections[i].buf) - DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); - if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); - if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); - DASM_M_FREE(Dst, D, D->psize); -} - -/* Setup global label array. Must be called before dasm_setup(). */ -void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) -{ - dasm_State *D = Dst_REF; - D->globals = gl - 10; /* Negative bias to compensate for locals. */ - DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); -} - -/* Grow PC label array. Can be called after dasm_setup(), too. */ -void dasm_growpc(Dst_DECL, unsigned int maxpc) -{ - dasm_State *D = Dst_REF; - size_t osz = D->pcsize; - DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); - memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); -} - -/* Setup encoder. */ -void dasm_setup(Dst_DECL, const void *actionlist) -{ - dasm_State *D = Dst_REF; - int i; - D->actionlist = (dasm_ActList)actionlist; - D->status = DASM_S_OK; - D->section = &D->sections[0]; - memset((void *)D->lglabels, 0, D->lgsize); - if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); - for (i = 0; i < D->maxsection; i++) { - D->sections[i].pos = DASM_SEC2POS(i); - D->sections[i].ofs = 0; - } -} - - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) { \ - D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) -#define CKPL(kind, st) \ - do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ - D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) -#else -#define CK(x, st) ((void)0) -#define CKPL(kind, st) ((void)0) -#endif - -static int dasm_imm12(unsigned int n) -{ - int i; - for (i = 0; i < 16; i++, n = (n << 2) | (n >> 30)) - if (n <= 255) return (int)(n + (i << 8)); - return -1; -} - -/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ -void dasm_put(Dst_DECL, int start, ...) -{ - va_list ap; - dasm_State *D = Dst_REF; - dasm_ActList p = D->actionlist + start; - dasm_Section *sec = D->section; - int pos = sec->pos, ofs = sec->ofs; - int *b; - - if (pos >= sec->epos) { - DASM_M_GROW(Dst, int, sec->buf, sec->bsize, - sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); - sec->rbuf = sec->buf - DASM_POS2BIAS(pos); - sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); - } - - b = sec->rbuf; - b[pos++] = start; - - va_start(ap, start); - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - if (action >= DASM__MAX) { - ofs += 4; - } else { - int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; - switch (action) { - case DASM_STOP: goto stop; - case DASM_SECTION: - n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); - D->section = &D->sections[n]; goto stop; - case DASM_ESC: p++; ofs += 4; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; - case DASM_REL_LG: - n = (ins & 2047) - 10; pl = D->lglabels + n; - /* Bkwd rel or global. */ - if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } - pl += 10; n = *pl; - if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ - goto linkrel; - case DASM_REL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putrel: - n = *pl; - if (n < 0) { /* Label exists. Get label pos and store it. */ - b[pos] = -n; - } else { - linkrel: - b[pos] = n; /* Else link to rel chain, anchored at label. */ - *pl = pos; - } - pos++; - break; - case DASM_LABEL_LG: - pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; - case DASM_LABEL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putlabel: - n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; - } - *pl = -pos; /* Label exists now. */ - b[pos++] = ofs; /* Store pass1 offset estimate. */ - break; - case DASM_IMM: - case DASM_IMM16: -#ifdef DASM_CHECKS - CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); - if ((ins & 0x8000)) - CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); - else - CK((n>>((ins>>5)&31)) == 0, RANGE_I); -#endif - b[pos++] = n; - break; - case DASM_IMMV8: - CK((n & 3) == 0, RANGE_I); - n >>= 2; - case DASM_IMML8: - case DASM_IMML12: - CK(n >= 0 ? ((n>>((ins>>5)&31)) == 0) : - (((-n)>>((ins>>5)&31)) == 0), RANGE_I); - b[pos++] = n; - break; - case DASM_IMM12: - CK(dasm_imm12((unsigned int)n) != -1, RANGE_I); - b[pos++] = n; - break; - } - } - } -stop: - va_end(ap); - sec->pos = pos; - sec->ofs = ofs; -} -#undef CK - -/* Pass 2: Link sections, shrink aligns, fix label offsets. */ -int dasm_link(Dst_DECL, size_t *szp) -{ - dasm_State *D = Dst_REF; - int secnum; - int ofs = 0; - -#ifdef DASM_CHECKS - *szp = 0; - if (D->status != DASM_S_OK) return D->status; - { - int pc; - for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) - if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; - } -#endif - - { /* Handle globals not defined in this translation unit. */ - int idx; - for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { - int n = D->lglabels[idx]; - /* Undefined label: Collapse rel chain and replace with marker (< 0). */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } - } - } - - /* Combine all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->rbuf; - int pos = DASM_SEC2POS(secnum); - int lastpos = sec->pos; - - while (pos != lastpos) { - dasm_ActList p = D->actionlist + b[pos++]; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: p++; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; - case DASM_REL_LG: case DASM_REL_PC: pos++; break; - case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; - case DASM_IMM: case DASM_IMM12: case DASM_IMM16: - case DASM_IMML8: case DASM_IMML12: case DASM_IMMV8: pos++; break; - } - } - stop: (void)0; - } - ofs += sec->ofs; /* Next section starts right after current section. */ - } - - D->codesize = ofs; /* Total size of all code sections */ - *szp = ofs; - return DASM_S_OK; -} - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) -#else -#define CK(x, st) ((void)0) -#endif - -/* Pass 3: Encode sections. */ -int dasm_encode(Dst_DECL, void *buffer) -{ - dasm_State *D = Dst_REF; - char *base = (char *)buffer; - unsigned int *cp = (unsigned int *)buffer; - int secnum; - - /* Encode all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->buf; - int *endb = sec->rbuf + sec->pos; - - while (b != endb) { - dasm_ActList p = D->actionlist + *b++; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: *cp++ = *p++; break; - case DASM_REL_EXT: - n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048)); - goto patchrel; - case DASM_ALIGN: - ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000; - break; - case DASM_REL_LG: - CK(n >= 0, UNDEF_LG); - case DASM_REL_PC: - CK(n >= 0, UNDEF_PC); - n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) - 4; - patchrel: - if ((ins & 0x800) == 0) { - CK((n & 3) == 0 && ((n+0x02000000) >> 26) == 0, RANGE_REL); - cp[-1] |= ((n >> 2) & 0x00ffffff); - } else if ((ins & 0x1000)) { - CK((n & 3) == 0 && -256 <= n && n <= 256, RANGE_REL); - goto patchimml8; - } else if ((ins & 0x2000) == 0) { - CK((n & 3) == 0 && -4096 <= n && n <= 4096, RANGE_REL); - goto patchimml; - } else { - CK((n & 3) == 0 && -1020 <= n && n <= 1020, RANGE_REL); - n >>= 2; - goto patchimml; - } - break; - case DASM_LABEL_LG: - ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); - break; - case DASM_LABEL_PC: break; - case DASM_IMM: - cp[-1] |= ((n>>((ins>>10)&31)) & ((1<<((ins>>5)&31))-1)) << (ins&31); - break; - case DASM_IMM12: - cp[-1] |= dasm_imm12((unsigned int)n); - break; - case DASM_IMM16: - cp[-1] |= ((n & 0xf000) << 4) | (n & 0x0fff); - break; - case DASM_IMML8: patchimml8: - cp[-1] |= n >= 0 ? (0x00800000 | (n & 0x0f) | ((n & 0xf0) << 4)) : - ((-n & 0x0f) | ((-n & 0xf0) << 4)); - break; - case DASM_IMML12: case DASM_IMMV8: patchimml: - cp[-1] |= n >= 0 ? (0x00800000 | n) : (-n); - break; - default: *cp++ = ins; break; - } - } - stop: (void)0; - } - } - - if (base + D->codesize != (char *)cp) /* Check for phase errors. */ - return DASM_S_PHASE; - return DASM_S_OK; -} -#undef CK - -/* Get PC label offset. */ -int dasm_getpclabel(Dst_DECL, unsigned int pc) -{ - dasm_State *D = Dst_REF; - if (pc*sizeof(int) < D->pcsize) { - int pos = D->pclabels[pc]; - if (pos < 0) return *DASM_POS2PTR(D, -pos); - if (pos > 0) return -1; /* Undefined. */ - } - return -2; /* Unused or out of range. */ -} - -#ifdef DASM_CHECKS -/* Optional sanity checker to call between isolated encoding steps. */ -int dasm_checkstep(Dst_DECL, int secmatch) -{ - dasm_State *D = Dst_REF; - if (D->status == DASM_S_OK) { - int i; - for (i = 1; i <= 9; i++) { - if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } - D->lglabels[i] = 0; - } - } - if (D->status == DASM_S_OK && secmatch >= 0 && - D->section != &D->sections[secmatch]) - D->status = DASM_S_MATCH_SEC|(D->section-D->sections); - return D->status; -} -#endif - diff --git a/compiler/code-gen/assembly/include/dasm_arm64.h b/compiler/code-gen/assembly/include/dasm_arm64.h deleted file mode 100644 index d64e60a..0000000 --- a/compiler/code-gen/assembly/include/dasm_arm64.h +++ /dev/null @@ -1,518 +0,0 @@ -/* -** DynASM ARM64 encoding engine. -** Copyright (C) 2005-2016 Mike Pall. All rights reserved. -** Released under the MIT license. See dynasm.lua for full copyright notice. -*/ - -#include -#include -#include -#include - -#define DASM_ARCH "arm64" - -#ifndef DASM_EXTERN -#define DASM_EXTERN(a,b,c,d) 0 -#endif - -/* Action definitions. */ -enum { - DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, - /* The following actions need a buffer position. */ - DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, - /* The following actions also have an argument. */ - DASM_REL_PC, DASM_LABEL_PC, - DASM_IMM, DASM_IMM6, DASM_IMM12, DASM_IMM13W, DASM_IMM13X, DASM_IMML, - DASM__MAX -}; - -/* Maximum number of section buffer positions for a single dasm_put() call. */ -#define DASM_MAXSECPOS 25 - -/* DynASM encoder status codes. Action list offset or number are or'ed in. */ -#define DASM_S_OK 0x00000000 -#define DASM_S_NOMEM 0x01000000 -#define DASM_S_PHASE 0x02000000 -#define DASM_S_MATCH_SEC 0x03000000 -#define DASM_S_RANGE_I 0x11000000 -#define DASM_S_RANGE_SEC 0x12000000 -#define DASM_S_RANGE_LG 0x13000000 -#define DASM_S_RANGE_PC 0x14000000 -#define DASM_S_RANGE_REL 0x15000000 -#define DASM_S_UNDEF_LG 0x21000000 -#define DASM_S_UNDEF_PC 0x22000000 - -/* Macros to convert positions (8 bit section + 24 bit index). */ -#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) -#define DASM_POS2BIAS(pos) ((pos)&0xff000000) -#define DASM_SEC2POS(sec) ((sec)<<24) -#define DASM_POS2SEC(pos) ((pos)>>24) -#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) - -/* Action list type. */ -typedef const unsigned int *dasm_ActList; - -/* Per-section structure. */ -typedef struct dasm_Section { - int *rbuf; /* Biased buffer pointer (negative section bias). */ - int *buf; /* True buffer pointer. */ - size_t bsize; /* Buffer size in bytes. */ - int pos; /* Biased buffer position. */ - int epos; /* End of biased buffer position - max single put. */ - int ofs; /* Byte offset into section. */ -} dasm_Section; - -/* Core structure holding the DynASM encoding state. */ -struct dasm_State { - size_t psize; /* Allocated size of this structure. */ - dasm_ActList actionlist; /* Current actionlist pointer. */ - int *lglabels; /* Local/global chain/pos ptrs. */ - size_t lgsize; - int *pclabels; /* PC label chains/pos ptrs. */ - size_t pcsize; - void **globals; /* Array of globals (bias -10). */ - dasm_Section *section; /* Pointer to active section. */ - size_t codesize; /* Total size of all code sections. */ - int maxsection; /* 0 <= sectionidx < maxsection. */ - int status; /* Status code. */ - dasm_Section sections[1]; /* All sections. Alloc-extended. */ -}; - -/* The size of the core structure depends on the max. number of sections. */ -#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) - - -/* Initialize DynASM state. */ -void dasm_init(Dst_DECL, int maxsection) -{ - dasm_State *D; - size_t psz = 0; - int i; - Dst_REF = NULL; - DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); - D = Dst_REF; - D->psize = psz; - D->lglabels = NULL; - D->lgsize = 0; - D->pclabels = NULL; - D->pcsize = 0; - D->globals = NULL; - D->maxsection = maxsection; - for (i = 0; i < maxsection; i++) { - D->sections[i].buf = NULL; /* Need this for pass3. */ - D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); - D->sections[i].bsize = 0; - D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ - } -} - -/* Free DynASM state. */ -void dasm_free(Dst_DECL) -{ - dasm_State *D = Dst_REF; - int i; - for (i = 0; i < D->maxsection; i++) - if (D->sections[i].buf) - DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); - if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); - if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); - DASM_M_FREE(Dst, D, D->psize); -} - -/* Setup global label array. Must be called before dasm_setup(). */ -void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) -{ - dasm_State *D = Dst_REF; - D->globals = gl - 10; /* Negative bias to compensate for locals. */ - DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); -} - -/* Grow PC label array. Can be called after dasm_setup(), too. */ -void dasm_growpc(Dst_DECL, unsigned int maxpc) -{ - dasm_State *D = Dst_REF; - size_t osz = D->pcsize; - DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); - memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); -} - -/* Setup encoder. */ -void dasm_setup(Dst_DECL, const void *actionlist) -{ - dasm_State *D = Dst_REF; - int i; - D->actionlist = (dasm_ActList)actionlist; - D->status = DASM_S_OK; - D->section = &D->sections[0]; - memset((void *)D->lglabels, 0, D->lgsize); - if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); - for (i = 0; i < D->maxsection; i++) { - D->sections[i].pos = DASM_SEC2POS(i); - D->sections[i].ofs = 0; - } -} - - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) { \ - D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) -#define CKPL(kind, st) \ - do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ - D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) -#else -#define CK(x, st) ((void)0) -#define CKPL(kind, st) ((void)0) -#endif - -static int dasm_imm12(unsigned int n) -{ - if ((n >> 12) == 0) - return n; - else if ((n & 0xff000fff) == 0) - return (n >> 12) | 0x1000; - else - return -1; -} - -static int dasm_ffs(unsigned long long x) -{ - int n = -1; - while (x) { x >>= 1; n++; } - return n; -} - -static int dasm_imm13(int lo, int hi) -{ - int inv = 0, w = 64, s = 0xfff, xa, xb; - unsigned long long n = (((unsigned long long)hi) << 32) | (unsigned int)lo; - unsigned long long m = 1ULL, a, b, c; - if (n & 1) { n = ~n; inv = 1; } - a = n & -n; b = (n+a)&-(n+a); c = (n+a-b)&-(n+a-b); - xa = dasm_ffs(a); xb = dasm_ffs(b); - if (c) { - w = dasm_ffs(c) - xa; - if (w == 32) m = 0x0000000100000001UL; - else if (w == 16) m = 0x0001000100010001UL; - else if (w == 8) m = 0x0101010101010101UL; - else if (w == 4) m = 0x1111111111111111UL; - else if (w == 2) m = 0x5555555555555555UL; - else return -1; - s = (-2*w & 0x3f) - 1; - } else if (!a) { - return -1; - } else if (xb == -1) { - xb = 64; - } - if ((b-a) * m != n) return -1; - if (inv) { - return ((w - xb) << 6) | (s+w+xa-xb); - } else { - return ((w - xa) << 6) | (s+xb-xa); - } - return -1; -} - -/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ -void dasm_put(Dst_DECL, int start, ...) -{ - va_list ap; - dasm_State *D = Dst_REF; - dasm_ActList p = D->actionlist + start; - dasm_Section *sec = D->section; - int pos = sec->pos, ofs = sec->ofs; - int *b; - - if (pos >= sec->epos) { - DASM_M_GROW(Dst, int, sec->buf, sec->bsize, - sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); - sec->rbuf = sec->buf - DASM_POS2BIAS(pos); - sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); - } - - b = sec->rbuf; - b[pos++] = start; - - va_start(ap, start); - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - if (action >= DASM__MAX) { - ofs += 4; - } else { - int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; - switch (action) { - case DASM_STOP: goto stop; - case DASM_SECTION: - n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); - D->section = &D->sections[n]; goto stop; - case DASM_ESC: p++; ofs += 4; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; - case DASM_REL_LG: - n = (ins & 2047) - 10; pl = D->lglabels + n; - /* Bkwd rel or global. */ - if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } - pl += 10; n = *pl; - if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ - goto linkrel; - case DASM_REL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putrel: - n = *pl; - if (n < 0) { /* Label exists. Get label pos and store it. */ - b[pos] = -n; - } else { - linkrel: - b[pos] = n; /* Else link to rel chain, anchored at label. */ - *pl = pos; - } - pos++; - break; - case DASM_LABEL_LG: - pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; - case DASM_LABEL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putlabel: - n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; - } - *pl = -pos; /* Label exists now. */ - b[pos++] = ofs; /* Store pass1 offset estimate. */ - break; - case DASM_IMM: - CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); - n >>= ((ins>>10)&31); -#ifdef DASM_CHECKS - if ((ins & 0x8000)) - CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); - else - CK((n>>((ins>>5)&31)) == 0, RANGE_I); -#endif - b[pos++] = n; - break; - case DASM_IMM6: - CK((n >> 6) == 0, RANGE_I); - b[pos++] = n; - break; - case DASM_IMM12: - CK(dasm_imm12((unsigned int)n) != -1, RANGE_I); - b[pos++] = n; - break; - case DASM_IMM13W: - CK(dasm_imm13(n, n) != -1, RANGE_I); - b[pos++] = n; - break; - case DASM_IMM13X: { - int m = va_arg(ap, int); - CK(dasm_imm13(n, m) != -1, RANGE_I); - b[pos++] = n; - b[pos++] = m; - break; - } - case DASM_IMML: { -#ifdef DASM_CHECKS - int scale = (p[-2] >> 30); - CK((!(n & ((1<>scale) < 4096) || - (unsigned int)(n+256) < 512, RANGE_I); -#endif - b[pos++] = n; - break; - } - } - } - } -stop: - va_end(ap); - sec->pos = pos; - sec->ofs = ofs; -} -#undef CK - -/* Pass 2: Link sections, shrink aligns, fix label offsets. */ -int dasm_link(Dst_DECL, size_t *szp) -{ - dasm_State *D = Dst_REF; - int secnum; - int ofs = 0; - -#ifdef DASM_CHECKS - *szp = 0; - if (D->status != DASM_S_OK) return D->status; - { - int pc; - for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) - if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; - } -#endif - - { /* Handle globals not defined in this translation unit. */ - int idx; - for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { - int n = D->lglabels[idx]; - /* Undefined label: Collapse rel chain and replace with marker (< 0). */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } - } - } - - /* Combine all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->rbuf; - int pos = DASM_SEC2POS(secnum); - int lastpos = sec->pos; - - while (pos != lastpos) { - dasm_ActList p = D->actionlist + b[pos++]; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: p++; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; - case DASM_REL_LG: case DASM_REL_PC: pos++; break; - case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; - case DASM_IMM: case DASM_IMM6: case DASM_IMM12: case DASM_IMM13W: - case DASM_IMML: pos++; break; - case DASM_IMM13X: pos += 2; break; - } - } - stop: (void)0; - } - ofs += sec->ofs; /* Next section starts right after current section. */ - } - - D->codesize = ofs; /* Total size of all code sections */ - *szp = ofs; - return DASM_S_OK; -} - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) -#else -#define CK(x, st) ((void)0) -#endif - -/* Pass 3: Encode sections. */ -int dasm_encode(Dst_DECL, void *buffer) -{ - dasm_State *D = Dst_REF; - char *base = (char *)buffer; - unsigned int *cp = (unsigned int *)buffer; - int secnum; - - /* Encode all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->buf; - int *endb = sec->rbuf + sec->pos; - - while (b != endb) { - dasm_ActList p = D->actionlist + *b++; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: *cp++ = *p++; break; - case DASM_REL_EXT: - n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048)); - goto patchrel; - case DASM_ALIGN: - ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000; - break; - case DASM_REL_LG: - CK(n >= 0, UNDEF_LG); - case DASM_REL_PC: - CK(n >= 0, UNDEF_PC); - n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) + 4; - patchrel: - if (!(ins & 0xf800)) { /* B, BL */ - CK((n & 3) == 0 && ((n+0x08000000) >> 28) == 0, RANGE_REL); - cp[-1] |= ((n >> 2) & 0x03ffffff); - } else if ((ins & 0x800)) { /* B.cond, CBZ, CBNZ, LDR* literal */ - CK((n & 3) == 0 && ((n+0x00100000) >> 21) == 0, RANGE_REL); - cp[-1] |= ((n << 3) & 0x00ffffe0); - } else if ((ins & 0x3000) == 0x2000) { /* ADR */ - CK(((n+0x00100000) >> 21) == 0, RANGE_REL); - cp[-1] |= ((n << 3) & 0x00ffffe0) | ((n & 3) << 29); - } else if ((ins & 0x3000) == 0x3000) { /* ADRP */ - cp[-1] |= ((n >> 9) & 0x00ffffe0) | (((n >> 12) & 3) << 29); - } else if ((ins & 0x1000)) { /* TBZ, TBNZ */ - CK((n & 3) == 0 && ((n+0x00008000) >> 16) == 0, RANGE_REL); - cp[-1] |= ((n << 3) & 0x0007ffe0); - } - break; - case DASM_LABEL_LG: - ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); - break; - case DASM_LABEL_PC: break; - case DASM_IMM: - cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); - break; - case DASM_IMM6: - cp[-1] |= ((n&31) << 19) | ((n&32) << 26); - break; - case DASM_IMM12: - cp[-1] |= (dasm_imm12((unsigned int)n) << 10); - break; - case DASM_IMM13W: - cp[-1] |= (dasm_imm13(n, n) << 10); - break; - case DASM_IMM13X: - cp[-1] |= (dasm_imm13(n, *b++) << 10); - break; - case DASM_IMML: { - int scale = (p[-2] >> 30); - cp[-1] |= (!(n & ((1<>scale) < 4096) ? - ((n << (10-scale)) | 0x01000000) : ((n & 511) << 12); - break; - } - default: *cp++ = ins; break; - } - } - stop: (void)0; - } - } - - if (base + D->codesize != (char *)cp) /* Check for phase errors. */ - return DASM_S_PHASE; - return DASM_S_OK; -} -#undef CK - -/* Get PC label offset. */ -int dasm_getpclabel(Dst_DECL, unsigned int pc) -{ - dasm_State *D = Dst_REF; - if (pc*sizeof(int) < D->pcsize) { - int pos = D->pclabels[pc]; - if (pos < 0) return *DASM_POS2PTR(D, -pos); - if (pos > 0) return -1; /* Undefined. */ - } - return -2; /* Unused or out of range. */ -} - -#ifdef DASM_CHECKS -/* Optional sanity checker to call between isolated encoding steps. */ -int dasm_checkstep(Dst_DECL, int secmatch) -{ - dasm_State *D = Dst_REF; - if (D->status == DASM_S_OK) { - int i; - for (i = 1; i <= 9; i++) { - if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } - D->lglabels[i] = 0; - } - } - if (D->status == DASM_S_OK && secmatch >= 0 && - D->section != &D->sections[secmatch]) - D->status = DASM_S_MATCH_SEC|(D->section-D->sections); - return D->status; -} -#endif - diff --git a/compiler/code-gen/assembly/include/dasm_mips.h b/compiler/code-gen/assembly/include/dasm_mips.h deleted file mode 100644 index c10528f..0000000 --- a/compiler/code-gen/assembly/include/dasm_mips.h +++ /dev/null @@ -1,416 +0,0 @@ -/* -** DynASM MIPS encoding engine. -** Copyright (C) 2005-2016 Mike Pall. All rights reserved. -** Released under the MIT license. See dynasm.lua for full copyright notice. -*/ - -#include -#include -#include -#include - -#define DASM_ARCH "mips" - -#ifndef DASM_EXTERN -#define DASM_EXTERN(a,b,c,d) 0 -#endif - -/* Action definitions. */ -enum { - DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, - /* The following actions need a buffer position. */ - DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, - /* The following actions also have an argument. */ - DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, - DASM__MAX -}; - -/* Maximum number of section buffer positions for a single dasm_put() call. */ -#define DASM_MAXSECPOS 25 - -/* DynASM encoder status codes. Action list offset or number are or'ed in. */ -#define DASM_S_OK 0x00000000 -#define DASM_S_NOMEM 0x01000000 -#define DASM_S_PHASE 0x02000000 -#define DASM_S_MATCH_SEC 0x03000000 -#define DASM_S_RANGE_I 0x11000000 -#define DASM_S_RANGE_SEC 0x12000000 -#define DASM_S_RANGE_LG 0x13000000 -#define DASM_S_RANGE_PC 0x14000000 -#define DASM_S_RANGE_REL 0x15000000 -#define DASM_S_UNDEF_LG 0x21000000 -#define DASM_S_UNDEF_PC 0x22000000 - -/* Macros to convert positions (8 bit section + 24 bit index). */ -#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) -#define DASM_POS2BIAS(pos) ((pos)&0xff000000) -#define DASM_SEC2POS(sec) ((sec)<<24) -#define DASM_POS2SEC(pos) ((pos)>>24) -#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) - -/* Action list type. */ -typedef const unsigned int *dasm_ActList; - -/* Per-section structure. */ -typedef struct dasm_Section { - int *rbuf; /* Biased buffer pointer (negative section bias). */ - int *buf; /* True buffer pointer. */ - size_t bsize; /* Buffer size in bytes. */ - int pos; /* Biased buffer position. */ - int epos; /* End of biased buffer position - max single put. */ - int ofs; /* Byte offset into section. */ -} dasm_Section; - -/* Core structure holding the DynASM encoding state. */ -struct dasm_State { - size_t psize; /* Allocated size of this structure. */ - dasm_ActList actionlist; /* Current actionlist pointer. */ - int *lglabels; /* Local/global chain/pos ptrs. */ - size_t lgsize; - int *pclabels; /* PC label chains/pos ptrs. */ - size_t pcsize; - void **globals; /* Array of globals (bias -10). */ - dasm_Section *section; /* Pointer to active section. */ - size_t codesize; /* Total size of all code sections. */ - int maxsection; /* 0 <= sectionidx < maxsection. */ - int status; /* Status code. */ - dasm_Section sections[1]; /* All sections. Alloc-extended. */ -}; - -/* The size of the core structure depends on the max. number of sections. */ -#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) - - -/* Initialize DynASM state. */ -void dasm_init(Dst_DECL, int maxsection) -{ - dasm_State *D; - size_t psz = 0; - int i; - Dst_REF = NULL; - DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); - D = Dst_REF; - D->psize = psz; - D->lglabels = NULL; - D->lgsize = 0; - D->pclabels = NULL; - D->pcsize = 0; - D->globals = NULL; - D->maxsection = maxsection; - for (i = 0; i < maxsection; i++) { - D->sections[i].buf = NULL; /* Need this for pass3. */ - D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); - D->sections[i].bsize = 0; - D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ - } -} - -/* Free DynASM state. */ -void dasm_free(Dst_DECL) -{ - dasm_State *D = Dst_REF; - int i; - for (i = 0; i < D->maxsection; i++) - if (D->sections[i].buf) - DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); - if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); - if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); - DASM_M_FREE(Dst, D, D->psize); -} - -/* Setup global label array. Must be called before dasm_setup(). */ -void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) -{ - dasm_State *D = Dst_REF; - D->globals = gl - 10; /* Negative bias to compensate for locals. */ - DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); -} - -/* Grow PC label array. Can be called after dasm_setup(), too. */ -void dasm_growpc(Dst_DECL, unsigned int maxpc) -{ - dasm_State *D = Dst_REF; - size_t osz = D->pcsize; - DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); - memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); -} - -/* Setup encoder. */ -void dasm_setup(Dst_DECL, const void *actionlist) -{ - dasm_State *D = Dst_REF; - int i; - D->actionlist = (dasm_ActList)actionlist; - D->status = DASM_S_OK; - D->section = &D->sections[0]; - memset((void *)D->lglabels, 0, D->lgsize); - if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); - for (i = 0; i < D->maxsection; i++) { - D->sections[i].pos = DASM_SEC2POS(i); - D->sections[i].ofs = 0; - } -} - - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) { \ - D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) -#define CKPL(kind, st) \ - do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ - D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) -#else -#define CK(x, st) ((void)0) -#define CKPL(kind, st) ((void)0) -#endif - -/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ -void dasm_put(Dst_DECL, int start, ...) -{ - va_list ap; - dasm_State *D = Dst_REF; - dasm_ActList p = D->actionlist + start; - dasm_Section *sec = D->section; - int pos = sec->pos, ofs = sec->ofs; - int *b; - - if (pos >= sec->epos) { - DASM_M_GROW(Dst, int, sec->buf, sec->bsize, - sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); - sec->rbuf = sec->buf - DASM_POS2BIAS(pos); - sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); - } - - b = sec->rbuf; - b[pos++] = start; - - va_start(ap, start); - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16) - 0xff00; - if (action >= DASM__MAX) { - ofs += 4; - } else { - int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; - switch (action) { - case DASM_STOP: goto stop; - case DASM_SECTION: - n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); - D->section = &D->sections[n]; goto stop; - case DASM_ESC: p++; ofs += 4; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; - case DASM_REL_LG: - n = (ins & 2047) - 10; pl = D->lglabels + n; - /* Bkwd rel or global. */ - if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } - pl += 10; n = *pl; - if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ - goto linkrel; - case DASM_REL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putrel: - n = *pl; - if (n < 0) { /* Label exists. Get label pos and store it. */ - b[pos] = -n; - } else { - linkrel: - b[pos] = n; /* Else link to rel chain, anchored at label. */ - *pl = pos; - } - pos++; - break; - case DASM_LABEL_LG: - pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; - case DASM_LABEL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putlabel: - n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; - } - *pl = -pos; /* Label exists now. */ - b[pos++] = ofs; /* Store pass1 offset estimate. */ - break; - case DASM_IMM: -#ifdef DASM_CHECKS - CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); -#endif - n >>= ((ins>>10)&31); -#ifdef DASM_CHECKS - if (ins & 0x8000) - CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); - else - CK((n>>((ins>>5)&31)) == 0, RANGE_I); -#endif - b[pos++] = n; - break; - } - } - } -stop: - va_end(ap); - sec->pos = pos; - sec->ofs = ofs; -} -#undef CK - -/* Pass 2: Link sections, shrink aligns, fix label offsets. */ -int dasm_link(Dst_DECL, size_t *szp) -{ - dasm_State *D = Dst_REF; - int secnum; - int ofs = 0; - -#ifdef DASM_CHECKS - *szp = 0; - if (D->status != DASM_S_OK) return D->status; - { - int pc; - for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) - if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; - } -#endif - - { /* Handle globals not defined in this translation unit. */ - int idx; - for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { - int n = D->lglabels[idx]; - /* Undefined label: Collapse rel chain and replace with marker (< 0). */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } - } - } - - /* Combine all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->rbuf; - int pos = DASM_SEC2POS(secnum); - int lastpos = sec->pos; - - while (pos != lastpos) { - dasm_ActList p = D->actionlist + b[pos++]; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16) - 0xff00; - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: p++; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; - case DASM_REL_LG: case DASM_REL_PC: pos++; break; - case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; - case DASM_IMM: pos++; break; - } - } - stop: (void)0; - } - ofs += sec->ofs; /* Next section starts right after current section. */ - } - - D->codesize = ofs; /* Total size of all code sections */ - *szp = ofs; - return DASM_S_OK; -} - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) -#else -#define CK(x, st) ((void)0) -#endif - -/* Pass 3: Encode sections. */ -int dasm_encode(Dst_DECL, void *buffer) -{ - dasm_State *D = Dst_REF; - char *base = (char *)buffer; - unsigned int *cp = (unsigned int *)buffer; - int secnum; - - /* Encode all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->buf; - int *endb = sec->rbuf + sec->pos; - - while (b != endb) { - dasm_ActList p = D->actionlist + *b++; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16) - 0xff00; - int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: *cp++ = *p++; break; - case DASM_REL_EXT: - n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1); - goto patchrel; - case DASM_ALIGN: - ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000; - break; - case DASM_REL_LG: - CK(n >= 0, UNDEF_LG); - case DASM_REL_PC: - CK(n >= 0, UNDEF_PC); - n = *DASM_POS2PTR(D, n); - if (ins & 2048) - n = n - (int)((char *)cp - base); - else - n = (n + (int)base) & 0x0fffffff; - patchrel: - CK((n & 3) == 0 && - ((n + ((ins & 2048) ? 0x00020000 : 0)) >> - ((ins & 2048) ? 18 : 28)) == 0, RANGE_REL); - cp[-1] |= ((n>>2) & ((ins & 2048) ? 0x0000ffff: 0x03ffffff)); - break; - case DASM_LABEL_LG: - ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); - break; - case DASM_LABEL_PC: break; - case DASM_IMM: - cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); - break; - default: *cp++ = ins; break; - } - } - stop: (void)0; - } - } - - if (base + D->codesize != (char *)cp) /* Check for phase errors. */ - return DASM_S_PHASE; - return DASM_S_OK; -} -#undef CK - -/* Get PC label offset. */ -int dasm_getpclabel(Dst_DECL, unsigned int pc) -{ - dasm_State *D = Dst_REF; - if (pc*sizeof(int) < D->pcsize) { - int pos = D->pclabels[pc]; - if (pos < 0) return *DASM_POS2PTR(D, -pos); - if (pos > 0) return -1; /* Undefined. */ - } - return -2; /* Unused or out of range. */ -} - -#ifdef DASM_CHECKS -/* Optional sanity checker to call between isolated encoding steps. */ -int dasm_checkstep(Dst_DECL, int secmatch) -{ - dasm_State *D = Dst_REF; - if (D->status == DASM_S_OK) { - int i; - for (i = 1; i <= 9; i++) { - if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } - D->lglabels[i] = 0; - } - } - if (D->status == DASM_S_OK && secmatch >= 0 && - D->section != &D->sections[secmatch]) - D->status = DASM_S_MATCH_SEC|(D->section-D->sections); - return D->status; -} -#endif - diff --git a/compiler/code-gen/assembly/include/dasm_ppc.h b/compiler/code-gen/assembly/include/dasm_ppc.h deleted file mode 100644 index 3f267fb..0000000 --- a/compiler/code-gen/assembly/include/dasm_ppc.h +++ /dev/null @@ -1,419 +0,0 @@ -/* -** DynASM PPC/PPC64 encoding engine. -** Copyright (C) 2005-2016 Mike Pall. All rights reserved. -** Released under the MIT license. See dynasm.lua for full copyright notice. -*/ - -#include -#include -#include -#include - -#define DASM_ARCH "ppc" - -#ifndef DASM_EXTERN -#define DASM_EXTERN(a,b,c,d) 0 -#endif - -/* Action definitions. */ -enum { - DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, - /* The following actions need a buffer position. */ - DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, - /* The following actions also have an argument. */ - DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, DASM_IMMSH, - DASM__MAX -}; - -/* Maximum number of section buffer positions for a single dasm_put() call. */ -#define DASM_MAXSECPOS 25 - -/* DynASM encoder status codes. Action list offset or number are or'ed in. */ -#define DASM_S_OK 0x00000000 -#define DASM_S_NOMEM 0x01000000 -#define DASM_S_PHASE 0x02000000 -#define DASM_S_MATCH_SEC 0x03000000 -#define DASM_S_RANGE_I 0x11000000 -#define DASM_S_RANGE_SEC 0x12000000 -#define DASM_S_RANGE_LG 0x13000000 -#define DASM_S_RANGE_PC 0x14000000 -#define DASM_S_RANGE_REL 0x15000000 -#define DASM_S_UNDEF_LG 0x21000000 -#define DASM_S_UNDEF_PC 0x22000000 - -/* Macros to convert positions (8 bit section + 24 bit index). */ -#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) -#define DASM_POS2BIAS(pos) ((pos)&0xff000000) -#define DASM_SEC2POS(sec) ((sec)<<24) -#define DASM_POS2SEC(pos) ((pos)>>24) -#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) - -/* Action list type. */ -typedef const unsigned int *dasm_ActList; - -/* Per-section structure. */ -typedef struct dasm_Section { - int *rbuf; /* Biased buffer pointer (negative section bias). */ - int *buf; /* True buffer pointer. */ - size_t bsize; /* Buffer size in bytes. */ - int pos; /* Biased buffer position. */ - int epos; /* End of biased buffer position - max single put. */ - int ofs; /* Byte offset into section. */ -} dasm_Section; - -/* Core structure holding the DynASM encoding state. */ -struct dasm_State { - size_t psize; /* Allocated size of this structure. */ - dasm_ActList actionlist; /* Current actionlist pointer. */ - int *lglabels; /* Local/global chain/pos ptrs. */ - size_t lgsize; - int *pclabels; /* PC label chains/pos ptrs. */ - size_t pcsize; - void **globals; /* Array of globals (bias -10). */ - dasm_Section *section; /* Pointer to active section. */ - size_t codesize; /* Total size of all code sections. */ - int maxsection; /* 0 <= sectionidx < maxsection. */ - int status; /* Status code. */ - dasm_Section sections[1]; /* All sections. Alloc-extended. */ -}; - -/* The size of the core structure depends on the max. number of sections. */ -#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) - - -/* Initialize DynASM state. */ -void dasm_init(Dst_DECL, int maxsection) -{ - dasm_State *D; - size_t psz = 0; - int i; - Dst_REF = NULL; - DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); - D = Dst_REF; - D->psize = psz; - D->lglabels = NULL; - D->lgsize = 0; - D->pclabels = NULL; - D->pcsize = 0; - D->globals = NULL; - D->maxsection = maxsection; - for (i = 0; i < maxsection; i++) { - D->sections[i].buf = NULL; /* Need this for pass3. */ - D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); - D->sections[i].bsize = 0; - D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ - } -} - -/* Free DynASM state. */ -void dasm_free(Dst_DECL) -{ - dasm_State *D = Dst_REF; - int i; - for (i = 0; i < D->maxsection; i++) - if (D->sections[i].buf) - DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); - if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); - if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); - DASM_M_FREE(Dst, D, D->psize); -} - -/* Setup global label array. Must be called before dasm_setup(). */ -void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) -{ - dasm_State *D = Dst_REF; - D->globals = gl - 10; /* Negative bias to compensate for locals. */ - DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); -} - -/* Grow PC label array. Can be called after dasm_setup(), too. */ -void dasm_growpc(Dst_DECL, unsigned int maxpc) -{ - dasm_State *D = Dst_REF; - size_t osz = D->pcsize; - DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); - memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); -} - -/* Setup encoder. */ -void dasm_setup(Dst_DECL, const void *actionlist) -{ - dasm_State *D = Dst_REF; - int i; - D->actionlist = (dasm_ActList)actionlist; - D->status = DASM_S_OK; - D->section = &D->sections[0]; - memset((void *)D->lglabels, 0, D->lgsize); - if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); - for (i = 0; i < D->maxsection; i++) { - D->sections[i].pos = DASM_SEC2POS(i); - D->sections[i].ofs = 0; - } -} - - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) { \ - D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) -#define CKPL(kind, st) \ - do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ - D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) -#else -#define CK(x, st) ((void)0) -#define CKPL(kind, st) ((void)0) -#endif - -/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ -void dasm_put(Dst_DECL, int start, ...) -{ - va_list ap; - dasm_State *D = Dst_REF; - dasm_ActList p = D->actionlist + start; - dasm_Section *sec = D->section; - int pos = sec->pos, ofs = sec->ofs; - int *b; - - if (pos >= sec->epos) { - DASM_M_GROW(Dst, int, sec->buf, sec->bsize, - sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); - sec->rbuf = sec->buf - DASM_POS2BIAS(pos); - sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); - } - - b = sec->rbuf; - b[pos++] = start; - - va_start(ap, start); - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - if (action >= DASM__MAX) { - ofs += 4; - } else { - int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; - switch (action) { - case DASM_STOP: goto stop; - case DASM_SECTION: - n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); - D->section = &D->sections[n]; goto stop; - case DASM_ESC: p++; ofs += 4; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; - case DASM_REL_LG: - n = (ins & 2047) - 10; pl = D->lglabels + n; - /* Bkwd rel or global. */ - if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } - pl += 10; n = *pl; - if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ - goto linkrel; - case DASM_REL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putrel: - n = *pl; - if (n < 0) { /* Label exists. Get label pos and store it. */ - b[pos] = -n; - } else { - linkrel: - b[pos] = n; /* Else link to rel chain, anchored at label. */ - *pl = pos; - } - pos++; - break; - case DASM_LABEL_LG: - pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; - case DASM_LABEL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putlabel: - n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; - } - *pl = -pos; /* Label exists now. */ - b[pos++] = ofs; /* Store pass1 offset estimate. */ - break; - case DASM_IMM: -#ifdef DASM_CHECKS - CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); -#endif - n >>= ((ins>>10)&31); -#ifdef DASM_CHECKS - if (ins & 0x8000) - CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); - else - CK((n>>((ins>>5)&31)) == 0, RANGE_I); -#endif - b[pos++] = n; - break; - case DASM_IMMSH: - CK((n >> 6) == 0, RANGE_I); - b[pos++] = n; - break; - } - } - } -stop: - va_end(ap); - sec->pos = pos; - sec->ofs = ofs; -} -#undef CK - -/* Pass 2: Link sections, shrink aligns, fix label offsets. */ -int dasm_link(Dst_DECL, size_t *szp) -{ - dasm_State *D = Dst_REF; - int secnum; - int ofs = 0; - -#ifdef DASM_CHECKS - *szp = 0; - if (D->status != DASM_S_OK) return D->status; - { - int pc; - for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) - if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; - } -#endif - - { /* Handle globals not defined in this translation unit. */ - int idx; - for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { - int n = D->lglabels[idx]; - /* Undefined label: Collapse rel chain and replace with marker (< 0). */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } - } - } - - /* Combine all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->rbuf; - int pos = DASM_SEC2POS(secnum); - int lastpos = sec->pos; - - while (pos != lastpos) { - dasm_ActList p = D->actionlist + b[pos++]; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: p++; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; - case DASM_REL_LG: case DASM_REL_PC: pos++; break; - case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; - case DASM_IMM: case DASM_IMMSH: pos++; break; - } - } - stop: (void)0; - } - ofs += sec->ofs; /* Next section starts right after current section. */ - } - - D->codesize = ofs; /* Total size of all code sections */ - *szp = ofs; - return DASM_S_OK; -} - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) -#else -#define CK(x, st) ((void)0) -#endif - -/* Pass 3: Encode sections. */ -int dasm_encode(Dst_DECL, void *buffer) -{ - dasm_State *D = Dst_REF; - char *base = (char *)buffer; - unsigned int *cp = (unsigned int *)buffer; - int secnum; - - /* Encode all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->buf; - int *endb = sec->rbuf + sec->pos; - - while (b != endb) { - dasm_ActList p = D->actionlist + *b++; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: *cp++ = *p++; break; - case DASM_REL_EXT: - n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1) - 4; - goto patchrel; - case DASM_ALIGN: - ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000; - break; - case DASM_REL_LG: - CK(n >= 0, UNDEF_LG); - case DASM_REL_PC: - CK(n >= 0, UNDEF_PC); - n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base); - patchrel: - CK((n & 3) == 0 && - (((n+4) + ((ins & 2048) ? 0x00008000 : 0x02000000)) >> - ((ins & 2048) ? 16 : 26)) == 0, RANGE_REL); - cp[-1] |= ((n+4) & ((ins & 2048) ? 0x0000fffc: 0x03fffffc)); - break; - case DASM_LABEL_LG: - ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); - break; - case DASM_LABEL_PC: break; - case DASM_IMM: - cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); - break; - case DASM_IMMSH: - cp[-1] |= (ins & 1) ? ((n&31)<<11)|((n&32)>>4) : ((n&31)<<6)|(n&32); - break; - default: *cp++ = ins; break; - } - } - stop: (void)0; - } - } - - if (base + D->codesize != (char *)cp) /* Check for phase errors. */ - return DASM_S_PHASE; - return DASM_S_OK; -} -#undef CK - -/* Get PC label offset. */ -int dasm_getpclabel(Dst_DECL, unsigned int pc) -{ - dasm_State *D = Dst_REF; - if (pc*sizeof(int) < D->pcsize) { - int pos = D->pclabels[pc]; - if (pos < 0) return *DASM_POS2PTR(D, -pos); - if (pos > 0) return -1; /* Undefined. */ - } - return -2; /* Unused or out of range. */ -} - -#ifdef DASM_CHECKS -/* Optional sanity checker to call between isolated encoding steps. */ -int dasm_checkstep(Dst_DECL, int secmatch) -{ - dasm_State *D = Dst_REF; - if (D->status == DASM_S_OK) { - int i; - for (i = 1; i <= 9; i++) { - if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } - D->lglabels[i] = 0; - } - } - if (D->status == DASM_S_OK && secmatch >= 0 && - D->section != &D->sections[secmatch]) - D->status = DASM_S_MATCH_SEC|(D->section-D->sections); - return D->status; -} -#endif - diff --git a/compiler/code-gen/assembly/include/dasm_proto.h b/compiler/code-gen/assembly/include/dasm_proto.h deleted file mode 100644 index 3557907..0000000 --- a/compiler/code-gen/assembly/include/dasm_proto.h +++ /dev/null @@ -1,83 +0,0 @@ -/* -** DynASM encoding engine prototypes. -** Copyright (C) 2005-2016 Mike Pall. All rights reserved. -** Released under the MIT license. See dynasm.lua for full copyright notice. -*/ - -#ifndef _DASM_PROTO_H -#define _DASM_PROTO_H - -#include -#include - -#define DASM_IDENT "DynASM 1.4.0" -#define DASM_VERSION 10400 /* 1.4.0 */ - -#ifndef Dst_DECL -#define Dst_DECL dasm_State **Dst -#endif - -#ifndef Dst_REF -#define Dst_REF (*Dst) -#endif - -#ifndef DASM_FDEF -#define DASM_FDEF inline -#endif - -#ifndef DASM_M_GROW -#define DASM_M_GROW(ctx, t, p, sz, need) \ - do { \ - size_t _sz = (sz), _need = (need); \ - if (_sz < _need) { \ - if (_sz < 16) _sz = 16; \ - while (_sz < _need) _sz += _sz; \ - (p) = (t *)realloc((p), _sz); \ - if ((p) == NULL) exit(1); \ - (sz) = _sz; \ - } \ - } while(0) -#endif - -#ifndef DASM_M_FREE -#define DASM_M_FREE(ctx, p, sz) free(p) -#endif - -/* Internal DynASM encoder state. */ -typedef struct dasm_State dasm_State; - - -/* Initialize and free DynASM state. */ -DASM_FDEF void dasm_init(Dst_DECL, int maxsection); -DASM_FDEF void dasm_free(Dst_DECL); - -/* Setup global array. Must be called before dasm_setup(). */ -DASM_FDEF void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl); - -/* Grow PC label array. Can be called after dasm_setup(), too. */ -DASM_FDEF void dasm_growpc(Dst_DECL, unsigned int maxpc); - -/* Setup encoder. */ -DASM_FDEF void dasm_setup(Dst_DECL, const void *actionlist); - -/* Feed encoder with actions. Calls are generated by pre-processor. */ -DASM_FDEF void dasm_put(Dst_DECL, int start, ...); - -/* Link sections and return the resulting size. */ -DASM_FDEF int dasm_link(Dst_DECL, size_t *szp); - -/* Encode sections into buffer. */ -DASM_FDEF int dasm_encode(Dst_DECL, void *buffer); - -/* Get PC label offset. */ -DASM_FDEF int dasm_getpclabel(Dst_DECL, unsigned int pc); - -#ifdef DASM_CHECKS -/* Optional sanity checker to call between isolated encoding steps. */ -DASM_FDEF int dasm_checkstep(Dst_DECL, int secmatch); -#else -#define dasm_checkstep(a, b) 0 -#endif - - -#endif /* _DASM_PROTO_H */ diff --git a/compiler/code-gen/assembly/include/dasm_x86.h b/compiler/code-gen/assembly/include/dasm_x86.h deleted file mode 100644 index 562f401..0000000 --- a/compiler/code-gen/assembly/include/dasm_x86.h +++ /dev/null @@ -1,498 +0,0 @@ -/* -** DynASM x86 encoding engine. -** Copyright (C) 2005-2016 Mike Pall. All rights reserved. -** Released under the MIT license. See dynasm.lua for full copyright notice. -*/ - - -#include -#include -#include -#include - -#define DASM_ARCH "x86" - -#ifndef DASM_EXTERN -#define DASM_EXTERN(a,b,c,d) 0 -#endif - -/* Action definitions. DASM_STOP must be 255. */ -enum { - DASM_DISP = 233, - DASM_IMM_S, DASM_IMM_B, DASM_IMM_W, DASM_IMM_D, DASM_IMM_WB, DASM_IMM_DB, - DASM_VREG, DASM_SPACE, DASM_SETLABEL, DASM_REL_A, DASM_REL_LG, DASM_REL_PC, - DASM_IMM_LG, DASM_IMM_PC, DASM_LABEL_LG, DASM_LABEL_PC, DASM_ALIGN, - DASM_EXTERN, DASM_ESC, DASM_MARK, DASM_SECTION, DASM_STOP -}; - -/* Maximum number of section buffer positions for a single dasm_put() call. */ -#define DASM_MAXSECPOS 25 - -/* DynASM encoder status codes. Action list offset or number are or'ed in. */ -#define DASM_S_OK 0x00000000 -#define DASM_S_NOMEM 0x01000000 -#define DASM_S_PHASE 0x02000000 -#define DASM_S_MATCH_SEC 0x03000000 -#define DASM_S_RANGE_I 0x11000000 -#define DASM_S_RANGE_SEC 0x12000000 -#define DASM_S_RANGE_LG 0x13000000 -#define DASM_S_RANGE_PC 0x14000000 -#define DASM_S_RANGE_VREG 0x15000000 -#define DASM_S_UNDEF_L 0x21000000 -#define DASM_S_UNDEF_PC 0x22000000 - -/* Macros to convert positions (8 bit section + 24 bit index). */ -#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) -#define DASM_POS2BIAS(pos) ((pos)&0xff000000) -#define DASM_SEC2POS(sec) ((sec)<<24) -#define DASM_POS2SEC(pos) ((pos)>>24) -#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) - -/* Action list type. */ -typedef const unsigned char *dasm_ActList; - -/* Per-section structure. */ -typedef struct dasm_Section { - int *rbuf; /* Biased buffer pointer (negative section bias). */ - int *buf; /* True buffer pointer. */ - size_t bsize; /* Buffer size in bytes. */ - int pos; /* Biased buffer position. */ - int epos; /* End of biased buffer position - max single put. */ - int ofs; /* Byte offset into section. */ -} dasm_Section; - -/* Core structure holding the DynASM encoding state. */ -struct dasm_State { - size_t psize; /* Allocated size of this structure. */ - dasm_ActList actionlist; /* Current actionlist pointer. */ - int *lglabels; /* Local/global chain/pos ptrs. */ - size_t lgsize; - int *pclabels; /* PC label chains/pos ptrs. */ - size_t pcsize; - void **globals; /* Array of globals (bias -10). */ - dasm_Section *section; /* Pointer to active section. */ - size_t codesize; /* Total size of all code sections. */ - int maxsection; /* 0 <= sectionidx < maxsection. */ - int status; /* Status code. */ - dasm_Section sections[1]; /* All sections. Alloc-extended. */ -}; - -/* The size of the core structure depends on the max. number of sections. */ -#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) - - -/* Initialize DynASM state. */ -void dasm_init(Dst_DECL, int maxsection) -{ - dasm_State *D; - size_t psz = 0; - int i; - Dst_REF = NULL; - DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); - D = Dst_REF; - D->psize = psz; - D->lglabels = NULL; - D->lgsize = 0; - D->pclabels = NULL; - D->pcsize = 0; - D->globals = NULL; - D->maxsection = maxsection; - for (i = 0; i < maxsection; i++) { - D->sections[i].buf = NULL; /* Need this for pass3. */ - D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); - D->sections[i].bsize = 0; - D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ - } -} - -/* Free DynASM state. */ -void dasm_free(Dst_DECL) -{ - dasm_State *D = Dst_REF; - int i; - for (i = 0; i < D->maxsection; i++) - if (D->sections[i].buf) - DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); - if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); - if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); - DASM_M_FREE(Dst, D, D->psize); -} - -/* Setup global label array. Must be called before dasm_setup(). */ -void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) -{ - dasm_State *D = Dst_REF; - D->globals = gl - 10; /* Negative bias to compensate for locals. */ - DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); -} - -/* Grow PC label array. Can be called after dasm_setup(), too. */ -void dasm_growpc(Dst_DECL, unsigned int maxpc) -{ - dasm_State *D = Dst_REF; - size_t osz = D->pcsize; - DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); - memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); -} - -/* Setup encoder. */ -void dasm_setup(Dst_DECL, const void *actionlist) -{ - dasm_State *D = Dst_REF; - int i; - D->actionlist = (dasm_ActList)actionlist; - D->status = DASM_S_OK; - D->section = &D->sections[0]; - memset((void *)D->lglabels, 0, D->lgsize); - if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); - for (i = 0; i < D->maxsection; i++) { - D->sections[i].pos = DASM_SEC2POS(i); - D->sections[i].ofs = 0; - } -} - - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) { \ - D->status = DASM_S_##st|(int)(p-D->actionlist-1); return; } } while (0) -#define CKPL(kind, st) \ - do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ - D->status=DASM_S_RANGE_##st|(int)(p-D->actionlist-1); return; } } while (0) -#else -#define CK(x, st) ((void)0) -#define CKPL(kind, st) ((void)0) -#endif - -/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ -void dasm_put(Dst_DECL, int start, ...) -{ - va_list ap; - dasm_State *D = Dst_REF; - dasm_ActList p = D->actionlist + start; - dasm_Section *sec = D->section; - int pos = sec->pos, ofs = sec->ofs, mrm = -1; - int *b; - - if (pos >= sec->epos) { - DASM_M_GROW(Dst, int, sec->buf, sec->bsize, - sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); - sec->rbuf = sec->buf - DASM_POS2BIAS(pos); - sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); - } - - b = sec->rbuf; - b[pos++] = start; - - va_start(ap, start); - while (1) { - int action = *p++; - if (action < DASM_DISP) { - ofs++; - } else if (action <= DASM_REL_A) { - int n = va_arg(ap, int); - b[pos++] = n; - switch (action) { - case DASM_DISP: - if (n == 0) { if (mrm < 0) mrm = p[-2]; if ((mrm&7) != 5) break; } - case DASM_IMM_DB: if (((n+128)&-256) == 0) goto ob; - case DASM_REL_A: /* Assumes ptrdiff_t is int. !x64 */ - case DASM_IMM_D: ofs += 4; break; - case DASM_IMM_S: CK(((n+128)&-256) == 0, RANGE_I); goto ob; - case DASM_IMM_B: CK((n&-256) == 0, RANGE_I); ob: ofs++; break; - case DASM_IMM_WB: if (((n+128)&-256) == 0) goto ob; - case DASM_IMM_W: CK((n&-65536) == 0, RANGE_I); ofs += 2; break; - case DASM_SPACE: p++; ofs += n; break; - case DASM_SETLABEL: b[pos-2] = -0x40000000; break; /* Neg. label ofs. */ - case DASM_VREG: CK((n&-16) == 0 && (n != 4 || (*p>>5) != 2), RANGE_VREG); - if (*p < 0x40 && p[1] == DASM_DISP) mrm = n; - if (*p < 0x20 && (n&7) == 4) ofs++; - switch ((*p++ >> 3) & 3) { - case 3: n |= b[pos-3]; - case 2: n |= b[pos-2]; - case 1: if (n <= 7) { b[pos-1] |= 0x10; ofs--; } - } - continue; - } - mrm = -1; - } else { - int *pl, n; - switch (action) { - case DASM_REL_LG: - case DASM_IMM_LG: - n = *p++; pl = D->lglabels + n; - /* Bkwd rel or global. */ - if (n <= 246) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } - pl -= 246; n = *pl; - if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ - goto linkrel; - case DASM_REL_PC: - case DASM_IMM_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC); - putrel: - n = *pl; - if (n < 0) { /* Label exists. Get label pos and store it. */ - b[pos] = -n; - } else { - linkrel: - b[pos] = n; /* Else link to rel chain, anchored at label. */ - *pl = pos; - } - pos++; - ofs += 4; /* Maximum offset needed. */ - if (action == DASM_REL_LG || action == DASM_REL_PC) - b[pos++] = ofs; /* Store pass1 offset estimate. */ - break; - case DASM_LABEL_LG: pl = D->lglabels + *p++; CKPL(lg, LG); goto putlabel; - case DASM_LABEL_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC); - putlabel: - n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; } - *pl = -pos; /* Label exists now. */ - b[pos++] = ofs; /* Store pass1 offset estimate. */ - break; - case DASM_ALIGN: - ofs += *p++; /* Maximum alignment needed (arg is 2**n-1). */ - b[pos++] = ofs; /* Store pass1 offset estimate. */ - break; - case DASM_EXTERN: p += 2; ofs += 4; break; - case DASM_ESC: p++; ofs++; break; - case DASM_MARK: mrm = p[-2]; break; - case DASM_SECTION: - n = *p; CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n]; - case DASM_STOP: goto stop; - } - } - } -stop: - va_end(ap); - sec->pos = pos; - sec->ofs = ofs; -} -#undef CK - -/* Pass 2: Link sections, shrink branches/aligns, fix label offsets. */ -int dasm_link(Dst_DECL, size_t *szp) -{ - dasm_State *D = Dst_REF; - int secnum; - int ofs = 0; - -#ifdef DASM_CHECKS - *szp = 0; - if (D->status != DASM_S_OK) return D->status; - { - int pc; - for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) - if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; - } -#endif - - { /* Handle globals not defined in this translation unit. */ - int idx; - for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) { - int n = D->lglabels[idx]; - /* Undefined label: Collapse rel chain and replace with marker (< 0). */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } - } - } - - /* Combine all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->rbuf; - int pos = DASM_SEC2POS(secnum); - int lastpos = sec->pos; - - while (pos != lastpos) { - dasm_ActList p = D->actionlist + b[pos++]; - while (1) { - int op, action = *p++; - switch (action) { - case DASM_REL_LG: p++; op = p[-3]; goto rel_pc; - case DASM_REL_PC: op = p[-2]; rel_pc: { - int shrink = op == 0xe9 ? 3 : ((op&0xf0) == 0x80 ? 4 : 0); - if (shrink) { /* Shrinkable branch opcode? */ - int lofs, lpos = b[pos]; - if (lpos < 0) goto noshrink; /* Ext global? */ - lofs = *DASM_POS2PTR(D, lpos); - if (lpos > pos) { /* Fwd label: add cumulative section offsets. */ - int i; - for (i = secnum; i < DASM_POS2SEC(lpos); i++) - lofs += D->sections[i].ofs; - } else { - lofs -= ofs; /* Bkwd label: unfix offset. */ - } - lofs -= b[pos+1]; /* Short branch ok? */ - if (lofs >= -128-shrink && lofs <= 127) ofs -= shrink; /* Yes. */ - else { noshrink: shrink = 0; } /* No, cannot shrink op. */ - } - b[pos+1] = shrink; - pos += 2; - break; - } - case DASM_SPACE: case DASM_IMM_LG: case DASM_VREG: p++; - case DASM_DISP: case DASM_IMM_S: case DASM_IMM_B: case DASM_IMM_W: - case DASM_IMM_D: case DASM_IMM_WB: case DASM_IMM_DB: - case DASM_SETLABEL: case DASM_REL_A: case DASM_IMM_PC: pos++; break; - case DASM_LABEL_LG: p++; - case DASM_LABEL_PC: b[pos++] += ofs; break; /* Fix label offset. */ - case DASM_ALIGN: ofs -= (b[pos++]+ofs)&*p++; break; /* Adjust ofs. */ - case DASM_EXTERN: p += 2; break; - case DASM_ESC: p++; break; - case DASM_MARK: break; - case DASM_SECTION: case DASM_STOP: goto stop; - } - } - stop: (void)0; - } - ofs += sec->ofs; /* Next section starts right after current section. */ - } - - D->codesize = ofs; /* Total size of all code sections */ - *szp = ofs; - return DASM_S_OK; -} - -#define dasmb(x) *cp++ = (unsigned char)(x) -#ifndef DASM_ALIGNED_WRITES -#define dasmw(x) \ - do { *((unsigned short *)cp) = (unsigned short)(x); cp+=2; } while (0) -#define dasmd(x) \ - do { *((unsigned int *)cp) = (unsigned int)(x); cp+=4; } while (0) -#else -#define dasmw(x) do { dasmb(x); dasmb((x)>>8); } while (0) -#define dasmd(x) do { dasmw(x); dasmw((x)>>16); } while (0) -#endif - -/* Pass 3: Encode sections. */ -int dasm_encode(Dst_DECL, void *buffer) -{ - dasm_State *D = Dst_REF; - unsigned char *base = (unsigned char *)buffer; - unsigned char *cp = base; - int secnum; - - /* Encode all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->buf; - int *endb = sec->rbuf + sec->pos; - - while (b != endb) { - dasm_ActList p = D->actionlist + *b++; - unsigned char *mark = NULL; - while (1) { - int action = *p++; - int n = (action >= DASM_DISP && action <= DASM_ALIGN) ? *b++ : 0; - switch (action) { - case DASM_DISP: if (!mark) mark = cp; { - unsigned char *mm = mark; - if (*p != DASM_IMM_DB && *p != DASM_IMM_WB) mark = NULL; - if (n == 0) { int mrm = mm[-1]&7; if (mrm == 4) mrm = mm[0]&7; - if (mrm != 5) { mm[-1] -= 0x80; break; } } - if (((n+128) & -256) != 0) goto wd; else mm[-1] -= 0x40; - } - case DASM_IMM_S: case DASM_IMM_B: wb: dasmb(n); break; - case DASM_IMM_DB: if (((n+128)&-256) == 0) { - db: if (!mark) mark = cp; mark[-2] += 2; mark = NULL; goto wb; - } else mark = NULL; - case DASM_IMM_D: wd: dasmd(n); break; - case DASM_IMM_WB: if (((n+128)&-256) == 0) goto db; else mark = NULL; - case DASM_IMM_W: dasmw(n); break; - case DASM_VREG: { - int t = *p++; - unsigned char *ex = cp - (t&7); - if ((n & 8) && t < 0xa0) { - if (*ex & 0x80) ex[1] ^= 0x20 << (t>>6); else *ex ^= 1 << (t>>6); - n &= 7; - } else if (n & 0x10) { - if (*ex & 0x80) { - *ex = 0xc5; ex[1] = (ex[1] & 0x80) | ex[2]; ex += 2; - } - while (++ex < cp) ex[-1] = *ex; - if (mark) mark--; - cp--; - n &= 7; - } - if (t >= 0xc0) n <<= 4; - else if (t >= 0x40) n <<= 3; - else if (n == 4 && t < 0x20) { cp[-1] ^= n; *cp++ = 0x20; } - cp[-1] ^= n; - break; - } - case DASM_REL_LG: p++; if (n >= 0) goto rel_pc; - b++; n = (int)(ptrdiff_t)D->globals[-n]; - case DASM_REL_A: rel_a: n -= (int)(ptrdiff_t)(cp+4); goto wd; /* !x64 */ - case DASM_REL_PC: rel_pc: { - int shrink = *b++; - int *pb = DASM_POS2PTR(D, n); if (*pb < 0) { n = pb[1]; goto rel_a; } - n = *pb - ((int)(cp-base) + 4-shrink); - if (shrink == 0) goto wd; - if (shrink == 4) { cp--; cp[-1] = *cp-0x10; } else cp[-1] = 0xeb; - goto wb; - } - case DASM_IMM_LG: - p++; if (n < 0) { n = (int)(ptrdiff_t)D->globals[-n]; goto wd; } - case DASM_IMM_PC: { - int *pb = DASM_POS2PTR(D, n); - n = *pb < 0 ? pb[1] : (*pb + (int)(ptrdiff_t)base); - goto wd; - } - case DASM_LABEL_LG: { - int idx = *p++; - if (idx >= 10) - D->globals[idx] = (void *)(base + (*p == DASM_SETLABEL ? *b : n)); - break; - } - case DASM_LABEL_PC: case DASM_SETLABEL: break; - case DASM_SPACE: { int fill = *p++; while (n--) *cp++ = fill; break; } - case DASM_ALIGN: - n = *p++; - while (((cp-base) & n)) *cp++ = 0x90; /* nop */ - break; - case DASM_EXTERN: n = DASM_EXTERN(Dst, cp, p[1], *p); p += 2; goto wd; - case DASM_MARK: mark = cp; break; - case DASM_ESC: action = *p++; - default: *cp++ = action; break; - case DASM_SECTION: case DASM_STOP: goto stop; - } - } - stop: (void)0; - } - } - - if (base + D->codesize != cp) /* Check for phase errors. */ - return DASM_S_PHASE; - return DASM_S_OK; -} - -/* Get PC label offset. */ -int dasm_getpclabel(Dst_DECL, unsigned int pc) -{ - dasm_State *D = Dst_REF; - if (pc*sizeof(int) < D->pcsize) { - int pos = D->pclabels[pc]; - if (pos < 0) return *DASM_POS2PTR(D, -pos); - if (pos > 0) return -1; /* Undefined. */ - } - return -2; /* Unused or out of range. */ -} - -#ifdef DASM_CHECKS -/* Optional sanity checker to call between isolated encoding steps. */ -int dasm_checkstep(Dst_DECL, int secmatch) -{ - dasm_State *D = Dst_REF; - if (D->status == DASM_S_OK) { - int i; - for (i = 1; i <= 9; i++) { - if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_L|i; break; } - D->lglabels[i] = 0; - } - } - if (D->status == DASM_S_OK && secmatch >= 0 && - D->section != &D->sections[secmatch]) - D->status = DASM_S_MATCH_SEC|(int)(D->section-D->sections); - return D->status; -} -#endif \ No newline at end of file diff --git a/compiler/code-gen/code_generator.cc b/compiler/code-gen/code_generator.cc deleted file mode 100644 index ef20106..0000000 --- a/compiler/code-gen/code_generator.cc +++ /dev/null @@ -1,350 +0,0 @@ -/** - * Copyright 2017 Manuel Fasching - * Distributed under the MIT License - * - * 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 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 -#include -#include -#include -#include -#include - - - - -/** - * @see ptr_map_container.hh - */ -std::map FunctionPtrMap::map; - -/** - * @see code_generator.hh - */ -CodeGenerator::CodeGenerator() { - dynamicLabelCount = 0; -} - -/** - * @see code_generator.hh - */ -CodeGenerator::~CodeGenerator() -{ -} - -/** - * @see code_generator.hh - */ -dasm_gen_func CodeGenerator::generateCode(FunctionContext* &functionContext) -{ - FunctionPtrMap::initialize_map(); - assembly.initialize(functionContext->parameters.size()); - assembly.prologue(); - - assembly.reserveMemoryForLocalVariables(functionContext->variables.size()); - - evaluateAst(functionContext, functionContext->root); - - return assembly.linkAndEncode(); -} - -/** - * @see code_generator.hh - */ -void CodeGenerator::evaluateAst(FunctionContext* &functionContext, Node* &node){ - switch(node->nodeType) - { - case ROOT:{ - dsfUtil(functionContext, node); - break; - } - case CONSTANT: - { - assembly.pushConstantToStack((static_cast(node)->value)); - break; - } - - case VARIABLE: - { - dsfUtil(functionContext, node); - if(functionContext->containsVariable(static_cast(node)->name)) { - assembly.pushLocalVariableToStack(functionContext->getIndexOfVariable(static_cast(node)->name)); - break; - } - else if(functionContext->containsParameter(static_cast(node)->name)) { - assembly.pushParameterToStack(functionContext->getIndexOfParameter(static_cast(node)->name)); - break; - } - else{ - throw std::runtime_error("Variable not found!"); - } - } - - case NEGATION: - { - dsfUtil(functionContext, node); - assembly.callExternalFunction(reinterpret_cast(CalculationHelper::changeSign), 1); - break; - } - - case ADDITION: - { - dsfUtil(functionContext, node); - assembly.calculateAddition(); - break; - } - - case SUBTRACTION: - { - dsfUtil(functionContext, node); - assembly.calculateSubtraction(); - break; - } - - case MULTIPLICATION: - { - dsfUtil(functionContext, node); - assembly.calculateMultiplication(); - break; - } - - case DIVISION: - { - dsfUtil(functionContext, node); - assembly.calculateDivision(); - break; - } - - case EXTERNAL_FUNCTION: - { - dsfUtil(functionContext, node); - assembly.callExternalFunction(FunctionPtrMap::map.find((static_cast(node)->name))->second, node->nodes.size()); - break; - } - - case ASSIGNMENT: - { - dsfUtil(functionContext, node); - if(functionContext->containsVariable(static_cast(node)->name)) { - assembly.storeLocalVariable(functionContext->getIndexOfVariable(static_cast(node)->name)); - break; - } - else if(functionContext->containsParameter(static_cast(node)->name)) { - assembly.replaceParameter(functionContext->getIndexOfParameter(static_cast(node)->name)); - break; - } - else{ - throw std::runtime_error("Variable was not found in semantic analysis phase!"); - } - } - - case IF_STATEMENT: - { - unsigned labelDemand = (2 + countLabels(node->nodes.at(0))); // Two labels for me, and x for my children - unsigned label1 = dynamicLabelCount; // The first new label number is the current overall count. - dynamicLabelCount += labelDemand; - unsigned label2 = dynamicLabelCount-1; // The bad label has the highest number. - // The first child will get label1+1 as good label and label2-1 as bad label - - assembly.growPC(dynamicLabelCount); // Now dynamically increase the number of available labels - - conditionEvaluationHelper(functionContext, node->nodes.at(0), label1, label2); // Evaluate the condition - assembly.addDynamicLabel(label1); // Place the good label - assembly.pushStackPos(); // Create a new branch - dsfUtil(functionContext, node->nodes.at(1)); // Place the if body - assembly.popStackPos(); // Restore the original stack position - assembly.addDynamicLabel(label2); // Place the bad label - break; - } - case IF_ELSE_STATEMENT: - { - unsigned labelDemand = (3 + countLabels(node->nodes.at(0))); // Three labels for me (since I also carry an else part), and x for my children - unsigned label1 = dynamicLabelCount; // The first new label number is the current overall count. - dynamicLabelCount += labelDemand; - unsigned label2 = dynamicLabelCount-2; // The bad label has the second highest number. - unsigned label3 = dynamicLabelCount-1; // The exit label has the highest number. - assembly.growPC(dynamicLabelCount); // Now dynamically increase the number of available labels - - conditionEvaluationHelper(functionContext, node->nodes.at(0), label1, label2); // Evaluate the condition - - assembly.addDynamicLabel(label1); // Place the good label - assembly.pushStackPos(); - dsfUtil(functionContext, node->nodes.at(1)); // Place the if body - assembly.popStackPos(); - assembly.jumpForwardToDynamicLabel(label3); // Jump forward to the exit label, if "if" was executed - assembly.addDynamicLabel(label2); // Place the bad label - // assembly.pushStackPos(); - dsfUtil(functionContext, node->nodes.at(2)); // Place the else body - // assembly.popStackPos(); - assembly.addDynamicLabel(label3); // Add the exit label - break; - } - case IF_BODY: - { - dsfUtil(functionContext, node); - break; - } - case ELSE_BODY: - { - dsfUtil(functionContext, node); - break; - } - - case RETURN: - { - dsfUtil(functionContext, node); - assembly.extractResult(); - assembly.epilogue(); - break; - } - } -} - -/** - * @see code_generator.hh - */ -void CodeGenerator::dsfUtil(FunctionContext* &functionContext, Node* &node) { - for(std::vector::iterator it = node->nodes.begin(); it != node->nodes.end(); ++it) { - evaluateAst(functionContext, (*it)); - } -} - -/** - * @see code_generator.hh - */ -unsigned CodeGenerator::countLabels(Node* node){ - unsigned labels = 0; - for(std::vector::iterator it = node->nodes.begin(); it != node->nodes.end(); ++it) { - - // A new label is only needed when I am an OR Junction and my child is an AND Junction or vice versa. - if (node->nodeType == BOOLEAN_OR_JUNCTION) { - if ((*it)->nodeType == BOOLEAN_AND_JUNCTION) { - labels++; - } - } - else if (node->nodeType == BOOLEAN_AND_JUNCTION) { - if ((*it)->nodeType == BOOLEAN_OR_JUNCTION) { - labels++; - } - } - - // And I have to check this for my childs, too. Of course. - labels += countLabels((*it)); - } - return labels; -} - -/** - * @see code_generator.hh - */ -void CodeGenerator::conditionEvaluationHelper(FunctionContext* &functionContext, Node* &node, unsigned label1, unsigned label2){ - // Ok, let's start. I am a condition or a boolean junction. Check all my childs. These could either be also boolean junctions, or I only carry - // a simple comparison. e.g. (x==y) && (a==b) or (x==y) - for(std::vector::iterator it = node->nodes.begin(); it != node->nodes.end(); ++it) { - switch(node->nodeType) - { - case COMPARISON: - { - // I am a compare node. Ok, evaluate my expressions and place a conditionally jump statement - // Max recursion depth reached - dsfUtil(functionContext, node); - assembly.conditionalJumpForwardToDynamicLabel(label2, false, static_cast(node)->compareOperator); - break; - } - // I am a boolean or junction. This is true for the whole loop. - case BOOLEAN_OR_JUNCTION: - { - //Ok, now I have to check the type of the currently traversed child. - switch((*it)->nodeType){ - - // My Child is a comparison - case COMPARISON: - { - // Evaluate it's expressions and place a conditionally jump statement. - // Max recursion depth reached - dsfUtil(functionContext, *it); - assembly.conditionalJumpForwardToDynamicLabel(label1, true, static_cast(*it)->compareOperator); - break; - } - - // My Child is an OR Junction - case BOOLEAN_OR_JUNCTION: - { - // Ok, OR junctions must evaluate all conditions. No need to jump here. - conditionEvaluationHelper(functionContext, (*it), label1, label2); - break; - } - - // My child is an AND Junction - case BOOLEAN_AND_JUNCTION: - { - // Well, Adapt label numbers and call the evaluation helper again. - conditionEvaluationHelper(functionContext, (*it), label1, label2-1); - - // This is executed, when any AND condition was true. Jump to the good label :) - assembly.jumpForwardToDynamicLabel(label1); - - // And also place a bad label, where my children can jump to. - assembly.addDynamicLabel(label2-1); - break; - } - } - break; - } - - // I am a boolean and junction. This is true for the whole loop. - // Read the comment in line 295 again. Now you got it, right? - case BOOLEAN_AND_JUNCTION: - { - //Again, now I have to check the type of the currently traversed child. - switch((*it)->nodeType) { - // In case it is a comparison: Jump to the bad label, if the comparison is false...remember - I'm an - // AND junction. All conditions must be true. - case COMPARISON: { - dsfUtil(functionContext, *it); - assembly.conditionalJumpForwardToDynamicLabel(label2, false, static_cast(*it)->compareOperator); - break; - } - - // Ok, my child is also a boolean AND Junction. No need to place a label. e.g. (A && (B && C)) = ( A && B && C) - case BOOLEAN_AND_JUNCTION: - { - conditionEvaluationHelper(functionContext, (*it), label1, label2); - break; - } - - // My child is a boolean OR Junction. Evaluate the child and place a good label. - case BOOLEAN_OR_JUNCTION: - { - conditionEvaluationHelper(functionContext, (*it), label1+1, label2); - assembly.addDynamicLabel(label1+1); - break; - } - } - } - } - - // If I am a comparison we can break the loop. All children were evaluated, and nothing more to do. - if(node->nodeType == COMPARISON) - break; - } - // After all we must place a bad label, in case I'm an OR junction. My children need a label to jump to, when nothing was true. - if(node->nodeType == BOOLEAN_OR_JUNCTION) - assembly.jumpForwardToDynamicLabel(label2); -} \ No newline at end of file diff --git a/compiler/code-gen/code_generator.cpp b/compiler/code-gen/code_generator.cpp new file mode 100644 index 0000000..5c30154 --- /dev/null +++ b/compiler/code-gen/code_generator.cpp @@ -0,0 +1,103 @@ +/** + * Copyright 2017 Manuel Fasching + * Distributed under the MIT License + * + * 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 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 "code_generator.h" +#include "codegen_visitor.h" +#include "engine.h" +#include "pretty_printer.h" +#include "llvm/IR/Verifier.h" +#include + +void CodeGenerator::generateLLVMCode(FunctionContext *&functionContext, llvm::Module &module, + const impalajit::Options &options) { + if (options.printAST) { + impala::PrettyPrinter printer; + functionContext->root->accept(&printer); + std::cout << std::string(80, '=') << std::endl; + } + + auto &jit = impala::engine::Jit::getJit(); + { + auto lock = jit.getLock(); + impala::engine::Jit::Toolbox tools = jit.createToolbox(); + llvm::Type *realType = + (options.isDoublePrecision) ? llvm::Type::getDoubleTy(tools.context) : llvm::Type::getFloatTy(tools.context); + + auto function = CodeGenerator::genFunctionProto(functionContext, module, tools, realType, options); + impala::CodegenVisitor codegenVisitor(tools, realType); + functionContext->root->accept(&codegenVisitor); + checkLastBasicBlock(function); + + llvm::verifyFunction(*function, &llvm::outs()); + if (options.printIR) { + impala::engine::Jit::printIRFunction(function); + } + } +} + +llvm::Function *CodeGenerator::genFunctionProto(FunctionContext *&functionContext, llvm::Module &currModule, + impala::engine::Jit::Toolbox &tools, llvm::Type *realType, + const impalajit::Options &options) { + + const auto numParams = functionContext->parameters.size(); + std::vector paramTypes(numParams, realType); + auto functionProto = llvm::FunctionType::get(realType, paramTypes, false); + + // First, see if the function has already been added to the current module + // check: name, type of operands and a number of operands + if (auto previouslyDefined = currModule.getFunction(functionContext->name)) { + bool isSame = (previouslyDefined->getName() == llvm::StringRef(functionContext->name)); + // type comparison is done via pointer comparison in LLVM + isSame &= (previouslyDefined->getNumOperands() == functionContext->parameters.size()); + isSame &= (previouslyDefined->getFunctionType() == realType); + + if (isSame) { + std::stringstream errStream; + errStream << "function `" << functionContext->name << "` has been previously defined"; + throw std::runtime_error(errStream.str()); + } + } + + auto linkageType = (options.weakLinkage) ? llvm::Function::WeakAnyLinkage : llvm::Function::ExternalLinkage; + + auto function = llvm::Function::Create(functionProto, linkageType, functionContext->name, currModule); + + auto entryBlock = llvm::BasicBlock::Create(tools.context, "entry", function); + tools.builder->SetInsertPoint(entryBlock); + + const auto ¶ms = functionContext->parameters; + for (size_t i = 0; i < params.size(); ++i) { + auto arg = function->getArg(i); + arg->setName(params[i]); + + auto argPtr = tools.builder->CreateAlloca(realType); + tools.symbolTable.addSymbol(params[i], argPtr); + tools.builder->CreateStore(arg, argPtr); + } + + return function; +} + +void CodeGenerator::checkLastBasicBlock(llvm::Function *function) { + auto &lastBasicBlock = function->getBasicBlockList().back(); + if (lastBasicBlock.empty()) { + impala::engine::Jit::printIRFunction(function); + throw std::runtime_error("impala: the last basic block is empty. Probably a forgotten return statement"); + } +} \ No newline at end of file diff --git a/compiler/code-gen/codegen_visitor.cpp b/compiler/code-gen/codegen_visitor.cpp new file mode 100644 index 0000000..43c8b1c --- /dev/null +++ b/compiler/code-gen/codegen_visitor.cpp @@ -0,0 +1,282 @@ +#include "codegen_visitor.h" +#include "assignment_nodes.h" +#include "boolean_nodes.h" +#include "compare_nodes.h" +#include "conditional_nodes.h" +#include "expression_nodes.h" +#include "external_function_nodes.h" +#include "return_nodes.h" + +namespace impala { +void CodegenVisitor::visit(RootNode *node) { + for (auto statements : node->nodes) { + statements->accept(this); + } +}; + +void CodegenVisitor::visit(ReturnNode *node) { + assert(node->nodes.size() == 1 && "ReturnNode must have one child"); + node->nodes[0]->accept(this); + auto returnValue = top(); + stack.push(toolbox.builder->CreateRet(returnValue)); +} + +void CodegenVisitor::visit(ExternalFunctionNode *node) { + std::string calleeName = node->name; + std::stringstream errStream; + if (toolbox.externalMathFunctions.find(calleeName) == toolbox.externalMathFunctions.end()) { + errStream << "impala: function `" << calleeName << "` doesn't belong to the standard math library"; + throw std::runtime_error(errStream.str()); + } + + auto proto = toolbox.externalMathFunctions[calleeName]; + if (node->nodes.size() != proto->arg_size()) { + errStream << "impala: function `" << calleeName << "` takes " << proto->arg_size() << " parameters, " + << "given " << node->nodes.size(); + throw std::runtime_error(errStream.str()); + } + + std::vector args; + for (auto child : node->nodes) { + child->accept(this); + if (stack.top()) { + args.push_back(top()); + } else { + errStream << "impala: found a statement in a list of formal parameters. " + << "Please, check `" << calleeName << "` function call"; + throw std::runtime_error(errStream.str()); + } + } + stack.push(toolbox.builder->CreateCall(proto, args)); +} + +void CodegenVisitor::visit(ExternalFunctionParametersNode *node) { + // TODO: delete + throw std::runtime_error("impala: ExternalFunctionParametersNode has never been supported by the language"); +} + +void CodegenVisitor::visit(PowerNode *node) { + // TODO: delete + assert(node->nodes.size() == 2 && "PowerNode must be a binary op"); + throw std::runtime_error("impala: PowerNode has never been supported by the language"); +} + +void CodegenVisitor::visit(DivisionNode *node) { + assert(node->nodes.size() == 2 && "DivisionNode must be a binary op"); + node->nodes[0]->accept(this); + auto lhs = top(); + node->nodes[1]->accept(this); + auto rhs = top(); + stack.push(toolbox.builder->CreateFDiv(lhs, rhs)); +} + +void CodegenVisitor::visit(MultiplicationNode *node) { + assert(node->nodes.size() == 2 && "MultiplicationNode must be a binary op"); + node->nodes[0]->accept(this); + auto lhs = top(); + node->nodes[1]->accept(this); + auto rhs = top(); + stack.push(toolbox.builder->CreateFMul(lhs, rhs)); +} + +void CodegenVisitor::visit(SubtractionNode *node) { + assert(node->nodes.size() == 2 && "SubtractionNode must be a binary op"); + node->nodes[0]->accept(this); + auto lhs = top(); + node->nodes[1]->accept(this); + auto rhs = top(); + stack.push(toolbox.builder->CreateFSub(lhs, rhs)); +} + +void CodegenVisitor::visit(AdditionNode *node) { + assert(node->nodes.size() == 2 && "AdditionNode must be a binary op"); + node->nodes[0]->accept(this); + auto lhs = top(); + node->nodes[1]->accept(this); + auto rhs = top(); + stack.push(toolbox.builder->CreateFAdd(lhs, rhs)); +} + +void CodegenVisitor::visit(NegationNode *node) { + assert(node->nodes.size() == 1 && "NegationNode must be a binary op"); + node->nodes[0]->accept(this); + auto expr = top(); + stack.push(toolbox.builder->CreateFNeg(expr)); +} + +void CodegenVisitor::visit(VariableNode *node) { + assert(node->nodes.empty() && "VariableNode must have no children"); + auto address = toolbox.symbolTable[node->name]; + if (!address) { + throw std::runtime_error("symbol `" + node->name + "` have not been defined"); + } + stack.push(toolbox.builder->CreateLoad(address)); +} + +void CodegenVisitor::visit(ConstantNode *node) { + assert(node->nodes.empty() && "ConstantNode must have no children"); + stack.push(llvm::ConstantFP::get(realType, node->value)); +} + +void CodegenVisitor::visit(CompareNode *node) { + assert(node->nodes.size() == 2 && "CompareNode must be a binary op"); + // NOTE: it was originally mixed up + node->nodes[1]->accept(this); + auto lhs = top(); + node->nodes[0]->accept(this); + auto rhs = top(); + + llvm::Value *cmpResult{nullptr}; + switch (node->compareOperator) { + case CompareOperatorType::EQ: { + cmpResult = toolbox.builder->CreateFCmpOEQ(lhs, rhs); + break; + } + case CompareOperatorType::NE: { + cmpResult = toolbox.builder->CreateFCmpONE(lhs, rhs); + break; + } + case CompareOperatorType::GT: { + cmpResult = toolbox.builder->CreateFCmpOGT(lhs, rhs); + break; + } + case CompareOperatorType::LT: { + cmpResult = toolbox.builder->CreateFCmpOLT(lhs, rhs); + break; + } + case CompareOperatorType::GTE: { + cmpResult = toolbox.builder->CreateFCmpOGE(lhs, rhs); + break; + } + case CompareOperatorType::LTE: { + cmpResult = toolbox.builder->CreateFCmpOLE(lhs, rhs); + break; + } + default: { + std::string msg = "Unknown comparison operator: " + std::to_string(static_cast(node->compareOperator)); + throw std::runtime_error(msg); + } + } + stack.push(cmpResult); +} + +void CodegenVisitor::visit(BooleanAndNode *node) { + assert(node->nodes.size() == 2 && "BooleanAndNode must be a binary op"); + node->nodes[0]->accept(this); + auto lhs = top(); + node->nodes[1]->accept(this); + auto rhs = top(); + + stack.push(toolbox.builder->CreateAnd(lhs, rhs)); +} + +void CodegenVisitor::visit(BooleanOrNode *node) { + assert(node->nodes.size() == 2 && "BooleanOrNode must be a binary op"); + node->nodes[0]->accept(this); + auto lhs = top(); + node->nodes[1]->accept(this); + auto rhs = top(); + + stack.push(toolbox.builder->CreateOr(lhs, rhs)); +} + +void CodegenVisitor::visit(AssignmentNode *node) { + assert(node->nodes.size() == 1 && "AssignmentNode must have one child expr"); + node->nodes[0]->accept(this); + auto expr = top(); + + auto address = toolbox.symbolTable[node->name]; + if (!address) { + address = toolbox.builder->CreateAlloca(realType); + toolbox.symbolTable.addSymbol(node->name, address); + } + toolbox.builder->CreateStore(expr, address); +} + +void CodegenVisitor::visit(IfStmtNode *node) { + assert(node->nodes.size() == 2 && "IfStmtNode must have three children nodes"); + node->nodes[0]->accept(this); + auto predicate = top(); + + auto currFunction = toolbox.builder->GetInsertBlock()->getParent(); + auto thenBlock = llvm::BasicBlock::Create(toolbox.context); + auto mergeBlock = llvm::BasicBlock::Create(toolbox.context); + toolbox.builder->CreateCondBr(predicate, thenBlock, mergeBlock); + + currFunction->getBasicBlockList().push_back(thenBlock); + currFunction->getBasicBlockList().push_back(mergeBlock); + + toolbox.builder->SetInsertPoint(thenBlock); + node->nodes[1]->accept(this); + auto &lastInstr = toolbox.builder->GetInsertBlock()->back(); + if (!llvm::isa(lastInstr)) { + toolbox.builder->CreateBr(mergeBlock); + } + + toolbox.builder->SetInsertPoint(mergeBlock); +} + +void CodegenVisitor::visit(IfElseStmtNode *node) { + assert(node->nodes.size() == 3 && "IfStmtNode must have three children nodes"); + node->nodes[0]->accept(this); + auto predicate = top(); + + auto currFunction = toolbox.builder->GetInsertBlock()->getParent(); + auto thenBlock = llvm::BasicBlock::Create(toolbox.context); + auto elseBlock = llvm::BasicBlock::Create(toolbox.context); + auto mergeBlock = llvm::BasicBlock::Create(toolbox.context); + + currFunction->getBasicBlockList().push_back(thenBlock); + currFunction->getBasicBlockList().push_back(elseBlock); + + toolbox.builder->CreateCondBr(predicate, thenBlock, elseBlock); + + toolbox.builder->SetInsertPoint(thenBlock); + node->nodes[1]->accept(this); + auto &lastThenBlockInstr = toolbox.builder->GetInsertBlock()->back(); + bool noReturnInThenBlock = !llvm::isa(lastThenBlockInstr); + if (noReturnInThenBlock) { + toolbox.builder->CreateBr(mergeBlock); + } + + toolbox.builder->SetInsertPoint(elseBlock); + node->nodes[2]->accept(this); + auto &lastElseBlockInstr = toolbox.builder->GetInsertBlock()->back(); + bool noReturnInElseBlock = !llvm::isa(lastElseBlockInstr); + if (noReturnInElseBlock) { + toolbox.builder->CreateBr(mergeBlock); + } + + if (noReturnInThenBlock || noReturnInElseBlock) { + currFunction->getBasicBlockList().push_back(mergeBlock); + toolbox.builder->SetInsertPoint(mergeBlock); + } +} + +void CodegenVisitor::visit(IfBodyNode *node) { + toolbox.symbolTable.addScope(); + for (auto child : node->nodes) { + child->accept(this); + auto &lastInstruction = toolbox.builder->GetInsertBlock()->back(); + if (llvm::isa(lastInstruction)) { + // a return instruction found. Doesn't make sense to generate the rest of the instructions + break; + } + } + toolbox.symbolTable.removeScope(); +} + +void CodegenVisitor::visit(ElseBodyNode *node) { + toolbox.symbolTable.addScope(); + for (auto child : node->nodes) { + child->accept(this); + auto &lastInstruction = toolbox.builder->GetInsertBlock()->back(); + if (llvm::isa(lastInstruction)) { + // a return instruction found. Doesn't make sense to generate the rest of the instructions + break; + } + } + toolbox.symbolTable.removeScope(); +} + +} // namespace impala \ No newline at end of file diff --git a/compiler/code-gen/include/abstract_visitor.h b/compiler/code-gen/include/abstract_visitor.h new file mode 100644 index 0000000..cc38af8 --- /dev/null +++ b/compiler/code-gen/include/abstract_visitor.h @@ -0,0 +1,52 @@ +#ifndef IMPALA_CPP_ABSTRACTVISITOR_H +#define IMPALA_CPP_ABSTRACTVISITOR_H + +class RootNode; +class ReturnNode; +class ExternalFunctionNode; +class ExternalFunctionParametersNode; +class PowerNode; +class DivisionNode; +class MultiplicationNode; +class SubtractionNode; +class AdditionNode; +class NegationNode; +class VariableNode; +class ConstantNode; +class ElseBodyNode; +class IfBodyNode; +class IfElseStmtNode; +class IfStmtNode; +class CompareNode; +class BooleanAndNode; +class BooleanOrNode; +class AssignmentNode; + +namespace impala { +class AbstractVisitor { +public: + virtual ~AbstractVisitor() = default; + virtual void visit(RootNode *node) = 0; + virtual void visit(ReturnNode *node) = 0; + virtual void visit(ExternalFunctionNode *node) = 0; + virtual void visit(ExternalFunctionParametersNode *node) = 0; + virtual void visit(PowerNode *node) = 0; + virtual void visit(DivisionNode *node) = 0; + virtual void visit(MultiplicationNode *node) = 0; + virtual void visit(SubtractionNode *node) = 0; + virtual void visit(AdditionNode *node) = 0; + virtual void visit(NegationNode *node) = 0; + virtual void visit(VariableNode *node) = 0; + virtual void visit(ConstantNode *node) = 0; + virtual void visit(ElseBodyNode *node) = 0; + virtual void visit(IfBodyNode *node) = 0; + virtual void visit(IfElseStmtNode *node) = 0; + virtual void visit(IfStmtNode *node) = 0; + virtual void visit(CompareNode *node) = 0; + virtual void visit(BooleanAndNode *node) = 0; + virtual void visit(BooleanOrNode *node) = 0; + virtual void visit(AssignmentNode *node) = 0; +}; +} // namespace impala + +#endif // IMPALA_CPP_ABSTRACTVISITOR_H diff --git a/compiler/code-gen/include/calculation_helper.hh b/compiler/code-gen/include/code_generator.h similarity index 54% rename from compiler/code-gen/include/calculation_helper.hh rename to compiler/code-gen/include/code_generator.h index 9f4dbe3..6a4c6e8 100644 --- a/compiler/code-gen/include/calculation_helper.hh +++ b/compiler/code-gen/include/code_generator.h @@ -17,24 +17,31 @@ * THE SOFTWARE. */ -#ifndef IMPALAJIT_CALCULATION_HELPER_HH -#define IMPALAJIT_CALCULATION_HELPER_HH +#ifndef IMPALAJIT_CODE_GENERATOR_HH +#define IMPALAJIT_CODE_GENERATOR_HH + +#include "engine.h" +#include "engine_types.h" +#include +#include +#include +#include +#include +#include + +class CodeGenerator { +private: + static llvm::Function *genFunctionProto(FunctionContext *&functionContext, llvm::Module &currModule, + impala::engine::Jit::Toolbox &tools, llvm::Type *realType, + const impalajit::Options &options); + + static void checkLastBasicBlock(llvm::Function *function); -/** - * This class contains functions, which are available - * in impala files. If you add functions, add also the - * pointer in ptr_map_container.hh - */ -class CalculationHelper { public: - /** - * Trivial... - * - * @param value value - * @return -value - */ - static double changeSign(double value) { - return -value; - } + CodeGenerator() = default; + ~CodeGenerator() = default; + + static void generateLLVMCode(FunctionContext *&functionContext, llvm::Module &module, + const impalajit::Options &options); }; -#endif //IMPALAJIT_CALCULATION_HELPER_HH +#endif // IMPALAJIT_CODE_GENERATOR_HH diff --git a/compiler/code-gen/include/code_generator.hh b/compiler/code-gen/include/code_generator.hh deleted file mode 100644 index cf36018..0000000 --- a/compiler/code-gen/include/code_generator.hh +++ /dev/null @@ -1,113 +0,0 @@ -/** - * Copyright 2017 Manuel Fasching - * Distributed under the MIT License - * - * 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 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 IMPALAJIT_CODE_GENERATOR_HH -#define IMPALAJIT_CODE_GENERATOR_HH - -#include -#include -#include -#include -#include -#include -#include - -/** - * This class traverses the AST and calls appropriate functions in the - * impalajit assembly layer. - */ -class CodeGenerator { -private: - unsigned dynamicLabelCount; // Global count of assigned - - Assembly__SSE_4_1 assembly; - - /** - * This functions performs the depth-first search algorithm. - * Each Node of the AST carries a type. - * The big switch statement is ugly, I know. In terms of code style and - * it would be better to add an evaluate function to the ast nodes and call - * it recursively. - * - * However, the label numbers in conditionals depend on the state of caller nodes. - * This means, an evaluate() function of conditional nodes would have to take labels - * as arguments and would hence differ from other nodes, which makes - * a clean inherited node structure difficult. The label placement would be also more difficult. - * - * I also tried it with pointers...don't do it, it's a mess. - * - * TODO: Devlop a clean concept, which solves all problems. - * - * @param functionContext The function context, which carries the ast - * @param node The currently visited node. - */ - void evaluateAst(FunctionContext* &functionContext, Node* &node); - - /** - * Simple helper function which calls evaluateAst for all child nodes - * - * @param functionContext The function context, which carries the ast - * @param node The currently visited node. - */ - void dsfUtil(FunctionContext* &functionContext, Node* &node); - - /** - * Helper function for conditional nodes. Places lables and jumps, based - * on ast structure. This is also true for nested if else statements. - * It needs two labels: One where it jumps to, if the condition is true, - * and one if it's false. - * - * @param functionContext The function context, which carries the ast - * @param node The currently visited node. - * @param label1 The good label. (condition == True) - * @param label2 The bad label. (condition ==False) - */ - void conditionEvaluationHelper(FunctionContext* &functionContext, Node* &node, unsigned label1, unsigned label2); - - /** - * This function counts the amount of labels, which is required by an - * conditional node. This number is needed in advance, since the number - * of available labels are increased dynamically for performance reasons. - * - * @param node The conditional node - * @return the required amount of labels - */ - unsigned countLabels(Node* node); - -public: - /** - * Constructor. Initializes the dynamic label count; - */ - CodeGenerator(); - - /** - * Destructor - */ - ~CodeGenerator(); - - /** - * This function calls the assembly prologue and starts evaluation - * the ast. Afterwards it extracts the functions. - * - * @param functionContext The function context, which carries the ast - * @return the function pointer - */ - dasm_gen_func generateCode(FunctionContext* &functionContext); -}; -#endif //IMPALAJIT_CODE_GENERATOR_HH diff --git a/compiler/code-gen/include/codegen_visitor.h b/compiler/code-gen/include/codegen_visitor.h new file mode 100644 index 0000000..d5b1888 --- /dev/null +++ b/compiler/code-gen/include/codegen_visitor.h @@ -0,0 +1,46 @@ +#ifndef IMPALA_CPP_CODEGENVISITOR_H +#define IMPALA_CPP_CODEGENVISITOR_H + +#include "abstract_visitor.h" +#include "engine.h" +#include + +namespace impala { +class CodegenVisitor : public AbstractVisitor { +public: + CodegenVisitor(engine::Jit::Toolbox &tools, llvm::Type *realType) : toolbox(tools), realType(realType) {} + void visit(RootNode *node) override; + void visit(ReturnNode *node) override; + void visit(ExternalFunctionNode *node) override; + void visit(ExternalFunctionParametersNode *node) override; + void visit(PowerNode *node) override; + void visit(DivisionNode *node) override; + void visit(MultiplicationNode *node) override; + void visit(SubtractionNode *node) override; + void visit(AdditionNode *node) override; + void visit(NegationNode *node) override; + void visit(VariableNode *node) override; + void visit(ConstantNode *node) override; + void visit(CompareNode *node) override; + void visit(BooleanAndNode *node) override; + void visit(BooleanOrNode *node) override; + void visit(AssignmentNode *node) override; + void visit(IfStmtNode *node) override; + void visit(IfElseStmtNode *node) override; + void visit(IfBodyNode *node) override; + void visit(ElseBodyNode *node) override; + +private: + llvm::Value *top() { + auto topValue = stack.top(); + stack.pop(); + return topValue; + } + + std::stack stack{}; + engine::Jit::Toolbox &toolbox; + llvm::Type *realType{nullptr}; +}; +} // namespace impala + +#endif // IMPALA_CPP_CODEGENVISITOR_H diff --git a/compiler/code-gen/include/pretty_printer.h b/compiler/code-gen/include/pretty_printer.h new file mode 100644 index 0000000..f931c67 --- /dev/null +++ b/compiler/code-gen/include/pretty_printer.h @@ -0,0 +1,42 @@ +#ifndef IMPALA_CPP_PRETTY_PRINTER_H +#define IMPALA_CPP_PRETTY_PRINTER_H + +#include "abstract_visitor.h" +#include + +namespace impala { +class PrettyPrinter : public AbstractVisitor { +public: + void visit(RootNode *node) override; + void visit(ReturnNode *node) override; + void visit(ExternalFunctionNode *node) override; + void visit(ExternalFunctionParametersNode *node) override; + void visit(PowerNode *node) override; + void visit(DivisionNode *node) override; + void visit(MultiplicationNode *node) override; + void visit(SubtractionNode *node) override; + void visit(AdditionNode *node) override; + void visit(NegationNode *node) override; + void visit(VariableNode *node) override; + void visit(ConstantNode *node) override; + void visit(CompareNode *node) override; + void visit(BooleanAndNode *node) override; + void visit(BooleanOrNode *node) override; + void visit(AssignmentNode *node) override; + void visit(IfStmtNode *node) override; + void visit(IfElseStmtNode *node) override; + void visit(IfBodyNode *node) override; + void visit(ElseBodyNode *node) override; + +private: + static constexpr int IndentSize{2}; + static constexpr char IndentChar{'-'}; + void increment() { indent += IndentSize; } + void decrement() { indent -= IndentSize; } + std::string getIndentLine() { return std::string(indent, IndentChar) + "> "; } + + int indent{0}; +}; +} // namespace impala + +#endif // IMPALA_CPP_PRETTY_PRINTER_H diff --git a/compiler/code-gen/include/ptr_map_container.hh b/compiler/code-gen/include/ptr_map_container.hh deleted file mode 100644 index 18a4d37..0000000 --- a/compiler/code-gen/include/ptr_map_container.hh +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright 2017 Manuel Fasching - * Distributed under the MIT License - * - * 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 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 IMPALAJIT_EXTERNAL_FUNCTION_DEFINITION_HH -#define IMPALAJIT_EXTERNAL_FUNCTION_DEFINITION_HH - -#include -#include -#include - -/** - * Container class for a static map of function pointers. The map acts - * as a lookup table for function names, which are available in impala files. - * A table base approach is necessary, since C++ does not support reflection. - */ -class FunctionPtrMap{ -public: - static std::map map; - - /** - * Initializes the map with function pointers and their names. - * Add additional function HERE - */ - static void initialize_map() { - map["cos"] = reinterpret_cast(static_cast(cos)); - map["sin"] = reinterpret_cast(static_cast(sin)); - map["tan"] = reinterpret_cast(static_cast(tan)); - map["acos"] = reinterpret_cast(static_cast(acos)); - map["asin"] = reinterpret_cast(static_cast(asin)); - map["atan"] = reinterpret_cast(static_cast(atan)); - map["atan2"] = reinterpret_cast(static_cast(atan2)); - map["cosh"] = reinterpret_cast(static_cast(cosh)); - map["sinh"] = reinterpret_cast(static_cast(sinh)); - map["tanh"] = reinterpret_cast(static_cast(tanh)); - map["exp"] = reinterpret_cast(static_cast(exp)); - map["log"] = reinterpret_cast(static_cast(log)); - map["log10"] = reinterpret_cast(static_cast(log10)); - map["pow"] = reinterpret_cast(static_cast(pow)); - map["sqrt"] = reinterpret_cast(static_cast(sqrt)); - map["min"] = reinterpret_cast(static_cast(fmin)); - map["max"] = reinterpret_cast(static_cast(fmax)); - map["abs"] = reinterpret_cast(static_cast(fabs)); - map["floor"] = reinterpret_cast(static_cast(floor)); - map["ceil"] = reinterpret_cast(static_cast(ceil)); - map["round"] = reinterpret_cast(static_cast(round)); - map["erf"] = reinterpret_cast(static_cast(erf)); - map["erfc"] = reinterpret_cast(static_cast(erfc)); - } -private: - /** - * Avoid contruction - * @return FunctionPointer - */ - FunctionPtrMap() { - } -}; - -#endif //IMPALAJIT_EXTERNAL_FUNCTION_DEFINITION_HH diff --git a/compiler/code-gen/pretty_printer.cpp b/compiler/code-gen/pretty_printer.cpp new file mode 100644 index 0000000..80604be --- /dev/null +++ b/compiler/code-gen/pretty_printer.cpp @@ -0,0 +1,195 @@ +#include "pretty_printer.h" +#include "assignment_nodes.h" +#include "boolean_nodes.h" +#include "compare_nodes.h" +#include "conditional_nodes.h" +#include "expression_nodes.h" +#include "external_function_nodes.h" +#include "return_nodes.h" + +namespace impala { +void PrettyPrinter::visit(RootNode *node) { + std::cout << getIndentLine() << "root" << std::endl; + + increment(); + for (auto statements : node->nodes) { + statements->accept(this); + } + decrement(); +}; + +void PrettyPrinter::visit(ReturnNode *node) { + assert(node->nodes.size() == 1 && "ReturnNode must have one child"); + std::cout << getIndentLine() << "return" << std::endl; + + increment(); + node->nodes[0]->accept(this); + decrement(); +} + +void PrettyPrinter::visit(ExternalFunctionNode *node) { + std::cout << getIndentLine() << "extern call: " << node->name << std::endl; + + increment(); + for (auto child : node->nodes) { + child->accept(this); + } + decrement(); +} + +void PrettyPrinter::visit(ExternalFunctionParametersNode *node) { + std::cout << getIndentLine() << "call" << std::endl; + + increment(); + for (auto child : node->nodes) { + child->accept(this); + } + decrement(); +} + +void PrettyPrinter::visit(PowerNode *node) { + assert(node->nodes.size() == 2 && "PowerNode must be a binary op"); + std::cout << getIndentLine() << "pow" << std::endl; + + increment(); + node->nodes[0]->accept(this); + node->nodes[1]->accept(this); + decrement(); +} + +void PrettyPrinter::visit(DivisionNode *node) { + assert(node->nodes.size() == 2 && "DivisionNode must be a binary op"); + std::cout << getIndentLine() << "/" << std::endl; + + increment(); + node->nodes[0]->accept(this); + node->nodes[1]->accept(this); + decrement(); +} + +void PrettyPrinter::visit(MultiplicationNode *node) { + assert(node->nodes.size() == 2 && "MultiplicationNode must be a binary op"); + std::cout << getIndentLine() << "*" << std::endl; + + increment(); + node->nodes[0]->accept(this); + node->nodes[1]->accept(this); + decrement(); +} + +void PrettyPrinter::visit(SubtractionNode *node) { + assert(node->nodes.size() == 2 && "SubtractionNode must be a binary op"); + std::cout << getIndentLine() << "-" << std::endl; + + increment(); + node->nodes[0]->accept(this); + node->nodes[1]->accept(this); + decrement(); +} + +void PrettyPrinter::visit(AdditionNode *node) { + assert(node->nodes.size() == 2 && "AdditionNode must be a binary op"); + std::cout << getIndentLine() << "+" << std::endl; + + increment(); + node->nodes[0]->accept(this); + node->nodes[1]->accept(this); + decrement(); +} + +void PrettyPrinter::visit(NegationNode *node) { + assert(node->nodes.size() == 1 && "NegationNode must be a binary op"); + std::cout << getIndentLine() << "NOR" << std::endl; + + increment(); + node->nodes[0]->accept(this); + decrement(); +} + +void PrettyPrinter::visit(VariableNode *node) { + assert(node->nodes.empty() && "VariableNode must have no children"); + std::cout << getIndentLine() << node->name << std::endl; +} + +void PrettyPrinter::visit(ConstantNode *node) { + assert(node->nodes.empty() && "ConstantNode must have no children"); + std::cout << getIndentLine() << node->value << std::endl; +} + +void PrettyPrinter::visit(CompareNode *node) { + assert(node->nodes.size() == 2 && "CompareNode must be a binary op"); + std::cout << getIndentLine() << "COMP" << std::endl; + + increment(); + node->nodes[0]->accept(this); + node->nodes[1]->accept(this); + decrement(); +} + +void PrettyPrinter::visit(BooleanAndNode *node) { + assert(node->nodes.size() == 2 && "BooleanAndNode must be a binary op"); + std::cout << getIndentLine() << "AND" << std::endl; + + increment(); + node->nodes[0]->accept(this); + node->nodes[1]->accept(this); + decrement(); +} + +void PrettyPrinter::visit(BooleanOrNode *node) { + assert(node->nodes.size() == 2 && "BooleanOrNode must be a binary op"); + std::cout << getIndentLine() << "OR" << std::endl; + + increment(); + node->nodes[0]->accept(this); + node->nodes[1]->accept(this); + decrement(); +} + +void PrettyPrinter::visit(AssignmentNode *node) { + assert(node->nodes.size() == 1 && "AssignmentNode must have one child expr"); + + std::cout << getIndentLine() << node->name << " :=" << std::endl; + increment(); + node->nodes[0]->accept(this); + decrement(); +} + +void PrettyPrinter::visit(IfStmtNode *node) { + assert(node->nodes.size() == 2 && "IfStmtNode must have three children nodes"); + std::cout << getIndentLine() << "if" << std::endl; + increment(); + node->nodes[0]->accept(this); + node->nodes[1]->accept(this); + decrement(); +} + +void PrettyPrinter::visit(IfElseStmtNode *node) { + assert(node->nodes.size() == 3 && "IfStmtNode must have three children nodes"); + std::cout << getIndentLine() << "if" << std::endl; + + increment(); + node->nodes[0]->accept(this); + node->nodes[1]->accept(this); + node->nodes[2]->accept(this); + decrement(); +} + +void PrettyPrinter::visit(IfBodyNode *node) { + std::cout << getIndentLine() << "then" << std::endl; + increment(); + for (auto stmt : node->nodes) { + stmt->accept(this); + } + decrement(); +} + +void PrettyPrinter::visit(ElseBodyNode *node) { + std::cout << getIndentLine() << "else" << std::endl; + increment(); + for (auto stmt : node->nodes) { + stmt->accept(this); + } + decrement(); +} +} // namespace impala \ No newline at end of file diff --git a/compiler/driver.cc b/compiler/driver.cc index 47c1e80..7b982a1 100644 --- a/compiler/driver.cc +++ b/compiler/driver.cc @@ -23,7 +23,7 @@ #include #include -#include +#include #include namespace impalajit { @@ -35,37 +35,36 @@ Driver::~Driver(){ delete functionContext; } -std::map Driver::parse_stream(std::istream& in) -{ - Scanner scanner(&in); - scanner.set_debug(false); - this->lexer = &scanner; - - Parser parser(*this); - parser.set_debug_level(false); - parser.parse(); +FunctionContext::FunctionSinatureT Driver::generateLLVMFunction(std::istream& in, + llvm::Module& module, + const impalajit::Options& options) { + Scanner scanner(&in); + scanner.set_debug(false); + this->lexer = &scanner; - SemanticAnalyzer semanticAnalyzer; - semanticAnalyzer.performSemanticAnalysis(functionContext); + Parser parser(*this); + parser.set_debug_level(false); + parser.parse(); - CodeGenerator codeGenerator; - dasm_gen_func function = codeGenerator.generateCode(functionContext); + SemanticAnalyzer semanticAnalyzer; + semanticAnalyzer.performSemanticAnalysis(functionContext); - std::map resultMap; - resultMap.insert(std::make_pair(functionContext->name, function)); - - return resultMap; + CodeGenerator codeGenerator; + codeGenerator.generateLLVMCode(functionContext, module, options); + return std::make_pair(functionContext->name, functionContext->parameters.size()); } -std::map Driver::parse_string(const std::string &input) -{ - std::istringstream iss(input); - return parse_stream(iss); +FunctionContext::FunctionSinatureT Driver::generateLLVMFunction(const std::string &input, + llvm::Module& module, + const impalajit::Options& options) { + std::istringstream iss(input); + auto signature = generateLLVMFunction(iss, module, options); + return signature; } void Driver::deleteFunctionContext(){ delete functionContext; - functionContext = NULL; + functionContext = nullptr; } void Driver::setFunctionContext(FunctionContext* _functionContext){ diff --git a/compiler/engine/engine.cpp b/compiler/engine/engine.cpp new file mode 100644 index 0000000..71b75c6 --- /dev/null +++ b/compiler/engine/engine.cpp @@ -0,0 +1,104 @@ +#include "engine.h" +#include "std_math_lib.h" +#include "llvm/IR/IRPrintingPasses.h" +#include "llvm/IR/PassManager.h" +#include + +namespace impala { +namespace engine { +Jit &Jit::getJit() { + static Jit jit; + return jit; +} + +Jit::Jit() { + LLVMInitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + llvm::InitializeNativeTargetAsmParser(); + + auto expectedJTMB = llvm::orc::JITTargetMachineBuilder::detectHost(); + if (!expectedJTMB) { + throw std::runtime_error("impala: cannot create jit machine builder"); + } + + auto expectedDataLayout = expectedJTMB->getDefaultDataLayoutForTarget(); + if (!expectedDataLayout) { + throw std::runtime_error("impala: cannot detect data layout"); + } + + try { + // create memory manager + auto memoryManager = []() { return std::make_unique(); }; + + // create compiler layer + objectLayer = std::make_unique(ES, memoryManager); + using compilerLayerT = llvm::orc::IRCompileLayer; + std::unique_ptr compiler(new llvm::orc::ConcurrentIRCompiler(std::move(*expectedJTMB))); + compileLayer = std::make_unique(ES, *objectLayer, std::move(compiler)); + + // create data layout + dataLayout = std::make_unique(std::move(*expectedDataLayout)); + + // create mangler + mangle = std::make_unique(ES, *dataLayout); + + // runtime dyn. layer + const std::string dylibName{"jit_dylib"}; + ES.createJITDylib(dylibName); + jitDylib = ES.getJITDylibByName(dylibName); + jitDylib->addGenerator( + llvm::cantFail(llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(dataLayout->getGlobalPrefix()))); + + // create llvm context + context = std::make_unique(std::make_unique()); + + } catch (const std::exception &err) { + llvm::errs() << err.what() << '\n'; + throw err; + } +} + +void Jit::addModule(std::unique_ptr &module, bool optimize) { + if (optimize) { + optimizer.run(*module); + } + llvm::cantFail(compileLayer->add(*jitDylib, llvm::orc::ThreadSafeModule(std::move(module), *context))); +} + +llvm::JITEvaluatedSymbol Jit::lookup(llvm::StringRef Name) { + // lookup will implicitly trigger compilation for any symbol that has not already been compiled + llvm::Expected expected = ES.lookup({jitDylib}, (*mangle)(Name.str())); + if (!expected) { + llvm::errs() << expected.takeError() << '\n'; + throw std::runtime_error("impala: lookup error"); + } + return *expected; +} + +std::unique_ptr Jit::createModule(bool isDoublePrecision) { + static long long counter{0}; + std::string moduleName{"impala_module_" + std::to_string(counter)}; + ++counter; + + auto module = std::make_unique(std::move(moduleName), *context->getContext()); + + // fill with libmath function definitions + externalMathFunctions = StdMathLib::fillModule(module, isDoublePrecision); + return module; +} + +Jit::Toolbox Jit::createToolbox() { return Jit::Toolbox(*(context->getContext()), externalMathFunctions); } + +void Jit::printIRFunction(llvm::Function *function) { + llvm::raw_fd_ostream stream(fileno(stdout), false); + llvm::FunctionPass *printPass = llvm::createPrintFunctionPass(llvm::outs()); + printPass->runOnFunction(*function); +} + +void Jit::printIRModule(llvm::Module &module) { + llvm::raw_fd_ostream stream(fileno(stdout), false); + llvm::ModulePass *printPass = llvm::createPrintModulePass(llvm::outs()); + printPass->runOnModule(module); +} +} // namespace engine +} // namespace impala \ No newline at end of file diff --git a/compiler/engine/engine.h b/compiler/engine/engine.h new file mode 100644 index 0000000..3be8192 --- /dev/null +++ b/compiler/engine/engine.h @@ -0,0 +1,99 @@ +#ifndef IMPALA_CPP_ENGINE_H +#define IMPALA_CPP_ENGINE_H + +#include "engine_types.h" +#include "optimizer.h" +#include "symbol_table.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ExecutionEngine/JITSymbol.h" +#include "llvm/ExecutionEngine/Orc/CompileUtils.h" +#include "llvm/ExecutionEngine/Orc/Core.h" +#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" +#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" +#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" +#include "llvm/ExecutionEngine/Orc/LLJIT.h" +#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/Support/TargetSelect.h" +#include +#include +#include + +/* + * ExecutionSession - provides context for our running JIT’d code (including the string pool, + * global mutex, and error reporting facilities) + * + * RTDyldObjectLinkingLayer - linker layer + * + * IRCompileLayer - compiler layer + * + * DataLayout - specifies how data is to be laid out in memory + * + * MangleAndInterner - for symbol mangling + * + * LLVMContext - llvm core + * + * + * return std::make_unique() - builds a JIT memory manager + * for each module that is added + * + * JITDylib - a symbol table that supports asynchoronous symbol queries + * */ +namespace impala { +namespace engine { +class Jit { +public: + struct Toolbox { + Toolbox(llvm::LLVMContext &context, engine::types::FunctionProtosT &externalMathFunctions) + : context(context), externalMathFunctions(externalMathFunctions) { + builder = std::make_unique>(context); + } + llvm::LLVMContext &context; + engine::types::FunctionProtosT &externalMathFunctions; + std::unique_ptr> builder{nullptr}; + SymbolTable symbolTable{}; + }; + + static Jit &getJit(); + + const llvm::DataLayout &getDataLayout() const { return *dataLayout; } + + llvm::LLVMContext &getContext() { return *context->getContext(); } + + llvm::orc::ThreadSafeContext::Lock getLock() { return context->getLock(); } + + // adds IR to the JIT and making it available for execution + void addModule(std::unique_ptr &module, bool optimize); + + // looks up addresses for function and variable definitions added to the JIT based on their symbol names. + llvm::JITEvaluatedSymbol lookup(llvm::StringRef Name); + + std::unique_ptr createModule(bool isDoublePrecision); + + types::FunctionProtosT &getExternalMathFunctions() { return externalMathFunctions; } + + Jit::Toolbox createToolbox(); + + static void printIRFunction(llvm::Function *function); + + static void printIRModule(llvm::Module &module); + +private: + Jit(); + + llvm::orc::ExecutionSession ES; + std::unique_ptr objectLayer{nullptr}; + std::unique_ptr compileLayer{nullptr}; + llvm::orc::JITDylib *jitDylib{nullptr}; + + std::unique_ptr dataLayout{nullptr}; + std::unique_ptr mangle{nullptr}; + std::unique_ptr context{nullptr}; + types::FunctionProtosT externalMathFunctions; + Optimizer optimizer; +}; // namespace Jit +} // namespace engine +} // namespace impala +#endif // IMPALA_CPP_ENGINE_H diff --git a/compiler/engine/engine_types.h b/compiler/engine/engine_types.h new file mode 100644 index 0000000..9093de2 --- /dev/null +++ b/compiler/engine/engine_types.h @@ -0,0 +1,17 @@ +#ifndef IMPALA_CPP_ENGINE_TYPES_H +#define IMPALA_CPP_ENGINE_TYPES_H + +#include "llvm/ExecutionEngine/Orc/Core.h" +#include "llvm/IR/Function.h" +#include + +namespace impala { +namespace engine { +namespace types { +using FunctionProtosT = std::unordered_map; +using FunctionSinatureT = std::pair; +} // namespace types +} // namespace engine +}; // namespace impala + +#endif // IMPALA_CPP_ENGINE_TYPES_H diff --git a/compiler/engine/hashers.h b/compiler/engine/hashers.h new file mode 100644 index 0000000..7a49366 --- /dev/null +++ b/compiler/engine/hashers.h @@ -0,0 +1,34 @@ +#ifndef IMPALA_CPP_HASHERS_H +#define IMPALA_CPP_HASHERS_H + +#include "engine_types.h" +#include +#include +#include + +namespace impala { +template inline void hashValue(std::size_t &seed, const T &value) { + std::hash hasher; + seed ^= hasher(value) + 0x9e3779b9 + (seed << 6) + (seed >> 2); +} + +template struct PairHash { + std::size_t operator()(std::pair const &instance) const { + std::size_t result = 0; + hashValue(result, instance.first); + hashValue(result, instance.second); + return result; + } +}; + +struct FunctionSignatureHash { + std::size_t operator()(engine::types::FunctionSinatureT const &instance) const { + std::size_t result = 0; + hashValue(result, instance.first); + hashValue(result, instance.second); + return result; + } +}; +} // namespace impala + +#endif // IMPALA_CPP_HASHERS_H diff --git a/compiler/engine/optimizer.cpp b/compiler/engine/optimizer.cpp new file mode 100644 index 0000000..a2899b9 --- /dev/null +++ b/compiler/engine/optimizer.cpp @@ -0,0 +1,32 @@ +#include "optimizer.h" +#include + +#include "llvm/Transforms/InstCombine/InstCombine.h" +#include "llvm/Transforms/Scalar/InstSimplifyPass.h" +#include "llvm/Transforms/Scalar/NewGVN.h" +#include "llvm/Transforms/Scalar/Reassociate.h" +#include "llvm/Transforms/Scalar/SimplifyCFG.h" + +namespace impala { +namespace engine { +Optimizer::Optimizer() { + passBuilder.registerModuleAnalyses(moduleAnalysisManager); + passBuilder.registerCGSCCAnalyses(cGSCCAnalysisManager); + passBuilder.registerFunctionAnalyses(functionAnalysisManager); + passBuilder.registerLoopAnalyses(loopAnalysisManager); + + passBuilder.crossRegisterProxies(loopAnalysisManager, functionAnalysisManager, cGSCCAnalysisManager, + moduleAnalysisManager); + + llvm::FunctionPassManager functionPassManager; + functionPassManager.addPass(llvm::InstCombinePass()); + functionPassManager.addPass(llvm::NewGVNPass()); + functionPassManager.addPass(llvm::InstSimplifyPass()); + functionPassManager.addPass(llvm::SimplifyCFGPass()); + + modulePassManager.addPass(llvm::createModuleToFunctionPassAdaptor(std::move(functionPassManager))); +} + +void Optimizer::run(llvm::Module &module) { modulePassManager.run(module, moduleAnalysisManager); } +} // namespace engine +} // namespace impala \ No newline at end of file diff --git a/compiler/engine/optimizer.h b/compiler/engine/optimizer.h new file mode 100644 index 0000000..96ce51b --- /dev/null +++ b/compiler/engine/optimizer.h @@ -0,0 +1,27 @@ +#ifndef IMPALAJIT_OPTIMIZER_H +#define IMPALAJIT_OPTIMIZER_H + +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Passes/PassBuilder.h" + +namespace impala { +namespace engine { +class Optimizer { +public: + Optimizer(); + + void run(llvm::Module &module); + +private: + llvm::PassBuilder passBuilder; + llvm::LoopAnalysisManager loopAnalysisManager; + llvm::FunctionAnalysisManager functionAnalysisManager; + llvm::CGSCCAnalysisManager cGSCCAnalysisManager; + llvm::ModuleAnalysisManager moduleAnalysisManager; + llvm::ModulePassManager modulePassManager; +}; +} // namespace engine +} // namespace impala + +#endif // IMPALAJIT_OPTIMIZER_H diff --git a/compiler/engine/std_math_lib.cpp b/compiler/engine/std_math_lib.cpp new file mode 100644 index 0000000..65cfd98 --- /dev/null +++ b/compiler/engine/std_math_lib.cpp @@ -0,0 +1,53 @@ +#include "std_math_lib.h" +#include "llvm/IR/Module.h" + +namespace impala { +namespace engine { + +StdMathLib::SupportedFunctionSetT &StdMathLib::getSupportedFunctionSet() { + static StdMathLib::SupportedFunctionSetT supportedSet{ + {"cos", 1}, {"sin", 1}, {"tan", 1}, {"acos", 1}, {"asin", 1}, {"atan", 1}, {"atan2", 2}, {"cosh", 1}, + {"sinh", 1}, {"tanh", 1}, {"exp", 1}, {"log", 1}, {"log10", 1}, {"pow", 2}, {"sqrt", 1}, {"min", 2}, + {"max", 2}, {"abs", 1}, {"floor", 1}, {"ceil", 1}, {"round", 1}, {"erf", 1}, {"erfc", 1}}; + return supportedSet; +} + +StdMathLib::FunctionAliasingMapT &StdMathLib::getFunctionAliasingMap() { + static StdMathLib::FunctionAliasingMapT aliasingMap{ + {"cos", "cos"}, {"sin", "sin"}, {"tan", "tan"}, {"asin", "asin"}, {"acos", "acos"}, {"atan", "atan"}, + {"atan2", "atan2"}, {"cosh", "cosh"}, {"sinh", "sinh"}, {"tanh", "tanh"}, {"exp", "exp"}, {"log", "log"}, + {"log10", "log10"}, {"pow", "pow"}, {"sqrt", "sqrt"}, {"min", "fmin"}, {"max", "fmax"}, {"abs", "abs"}, + {"floor", "floor"}, {"ceil", "ceil"}, {"round", "round"}, {"erf", "erf"}, {"erfc", "erfc"}}; + + return aliasingMap; +} + +bool StdMathLib::isSupported(const types::FunctionSinatureT &signature) { + auto &supportedSet = StdMathLib::getSupportedFunctionSet(); + return supportedSet.find(signature) != supportedSet.end(); +} + +types::FunctionProtosT StdMathLib::fillModule(std::unique_ptr &module, bool isDoublePrecision) { + + auto &context = module->getContext(); + llvm::Type *realType = (isDoublePrecision) ? llvm::Type::getDoubleTy(context) : llvm::Type::getFloatTy(context); + std::unordered_map functionProtoTable; + + auto &supportedSet = StdMathLib::getSupportedFunctionSet(); + auto &aliasingMap = StdMathLib::getFunctionAliasingMap(); + for (const auto &signature : supportedSet) { + const auto &name = signature.first; + const unsigned numParams = signature.second; + const std::string &realName = aliasingMap[name]; + + std::vector params(numParams, realType); + llvm::FunctionType *functionType = llvm::FunctionType::get(realType, params, false); + llvm::Function *function = llvm::Function::Create(functionType, llvm::Function::ExternalLinkage, realName, *module); + + functionProtoTable[name] = function; + } + + return functionProtoTable; +} +} // namespace engine +} // namespace impala diff --git a/compiler/engine/std_math_lib.h b/compiler/engine/std_math_lib.h new file mode 100644 index 0000000..6ff02b8 --- /dev/null +++ b/compiler/engine/std_math_lib.h @@ -0,0 +1,29 @@ +#ifndef IMPALA_CPP_STD_MATH_LIB_HPP +#define IMPALA_CPP_STD_MATH_LIB_HPP + +#include "hashers.h" +#include "llvm/ExecutionEngine/Orc/Core.h" +#include +#include +#include +#include +#include + +namespace impala { +namespace engine { +class StdMathLib { +public: + static types::FunctionProtosT fillModule(std::unique_ptr &module, bool isDoublePrecision); + static bool isSupported(const types::FunctionSinatureT &signature); + +private: + using SupportedFunctionSetT = std::unordered_set; + using FunctionAliasingMapT = std::unordered_map; + + static SupportedFunctionSetT &getSupportedFunctionSet(); + static FunctionAliasingMapT &getFunctionAliasingMap(); +}; +} // namespace engine +} // namespace impala + +#endif // IMPALA_CPP_STD_MATH_LIB_HPP diff --git a/compiler/frontend/scanner.cc b/compiler/frontend/scanner.cc index 7f5c7fb..aa4d63c 100644 --- a/compiler/frontend/scanner.cc +++ b/compiler/frontend/scanner.cc @@ -7,7 +7,6 @@ /* A lexical scanner generated by flex */ /* %not-for-header */ - /* %if-c-only */ /* %if-not-reentrant */ /* %endif */ @@ -17,7 +16,7 @@ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 6 -#define YY_FLEX_SUBMINOR_VERSION 0 +#define YY_FLEX_SUBMINOR_VERSION 4 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif @@ -35,6 +34,24 @@ /* %if-c-only */ /* %endif */ +#ifdef yyalloc +#define ImpalaJITalloc_ALREADY_DEFINED +#else +#define yyalloc ImpalaJITalloc +#endif + +#ifdef yyrealloc +#define ImpalaJITrealloc_ALREADY_DEFINED +#else +#define yyrealloc ImpalaJITrealloc +#endif + +#ifdef yyfree +#define ImpalaJITfree_ALREADY_DEFINED +#else +#define yyfree ImpalaJITfree +#endif + /* %if-c-only */ /* %endif */ @@ -109,15 +126,19 @@ typedef unsigned int flex_uint32_t; #define UINT32_MAX (4294967295U) #endif +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + #endif /* ! C99 */ #endif /* ! FLEXINT_H */ /* %endif */ -/* %if-c++-only */ /* begin standard C++ headers. */ -#include +/* %if-c++-only */ +#include #include #include #include @@ -125,41 +146,25 @@ typedef unsigned int flex_uint32_t; /* end standard C++ headers. */ /* %endif */ -#ifdef __cplusplus - -/* The "const" storage-class-modifier is valid. */ -#define YY_USE_CONST - -#else /* ! __cplusplus */ - -/* C99 requires __STDC__ to be defined as 1. */ -#if defined (__STDC__) - -#define YY_USE_CONST - -#endif /* defined (__STDC__) */ -#endif /* ! __cplusplus */ - -#ifdef YY_USE_CONST +/* TODO: this is always defined, so inline it */ #define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) #else -#define yyconst +#define yynoreturn #endif /* %not-for-header */ - /* Returned upon end-of-file. */ #define YY_NULL 0 /* %ok-for-header */ /* %not-for-header */ - -/* Promotes a possibly negative, possibly signed char to an unsigned - * integer for use as an array index. If the signed char is negative, - * we want to instead treat it as an 8-bit unsigned char, hence the - * double cast. +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. */ -#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) /* %ok-for-header */ /* %if-reentrant */ @@ -174,20 +179,16 @@ typedef unsigned int flex_uint32_t; * definition of BEGIN. */ #define BEGIN (yy_start) = 1 + 2 * - /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START - /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) - /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart( yyin ) - #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ @@ -218,7 +219,7 @@ typedef size_t yy_size_t; #endif /* %if-not-reentrant */ -extern yy_size_t yyleng; +extern int yyleng; /* %endif */ /* %if-c-only */ @@ -229,7 +230,7 @@ extern yy_size_t yyleng; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 - + #define YY_LESS_LINENO(n) #define YY_LINENO_REWIND_TO(ptr) @@ -246,7 +247,6 @@ extern yy_size_t yyleng; YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) - #define unput(c) yyunput( c, (yytext_ptr) ) #ifndef YY_STRUCT_YY_BUFFER_STATE @@ -257,7 +257,7 @@ struct yy_buffer_state /* %endif */ /* %if-c++-only */ - std::streambuf* yy_input_file; + std::streambuf* yy_input_file; /* %endif */ char *yy_ch_buf; /* input buffer */ @@ -266,7 +266,7 @@ struct yy_buffer_state /* Size of input buffer in bytes, not including room for EOB * characters. */ - yy_size_t yy_buf_size; + int yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. @@ -294,7 +294,7 @@ struct yy_buffer_state int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ - + /* Whether to try to fill the input buffer when we reach the * end of it. */ @@ -321,7 +321,6 @@ struct yy_buffer_state /* %if-c-only Standard (non-C++) definition */ /* %not-for-header */ - /* %if-not-reentrant */ /* %endif */ /* %ok-for-header */ @@ -337,7 +336,6 @@ struct yy_buffer_state #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) - /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ @@ -346,18 +344,16 @@ struct yy_buffer_state /* %if-c-only Standard (non-C++) definition */ /* %if-not-reentrant */ /* %not-for-header */ - /* %ok-for-header */ /* %endif */ /* %endif */ -void *ImpalaJITalloc (yy_size_t ); -void *ImpalaJITrealloc (void *,yy_size_t ); -void ImpalaJITfree (void * ); +void *yyalloc ( yy_size_t ); +void *yyrealloc ( void *, yy_size_t ); +void yyfree ( void * ); #define yy_new_buffer yy_create_buffer - #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ @@ -367,7 +363,6 @@ void ImpalaJITfree (void * ); } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } - #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ @@ -377,15 +372,13 @@ void ImpalaJITfree (void * ); } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } - #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* %% [1.0] yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here */ /* Begin user sect3 */ #define FLEX_DEBUG - -typedef unsigned char YY_CHAR; +typedef flex_uint8_t YY_CHAR; #define yytext_ptr yytext @@ -402,12 +395,11 @@ typedef unsigned char YY_CHAR; #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ /* %% [2.0] code to fiddle yytext and yyleng for yymore() goes here \ */\ - yyleng = (size_t) (yy_cp - yy_bp); \ + yyleng = (int) (yy_cp - yy_bp); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ /* %% [3.0] code to copy yytext_ptr to yytext[] goes here, if %array \ */\ (yy_c_buf_p) = yy_cp; - /* %% [4.0] data tables for the DFA and the user's section 1 definitions go here */ #define YY_NUM_RULES 19 #define YY_END_OF_BUFFER 20 @@ -418,7 +410,7 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_accept[41] = +static const flex_int16_t yy_accept[41] = { 0, 0, 0, 20, 18, 16, 17, 18, 18, 13, 1, 14, 6, 18, 7, 15, 15, 15, 15, 18, 16, @@ -426,7 +418,7 @@ static yyconst flex_int16_t yy_accept[41] = 10, 15, 9, 15, 15, 11, 15, 15, 12, 0 } ; -static yyconst YY_CHAR yy_ec[256] = +static const YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, @@ -458,14 +450,14 @@ static yyconst YY_CHAR yy_ec[256] = 1, 1, 1, 1, 1 } ; -static yyconst YY_CHAR yy_meta[26] = +static const YY_CHAR yy_meta[26] = { 0, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 } ; -static yyconst flex_uint16_t yy_base[42] = +static const flex_int16_t yy_base[42] = { 0, 0, 0, 53, 54, 50, 54, 40, 44, 54, 21, 54, 38, 37, 36, 0, 27, 28, 28, 18, 40, @@ -474,7 +466,7 @@ static yyconst flex_uint16_t yy_base[42] = 30 } ; -static yyconst flex_int16_t yy_def[42] = +static const flex_int16_t yy_def[42] = { 0, 40, 1, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 40, 40, @@ -483,7 +475,7 @@ static yyconst flex_int16_t yy_def[42] = 40 } ; -static yyconst flex_uint16_t yy_nxt[80] = +static const flex_int16_t yy_nxt[80] = { 0, 4, 5, 6, 7, 4, 8, 9, 10, 11, 12, 13, 14, 15, 4, 4, 16, 15, 17, 15, 15, @@ -495,7 +487,7 @@ static yyconst flex_uint16_t yy_nxt[80] = 40, 40, 40, 40, 40, 40, 40, 40, 40 } ; -static yyconst flex_int16_t yy_chk[80] = +static const flex_int16_t yy_chk[80] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -507,10 +499,10 @@ static yyconst flex_int16_t yy_chk[80] = 40, 40, 40, 40, 40, 40, 40, 40, 40 } ; -static yyconst flex_int16_t yy_rule_linenum[19] = +static const flex_int16_t yy_rule_linenum[19] = { 0, - 80, 87, 91, 95, 99, 103, 107, 115, 119, 125, - 129, 136, 143, 147, 153, 160, 165, 171 + 81, 88, 92, 96, 100, 104, 108, 116, 120, 126, + 130, 137, 144, 148, 154, 161, 166, 172 } ; /* The intent behind this definition is that it'll catch @@ -560,6 +552,7 @@ typedef impalajit::Parser::token_type token_type; * on Win32. The C++ scanner uses STL streams instead. */ #define YY_NO_UNISTD_H +#line 556 "scanner.cc" /*** Flex Declarations and Options ***/ /* enable c++ scanner class generation */ /* change the name of the scanner class. results in "ImpalaJITFlexLexer" */ @@ -572,7 +565,8 @@ typedef impalajit::Parser::token_type token_type; * yylex is invoked, the begin position is moved onto the end position. */ #line 68 "scanner.ll" #define YY_USER_ACTION yylloc->columns(yyleng); -#line 576 "scanner.cc" +#line 569 "scanner.cc" +#line 570 "scanner.cc" #define INITIAL 0 @@ -602,23 +596,21 @@ typedef impalajit::Parser::token_type token_type; /* %if-bison-bridge */ /* %endif */ /* %not-for-header */ - /* %ok-for-header */ /* %endif */ #ifndef yytext_ptr -static void yy_flex_strncpy (char *,yyconst char *,int ); +static void yy_flex_strncpy ( char *, const char *, int ); #endif #ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * ); +static int yy_flex_strlen ( const char * ); #endif #ifndef YY_NO_INPUT /* %if-c-only Standard (non-C++) definition */ /* %not-for-header */ - /* %ok-for-header */ /* %endif */ @@ -684,11 +676,9 @@ static int yy_flex_strlen (yyconst char * ); /* %if-tables-serialization structures and prototypes */ /* %not-for-header */ - /* %ok-for-header */ /* %not-for-header */ - /* %tables-yydmap generated elements */ /* %endif */ /* end tables serialization structures and prototypes */ @@ -724,7 +714,6 @@ static int yy_flex_strlen (yyconst char * ); YY_USER_ACTION /* %not-for-header */ - /** The main scanner function which does all the work. */ YY_DECL @@ -772,6 +761,7 @@ YY_DECL #line 71 "scanner.ll" +#line 74 "scanner.ll" /* code to place at the beginning of yylex() */ // reset location @@ -779,7 +769,7 @@ YY_DECL /*** Numbers ***/ -#line 783 "scanner.cc" +#line 773 "scanner.cc" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { @@ -809,9 +799,9 @@ YY_DECL { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 41 ) - yy_c = yy_meta[(unsigned int) yy_c]; + yy_c = yy_meta[yy_c]; } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } while ( yy_current_state != 40 ); @@ -856,7 +846,7 @@ YY_DECL case 1: YY_RULE_SETUP -#line 80 "scanner.ll" +#line 81 "scanner.ll" { yylval->doubleVal = atof(yytext); return token::DOUBLE; @@ -865,7 +855,7 @@ YY_RULE_SETUP /*** COMPARE OPERATORS ***/ case 2: YY_RULE_SETUP -#line 87 "scanner.ll" +#line 88 "scanner.ll" { yylval->integerVal = LTE; return token::CMPOP; @@ -873,7 +863,7 @@ YY_RULE_SETUP YY_BREAK case 3: YY_RULE_SETUP -#line 91 "scanner.ll" +#line 92 "scanner.ll" { yylval->integerVal = GTE; return token::CMPOP; @@ -881,7 +871,7 @@ YY_RULE_SETUP YY_BREAK case 4: YY_RULE_SETUP -#line 95 "scanner.ll" +#line 96 "scanner.ll" { yylval->integerVal = EQ; return token::CMPOP; @@ -889,7 +879,7 @@ YY_RULE_SETUP YY_BREAK case 5: YY_RULE_SETUP -#line 99 "scanner.ll" +#line 100 "scanner.ll" { yylval->integerVal = NE; return token::CMPOP; @@ -897,7 +887,7 @@ YY_RULE_SETUP YY_BREAK case 6: YY_RULE_SETUP -#line 103 "scanner.ll" +#line 104 "scanner.ll" { yylval->integerVal = LT; return token::CMPOP; @@ -905,7 +895,7 @@ YY_RULE_SETUP YY_BREAK case 7: YY_RULE_SETUP -#line 107 "scanner.ll" +#line 108 "scanner.ll" { yylval->integerVal = GT; return token::CMPOP; @@ -914,7 +904,7 @@ YY_RULE_SETUP /*** BOOL OPERATORS ***/ case 8: YY_RULE_SETUP -#line 115 "scanner.ll" +#line 116 "scanner.ll" { yylval->integerVal = AND; return token::AND; @@ -922,7 +912,7 @@ YY_RULE_SETUP YY_BREAK case 9: YY_RULE_SETUP -#line 119 "scanner.ll" +#line 120 "scanner.ll" { yylval->integerVal = OR; return token::OR; @@ -931,7 +921,7 @@ YY_RULE_SETUP /*** Conditionals ***/ case 10: YY_RULE_SETUP -#line 125 "scanner.ll" +#line 126 "scanner.ll" { yylval->stringVal = new std::string(yytext, yyleng); return token::IF; @@ -939,7 +929,7 @@ YY_RULE_SETUP YY_BREAK case 11: YY_RULE_SETUP -#line 129 "scanner.ll" +#line 130 "scanner.ll" { yylval->stringVal = new std::string(yytext, yyleng); return token::ELSE; @@ -948,7 +938,7 @@ YY_RULE_SETUP /*** return ***/ case 12: YY_RULE_SETUP -#line 136 "scanner.ll" +#line 137 "scanner.ll" { yylval->stringVal = new std::string(yytext, yyleng); return token::RETURN; @@ -957,7 +947,7 @@ YY_RULE_SETUP /*** Special strings ***/ case 13: YY_RULE_SETUP -#line 143 "scanner.ll" +#line 144 "scanner.ll" { yylval->stringVal = new std::string(yytext, yyleng); return token::COMMA; @@ -965,7 +955,7 @@ YY_RULE_SETUP YY_BREAK case 14: YY_RULE_SETUP -#line 147 "scanner.ll" +#line 148 "scanner.ll" { yylval->stringVal = new std::string(yytext, yyleng); return token::SEMICOLON; @@ -973,7 +963,7 @@ YY_RULE_SETUP YY_BREAK case 15: YY_RULE_SETUP -#line 153 "scanner.ll" +#line 154 "scanner.ll" { yylval->stringVal = new std::string(yytext, yyleng); return token::STRING; @@ -982,7 +972,7 @@ YY_RULE_SETUP /* gobble up white-spaces */ case 16: YY_RULE_SETUP -#line 160 "scanner.ll" +#line 161 "scanner.ll" { yylloc->step(); } @@ -991,7 +981,7 @@ YY_RULE_SETUP case 17: /* rule 17 can match eol */ YY_RULE_SETUP -#line 165 "scanner.ll" +#line 166 "scanner.ll" { yylloc->lines(yyleng); yylloc->step(); // return token::EOL; @@ -1000,7 +990,7 @@ YY_RULE_SETUP /* pass all other characters up to bison */ case 18: YY_RULE_SETUP -#line 171 "scanner.ll" +#line 172 "scanner.ll" { return static_cast(*yytext); } @@ -1008,10 +998,10 @@ YY_RULE_SETUP /*** END EXAMPLE - Change the impalajit lexer rules above ***/ case 19: YY_RULE_SETUP -#line 177 "scanner.ll" +#line 178 "scanner.ll" ECHO; YY_BREAK -#line 1015 "scanner.cc" +#line 1005 "scanner.cc" case YY_STATE_EOF(INITIAL): yyterminate(); @@ -1154,12 +1144,11 @@ case YY_STATE_EOF(INITIAL): /* %if-c++-only */ /* %not-for-header */ - /* The contents of this function are C++ specific, so the () macro is not used. * This constructor simply maintains backward compatibility. * DEPRECATED */ -yyFlexLexer::yyFlexLexer( FLEX_STD istream* arg_yyin, FLEX_STD ostream* arg_yyout ): +yyFlexLexer::yyFlexLexer( std::istream* arg_yyin, std::ostream* arg_yyout ): yyin(arg_yyin ? arg_yyin->rdbuf() : std::cin.rdbuf()), yyout(arg_yyout ? arg_yyout->rdbuf() : std::cout.rdbuf()) { @@ -1195,7 +1184,7 @@ void yyFlexLexer::ctor_common() yy_start_stack_ptr = yy_start_stack_depth = 0; yy_start_stack = NULL; - yy_buffer_stack = 0; + yy_buffer_stack = NULL; yy_buffer_stack_top = 0; yy_buffer_stack_max = 0; @@ -1208,9 +1197,9 @@ void yyFlexLexer::ctor_common() yyFlexLexer::~yyFlexLexer() { delete [] yy_state_buf; - ImpalaJITfree(yy_start_stack ); + yyfree( yy_start_stack ); yy_delete_buffer( YY_CURRENT_BUFFER ); - ImpalaJITfree(yy_buffer_stack ); + yyfree( yy_buffer_stack ); } /* The contents of this function are C++ specific, so the () macro is not used. @@ -1293,7 +1282,7 @@ int yyFlexLexer::yy_get_next_buffer() { char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; char *source = (yytext_ptr); - yy_size_t number_to_move, i; + int number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) @@ -1322,7 +1311,7 @@ int yyFlexLexer::yy_get_next_buffer() /* Try to read more data. */ /* First move last chars to start of buffer. */ - number_to_move = (yy_size_t) ((yy_c_buf_p) - (yytext_ptr)) - 1; + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1); for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); @@ -1335,7 +1324,7 @@ int yyFlexLexer::yy_get_next_buffer() else { - yy_size_t num_to_read = + int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) @@ -1349,7 +1338,7 @@ int yyFlexLexer::yy_get_next_buffer() if ( b->yy_is_our_buffer ) { - yy_size_t new_size = b->yy_buf_size * 2; + int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; @@ -1358,11 +1347,12 @@ int yyFlexLexer::yy_get_next_buffer() b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ - ImpalaJITrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); + yyrealloc( (void *) b->yy_ch_buf, + (yy_size_t) (b->yy_buf_size + 2) ); } else /* Can't grow it, we don't own it. */ - b->yy_ch_buf = 0; + b->yy_ch_buf = NULL; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( @@ -1404,12 +1394,15 @@ int yyFlexLexer::yy_get_next_buffer() else ret_val = EOB_ACT_CONTINUE_SCAN; - if ((int) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) ImpalaJITrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( + (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); } (yy_n_chars) += number_to_move; @@ -1425,7 +1418,6 @@ int yyFlexLexer::yy_get_next_buffer() /* %if-c-only */ /* %not-for-header */ - /* %endif */ /* %if-c++-only */ yy_state_type yyFlexLexer::yy_get_previous_state() @@ -1450,9 +1442,9 @@ int yyFlexLexer::yy_get_next_buffer() { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 41 ) - yy_c = yy_meta[(unsigned int) yy_c]; + yy_c = yy_meta[yy_c]; } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; } return yy_current_state; @@ -1483,9 +1475,9 @@ int yyFlexLexer::yy_get_next_buffer() { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 41 ) - yy_c = yy_meta[(unsigned int) yy_c]; + yy_c = yy_meta[yy_c]; } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; yy_is_jam = (yy_current_state == 40); return yy_is_jam ? 0 : yy_current_state; @@ -1508,7 +1500,7 @@ int yyFlexLexer::yy_get_next_buffer() if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ - yy_size_t number_to_move = (yy_n_chars) + 2; + int number_to_move = (yy_n_chars) + 2; char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; char *source = @@ -1520,7 +1512,7 @@ int yyFlexLexer::yy_get_next_buffer() yy_cp += (int) (dest - source); yy_bp += (int) (dest - source); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = - (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + (yy_n_chars) = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size; if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) YY_FATAL_ERROR( "flex scanner push-back overflow" ); @@ -1560,7 +1552,7 @@ int yyFlexLexer::yy_get_next_buffer() else { /* need more input */ - yy_size_t offset = (yy_c_buf_p) - (yytext_ptr); + int offset = (int) ((yy_c_buf_p) - (yytext_ptr)); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) @@ -1584,7 +1576,7 @@ int yyFlexLexer::yy_get_next_buffer() case EOB_ACT_END_OF_FILE: { if ( yywrap( ) ) - return EOF; + return 0; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; @@ -1643,6 +1635,9 @@ int yyFlexLexer::yy_get_next_buffer() */ void yyFlexLexer::yyrestart( std::istream* input_file ) { + if( ! input_file ) { + input_file = &yyin; + } yyrestart( *input_file ); } /* %endif */ @@ -1716,16 +1711,16 @@ void yyFlexLexer::yyrestart( std::istream* input_file ) { YY_BUFFER_STATE b; - b = (YY_BUFFER_STATE) ImpalaJITalloc(sizeof( struct yy_buffer_state ) ); + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - b->yy_buf_size = (yy_size_t)size; + b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ - b->yy_ch_buf = (char *) ImpalaJITalloc(b->yy_buf_size + 2 ); + b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); @@ -1767,9 +1762,9 @@ void yyFlexLexer::yyrestart( std::istream* input_file ) YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) - ImpalaJITfree((void *) b->yy_ch_buf ); + yyfree( (void *) b->yy_ch_buf ); - ImpalaJITfree((void *) b ); + yyfree( (void *) b ); } /* Initializes or reinitializes a buffer. @@ -1924,15 +1919,15 @@ void yyFlexLexer::yyensure_buffer_stack(void) * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ - num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ - (yy_buffer_stack) = (struct yy_buffer_state**)ImpalaJITalloc + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); - + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); - + (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; @@ -1944,7 +1939,7 @@ void yyFlexLexer::yyensure_buffer_stack(void) yy_size_t grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; - (yy_buffer_stack) = (struct yy_buffer_state**)ImpalaJITrealloc + (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc ((yy_buffer_stack), num_to_alloc * sizeof(struct yy_buffer_state*) ); @@ -1978,13 +1973,14 @@ void yyFlexLexer::yyensure_buffer_stack(void) yy_size_t new_size; (yy_start_stack_depth) += YY_START_STACK_INCR; - new_size = (yy_start_stack_depth) * sizeof( int ); + new_size = (yy_size_t) (yy_start_stack_depth) * sizeof( int ); if ( ! (yy_start_stack) ) - (yy_start_stack) = (int *) ImpalaJITalloc(new_size ); + (yy_start_stack) = (int *) yyalloc( new_size ); else - (yy_start_stack) = (int *) ImpalaJITrealloc((void *) (yy_start_stack),new_size ); + (yy_start_stack) = (int *) yyrealloc( + (void *) (yy_start_stack), new_size ); if ( ! (yy_start_stack) ) YY_FATAL_ERROR( "out of memory expanding start-condition stack" ); @@ -2023,7 +2019,7 @@ void yyFlexLexer::yyensure_buffer_stack(void) /* %if-c-only */ /* %endif */ /* %if-c++-only */ -void yyFlexLexer::LexerError( yyconst char msg[] ) +void yyFlexLexer::LexerError( const char* msg ) { std::cerr << msg << std::endl; exit( YY_EXIT_FAILURE ); @@ -2074,7 +2070,7 @@ void yyFlexLexer::LexerError( yyconst char msg[] ) */ #ifndef yytext_ptr -static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +static void yy_flex_strncpy (char* s1, const char * s2, int n ) { int i; @@ -2084,7 +2080,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) #endif #ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * s ) +static int yy_flex_strlen (const char * s ) { int n; for ( n = 0; s[n]; ++n ) @@ -2094,12 +2090,12 @@ static int yy_flex_strlen (yyconst char * s ) } #endif -void *ImpalaJITalloc (yy_size_t size ) +void *yyalloc (yy_size_t size ) { - return (void *) malloc( size ); + return malloc(size); } -void *ImpalaJITrealloc (void * ptr, yy_size_t size ) +void *yyrealloc (void * ptr, yy_size_t size ) { /* The cast to (char *) in the following accommodates both @@ -2109,12 +2105,12 @@ void *ImpalaJITrealloc (void * ptr, yy_size_t size ) * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ - return (void *) realloc( (char *) ptr, size ); + return realloc(ptr, size); } -void ImpalaJITfree (void * ptr ) +void yyfree (void * ptr ) { - free( (char *) ptr ); /* see ImpalaJITrealloc() for (char *) cast */ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } /* %if-tables-serialization definitions */ @@ -2124,8 +2120,7 @@ void ImpalaJITfree (void * ptr ) /* %ok-for-header */ -#line 177 "scanner.ll" - +#line 178 "scanner.ll" namespace impalajit { diff --git a/compiler/include/driver.h b/compiler/include/driver.h index 20e4176..1beac7a 100644 --- a/compiler/include/driver.h +++ b/compiler/include/driver.h @@ -20,41 +20,42 @@ #ifndef IMPALAJIT_DRIVER_H #define IMPALAJIT_DRIVER_H - - -#include #include +#include #include #include #include - namespace impalajit { -class Driver -{ +class Driver { private: - FunctionContext* functionContext; + FunctionContext *functionContext; + public: - Driver(); - ~Driver(); + Driver(); + ~Driver(); - class Scanner* lexer; + class Scanner *lexer; - std::map parse_stream(std::istream& in); + FunctionContext::FunctionSinatureT generateLLVMFunction(std::istream &in, + llvm::Module &module, + const impalajit::Options& options); - std::map parse_string(const std::string& input); + FunctionContext::FunctionSinatureT generateLLVMFunction(const std::string &input, + llvm::Module &module, + const impalajit::Options& options); - void setFunctionContext(FunctionContext* _functionContext); + void setFunctionContext(FunctionContext *_functionContext); - void deleteFunctionContext(); + void deleteFunctionContext(); - unsigned int getParameterCount(); + unsigned int getParameterCount(); - void error(const class location& l, const std::string& m); + void error(const class location &l, const std::string &m); - void error(const std::string& m); + void error(const std::string &m); }; } // namespace impalajit diff --git a/compiler/include/function_context.h b/compiler/include/function_context.h index 09318fa..c6864f2 100644 --- a/compiler/include/function_context.h +++ b/compiler/include/function_context.h @@ -19,34 +19,35 @@ #ifndef IMPALAJIT_FUNCTION_CONTEXT_HH #define IMPALAJIT_FUNCTION_CONTEXT_HH -#include -#include -#include #include +#include +#include +#include class FunctionContext { public: - std::vector parameters; - std::vector variables; - Node* root; - std::string name; + using FunctionSinatureT = std::pair; - FunctionContext(std::string &_name, std::vector &_parameters, Node* &_root); + std::vector parameters; + std::vector variables; + Node *root; + std::string name; - ~FunctionContext(); + FunctionContext(std::string &_name, std::vector &_parameters, Node *&_root); - bool containsParameter(std::string& name); + ~FunctionContext(); - bool containsVariable(std::string& name); + bool containsParameter(std::string &name); - int getIndexOfParameter(std::string& name); + bool containsVariable(std::string &name); - int getIndexOfVariable(std::string &name); + int getIndexOfParameter(std::string &name); - unsigned int getParameterCount(); + int getIndexOfVariable(std::string &name); - void clear(); + unsigned int getParameterCount(); + void clear(); }; -#endif //IMPALAJIT_FUNCTION_CONTEXT_HH +#endif // IMPALAJIT_FUNCTION_CONTEXT_HH diff --git a/compiler/include/nodes/assignment_nodes.h b/compiler/include/nodes/assignment_nodes.h index 315ce5a..e73dd49 100644 --- a/compiler/include/nodes/assignment_nodes.h +++ b/compiler/include/nodes/assignment_nodes.h @@ -22,23 +22,15 @@ #include -class AssignmentNode : public Node -{ +class AssignmentNode : public Node { public: - std::string &name; - AssignmentNode(std::string &_name, Node* _node) - : name(_name), Node(ASSIGNMENT) - { - nodes.push_back(_node); - } + std::string &name; + AssignmentNode(std::string &_name, Node *_node) : name(_name), Node(ASSIGNMENT) { nodes.push_back(_node); } - virtual ~AssignmentNode() - { - } -/* - virtual void evaluate() { - node->evaluate(); - assembly.storeLocalVariable(); - }*/ + virtual ~AssignmentNode() {} + + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); + } }; -#endif //IMPALAJIT_ASSIGNMENT_EXPRESSION_HH +#endif // IMPALAJIT_ASSIGNMENT_EXPRESSION_HH diff --git a/compiler/include/nodes/boolean_nodes.h b/compiler/include/nodes/boolean_nodes.h index 0bfbdb3..8269e68 100644 --- a/compiler/include/nodes/boolean_nodes.h +++ b/compiler/include/nodes/boolean_nodes.h @@ -25,20 +25,21 @@ class BooleanAndNode : public Node { public: - BooleanAndNode() - : Node(BOOLEAN_AND_JUNCTION) - { - } -}; + BooleanAndNode() : Node(BOOLEAN_AND_JUNCTION) {} + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); + } +}; class BooleanOrNode : public Node { public: - BooleanOrNode() - : Node(BOOLEAN_OR_JUNCTION) - { - } + BooleanOrNode() : Node(BOOLEAN_OR_JUNCTION) {} + + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); + } }; -#endif //IMPALAJIT_BOOL_H +#endif // IMPALAJIT_BOOL_H diff --git a/compiler/include/nodes/compare_nodes.h b/compiler/include/nodes/compare_nodes.h index f06ce03..8d62582 100644 --- a/compiler/include/nodes/compare_nodes.h +++ b/compiler/include/nodes/compare_nodes.h @@ -22,17 +22,18 @@ #include -class CompareNode : public Node -{ +class CompareNode : public Node { public: - CompareOperatorType compareOperator; - CompareNode(Node* _left, Node* _right, CompareOperatorType _compareOperator) - : Node(COMPARISON), compareOperator(_compareOperator) - { - nodes.push_back(_right); - nodes.push_back(_left); - } -}; + CompareOperatorType compareOperator; + CompareNode(Node *_left, Node *_right, CompareOperatorType _compareOperator) + : Node(COMPARISON), compareOperator(_compareOperator) { + nodes.push_back(_right); + nodes.push_back(_left); + } + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); + } +}; -#endif //IMPALAJIT_COMPARISON_EXPRESSION_H +#endif // IMPALAJIT_COMPARISON_EXPRESSION_H diff --git a/compiler/include/nodes/conditional_nodes.h b/compiler/include/nodes/conditional_nodes.h index 94b8ada..9fb0dc7 100644 --- a/compiler/include/nodes/conditional_nodes.h +++ b/compiler/include/nodes/conditional_nodes.h @@ -22,53 +22,50 @@ #include -class IfStmtNode : public Node -{ +class IfStmtNode : public Node { public: - IfStmtNode(Node* _condition, Node* _if_body) - : Node(IF_STATEMENT) - { - nodes.push_back(_condition); - nodes.push_back(_if_body); - } + IfStmtNode(Node *_condition, Node *_if_body) : Node(IF_STATEMENT) { + nodes.push_back(_condition); + nodes.push_back(_if_body); + } + + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); + } }; -class IfElseStmtNode : public Node -{ +class IfElseStmtNode : public Node { public: + IfElseStmtNode(Node *_condition, Node *_if_body, Node *_else_body) : Node(IF_ELSE_STATEMENT) { + nodes.push_back(_condition); + nodes.push_back(_if_body); + nodes.push_back(_else_body); + } - IfElseStmtNode(Node* _condition, Node* _if_body, Node* _else_body) - : Node(IF_ELSE_STATEMENT) - { - nodes.push_back(_condition); - nodes.push_back(_if_body); - nodes.push_back(_else_body); - } + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); + } }; -class IfBodyNode : public Node -{ +class IfBodyNode : public Node { public: - IfBodyNode() - : Node(IF_BODY) - { - } + IfBodyNode() : Node(IF_BODY) {} + + virtual ~IfBodyNode() {} - virtual ~IfBodyNode() - { - } + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); + } }; -class ElseBodyNode : public Node -{ +class ElseBodyNode : public Node { public: - ElseBodyNode() - : Node(ELSE_BODY) - { - } + ElseBodyNode() : Node(ELSE_BODY) {} + + virtual ~ElseBodyNode() {} - virtual ~ElseBodyNode() - { - } + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); + } }; -#endif //IMPALAJIT_COMPLEX_EXPRESSION_H +#endif // IMPALAJIT_COMPLEX_EXPRESSION_H diff --git a/compiler/include/nodes/expression_nodes.h b/compiler/include/nodes/expression_nodes.h index fb367d0..7d67dc8 100644 --- a/compiler/include/nodes/expression_nodes.h +++ b/compiler/include/nodes/expression_nodes.h @@ -22,88 +22,95 @@ #include -class ConstantNode : public Node -{ +class ConstantNode : public Node { public: - double value; - explicit ConstantNode(double _value) - : Node(CONSTANT), value(_value) - { - } + double value; + explicit ConstantNode(double _value) : Node(CONSTANT), value(_value) {} + + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); + } }; class VariableNode : public Node { public: - std::string &name; - VariableNode(std::string &_name) - : Node(VARIABLE), name(_name) { - } + std::string &name; + VariableNode(std::string &_name) : Node(VARIABLE), name(_name) {} + + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); + } }; -class NegationNode : public Node -{ +class NegationNode : public Node { public: - NegationNode(Node* _node) - : Node(NEGATION) - { - nodes.push_back(_node); - } + NegationNode(Node *_node) : Node(NEGATION) { nodes.push_back(_node); } + + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); + } }; -class AdditionNode : public Node -{ +class AdditionNode : public Node { public: - AdditionNode(Node* _left, Node* _right) - : Node(ADDITION) - { - nodes.push_back(_left); - nodes.push_back(_right); - } + AdditionNode(Node *_left, Node *_right) : Node(ADDITION) { + nodes.push_back(_left); + nodes.push_back(_right); + } + + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); + } }; -class SubtractionNode : public Node -{ +class SubtractionNode : public Node { public: - SubtractionNode(Node* _left, Node* _right) - : Node(SUBTRACTION) - { - nodes.push_back(_left); - nodes.push_back(_right); - } + SubtractionNode(Node *_left, Node *_right) : Node(SUBTRACTION) { + nodes.push_back(_left); + nodes.push_back(_right); + } + + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); + } }; -class MultiplicationNode : public Node -{ +class MultiplicationNode : public Node { public: - MultiplicationNode(Node* _left, Node* _right) - : Node(MULTIPLICATION) - { - nodes.push_back(_left); - nodes.push_back(_right); - } + MultiplicationNode(Node *_left, Node *_right) : Node(MULTIPLICATION) { + nodes.push_back(_left); + nodes.push_back(_right); + } + + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); + } }; -class DivisionNode : public Node -{ +class DivisionNode : public Node { public: - DivisionNode(Node* &_left, Node* &_right) - : Node(DIVISION) - { - nodes.push_back(_left); - nodes.push_back(_right); - } + DivisionNode(Node *&_left, Node *&_right) : Node(DIVISION) { + nodes.push_back(_left); + nodes.push_back(_right); + } + + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); + } }; -class PowerNode : public Node -{ +class PowerNode : public Node { +// TODO: delete public: - PowerNode(Node* _base, Node* _exponent) - : Node(POWER) - { - nodes.push_back(_exponent); - nodes.push_back(_base); - } + PowerNode(Node *_base, Node *_exponent) : Node(POWER) { + nodes.push_back(_exponent); + nodes.push_back(_base); + } + + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); + } }; -#endif //IMPALAJIT_BASIC_EXPRESSION_H_HH +#endif // IMPALAJIT_BASIC_EXPRESSION_H_HH diff --git a/compiler/include/nodes/external_function_nodes.h b/compiler/include/nodes/external_function_nodes.h index 14d2d5a..8c5e5ab 100644 --- a/compiler/include/nodes/external_function_nodes.h +++ b/compiler/include/nodes/external_function_nodes.h @@ -20,39 +20,35 @@ #ifndef IMPALAJIT_EXTERNAL_FUNCTION_NODE_H #define IMPALAJIT_EXTERNAL_FUNCTION_NODE_H -#include +#include "node.h" +#include "std_math_lib.h" #include +#include -class ExternalFunctionNode: public Node -{ +class ExternalFunctionNode : public Node { public: - std::string &name; - ExternalFunctionNode(std::string &_name, std::vector &_parameters) - : name(_name), Node(EXTERNAL_FUNCTION) - { - nodes.insert(nodes.end(), _parameters.begin(), _parameters.end()); - } - ExternalFunctionNode(std::string &_name) - : name(_name), Node(EXTERNAL_FUNCTION) - { - } - virtual ~ExternalFunctionNode() - { - } + std::string &name; + ExternalFunctionNode(std::string &_name, std::vector &_parameters) : name(_name), Node(EXTERNAL_FUNCTION) { + nodes.insert(nodes.end(), _parameters.begin(), _parameters.end()); + } + ExternalFunctionNode(std::string &_name) : name(_name), Node(EXTERNAL_FUNCTION) {} + virtual ~ExternalFunctionNode() {} + + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); + } }; -class ExternalFunctionParametersNode : public Node -{ +class ExternalFunctionParametersNode : public Node { +// TODO: delete public: - ExternalFunctionParametersNode() - : Node(EXTERNAL_FUNCTION_PARAMETER) - { - } - - virtual ~ExternalFunctionParametersNode() - { - } -}; + ExternalFunctionParametersNode() : Node(EXTERNAL_FUNCTION_PARAMETER) {} + virtual ~ExternalFunctionParametersNode() {} + + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); + } +}; -#endif //IMPALAJIT_EXTERNAL_FUNCTION_NODE_H \ No newline at end of file +#endif // IMPALAJIT_EXTERNAL_FUNCTION_NODE_H \ No newline at end of file diff --git a/compiler/include/nodes/node.h b/compiler/include/nodes/node.h index 339f8df..b456dca 100644 --- a/compiler/include/nodes/node.h +++ b/compiler/include/nodes/node.h @@ -20,32 +20,31 @@ #ifndef EXPRESSION_H #define EXPRESSION_H +#include "engine.h" +#include "abstract_visitor.h" #include +#include #include -class Node -{ + +class Node { public: - NodeType nodeType; - std::vector nodes; - - Node(NodeType _nodeType) : - nodeType(_nodeType) - { - } - virtual ~Node() - { - nodes.clear(); - } + NodeType nodeType; + std::vector nodes; + + Node(NodeType _nodeType) : nodeType(_nodeType) {} + virtual ~Node() { nodes.clear(); } + + virtual void accept(impala::AbstractVisitor* visitor) = 0; }; -class RootNode : public Node -{ +class RootNode : public Node { public: - RootNode() - : Node(ROOT) - { - } + RootNode() : Node(ROOT) {} + + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); + } }; #endif // EXPRESSION_H diff --git a/compiler/include/nodes/return_nodes.h b/compiler/include/nodes/return_nodes.h index fa22d0f..6430a77 100644 --- a/compiler/include/nodes/return_nodes.h +++ b/compiler/include/nodes/return_nodes.h @@ -22,13 +22,12 @@ #include -class ReturnNode : public Node -{ +class ReturnNode : public Node { public: - ReturnNode(Node* _node) - : Node(RETURN) - { - nodes.push_back(_node); - } + ReturnNode(Node *_node) : Node(RETURN) { nodes.push_back(_node); } + + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); + } }; -#endif //IMPALAJIT_RETURN_NODE_H +#endif // IMPALAJIT_RETURN_NODE_H diff --git a/compiler/include/symbol_table.h b/compiler/include/symbol_table.h new file mode 100644 index 0000000..8558a20 --- /dev/null +++ b/compiler/include/symbol_table.h @@ -0,0 +1,51 @@ +#ifndef IMPALA_CPP_SYMBOL_TABLE_H +#define IMPALA_CPP_SYMBOL_TABLE_H + +#include "engine_types.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Value.h" +#include +#include +#include +#include +#include + +namespace impala { + +struct SymbolTable { + SymbolTable() = default; + + void removeScope() { scopes.pop_back(); } + void addScope() { scopes.emplace_back(TableT{}); } + size_t getNumScopes() { return scopes.size(); } + + llvm::Value *operator[](const std::string &name) { + for (auto scope = scopes.rbegin(); scope != scopes.rend(); ++scope) { + if (scope->find(name) != scope->end()) { + return (*scope)[name]; + } + } + return nullptr; + } + + void addSymbol(const std::string &name, llvm::Value *value) { + if (scopes.empty()) { + this->addScope(); + } + auto &topMostScope = scopes.back(); + if (topMostScope.find(name) != topMostScope.end()) { + std::stringstream errStream; + errStream << "symbol `" << name << "` has already been defined in this scope"; + throw std::runtime_error(errStream.str()); + } else { + topMostScope[name] = value; + } + } + +private: + using TableT = std::unordered_map; + std::vector scopes{}; +}; +} // namespace impala + +#endif // IMPALA_CPP_SYMBOL_TABLE_H diff --git a/compiler/include/types/internal_types.hh b/compiler/include/types/internal_types.hh index fe65694..afe5730 100644 --- a/compiler/include/types/internal_types.hh +++ b/compiler/include/types/internal_types.hh @@ -23,34 +23,30 @@ typedef void (*externalFunction)(); enum NodeType { - ROOT, - CONSTANT, - VARIABLE, - NEGATION, - ADDITION, - SUBTRACTION, - MULTIPLICATION, - DIVISION, - POWER, - EXTERNAL_FUNCTION, - EXTERNAL_FUNCTION_PARAMETER, - ASSIGNMENT, - COMPARISON, - BOOLEAN_AND_JUNCTION, - BOOLEAN_OR_JUNCTION, - IF_STATEMENT, - IF_ELSE_STATEMENT, - IF_BODY, - ELSE_BODY, - RETURN + ROOT, + CONSTANT, + VARIABLE, + NEGATION, + ADDITION, + SUBTRACTION, + MULTIPLICATION, + DIVISION, + POWER, + EXTERNAL_FUNCTION, + EXTERNAL_FUNCTION_PARAMETER, + ASSIGNMENT, + COMPARISON, + BOOLEAN_AND_JUNCTION, + BOOLEAN_OR_JUNCTION, + IF_STATEMENT, + IF_ELSE_STATEMENT, + IF_BODY, + ELSE_BODY, + RETURN }; -enum CompareOperatorType{ - EQ=0, NE=4, GT=6, LT=9, GTE=5, LTE=2 -}; +enum CompareOperatorType { EQ = 0, NE = 4, GT = 6, LT = 9, GTE = 5, LTE = 2 }; -enum BooleanJunctionType{ - AND, OR -}; +enum BooleanJunctionType { AND, OR }; -#endif //IMPALAJIT_AST_TYPES_HH +#endif // IMPALAJIT_AST_TYPES_HH diff --git a/compiler/semantic_analysis/semantic_analyzer.cc b/compiler/semantic_analysis/semantic_analyzer.cc index 91b26c3..827dfb3 100644 --- a/compiler/semantic_analysis/semantic_analyzer.cc +++ b/compiler/semantic_analysis/semantic_analyzer.cc @@ -62,18 +62,6 @@ void SemanticAnalyzer::evaluateAst(FunctionContext* &functionContext, Node* &nod break; } } - - case NEGATION: - { - // Check if this is just a negative constant. - if(node->nodes.size()==1 && node->nodes.at(0)->nodeType==CONSTANT) { - double value = -(reinterpret_cast(node->nodes.at(0))->value); - delete node; - node = new ConstantNode(value); - } - dsfUtil(functionContext, node); - break; - } default: { dsfUtil(functionContext, node); @@ -84,8 +72,8 @@ void SemanticAnalyzer::evaluateAst(FunctionContext* &functionContext, Node* &nod void SemanticAnalyzer::dsfUtil(FunctionContext* &functionContext, Node* &node) { - for(std::vector::iterator it = node->nodes.begin(); it != node->nodes.end(); ++it) { - evaluateAst(functionContext, (*it)); + for (auto node: node->nodes) { + evaluateAst(functionContext, node); } } diff --git a/example/c/CMakeLists.txt b/example/c/CMakeLists.txt new file mode 100644 index 0000000..bf2a825 --- /dev/null +++ b/example/c/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 2.6) +project(impala-c) + +add_subdirectory(${PROJECT_SOURCE_DIR}/root) +add_executable(${CMAKE_PROJECT_NAME} ${PROJECT_SOURCE_DIR}/example.c) +target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/root/include) +target_link_libraries(${CMAKE_PROJECT_NAME} impalajit-static) + +file(COPY ${PROJECT_SOURCE_DIR}/example.conf DESTINATION .) +file(COPY ${PROJECT_SOURCE_DIR}/impala_file DESTINATION .) \ No newline at end of file diff --git a/example/c/root b/example/c/root new file mode 120000 index 0000000..c25bddb --- /dev/null +++ b/example/c/root @@ -0,0 +1 @@ +../.. \ No newline at end of file diff --git a/example/cpp/CMakeLists.txt b/example/cpp/CMakeLists.txt new file mode 100644 index 0000000..c97b3e2 --- /dev/null +++ b/example/cpp/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 2.6) +project(impala-cpp) + + +add_subdirectory(${PROJECT_SOURCE_DIR}/root) + +add_executable(${CMAKE_PROJECT_NAME} ${PROJECT_SOURCE_DIR}/example.cc) +target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/root/include) +target_link_libraries(${CMAKE_PROJECT_NAME} impalajit) + +file(COPY ${PROJECT_SOURCE_DIR}/example.conf DESTINATION .) +file(COPY ${PROJECT_SOURCE_DIR}/impala_file DESTINATION .) \ No newline at end of file diff --git a/example/cpp/example.cc b/example/cpp/example.cc index d96ffb1..a27a10b 100644 --- a/example/cpp/example.cc +++ b/example/cpp/example.cc @@ -17,15 +17,18 @@ * THE SOFTWARE. */ - #include #include -int main() -{ - impalajit::Compiler compiler("example.conf"); - compiler.compile(); - dasm_gen_func example = compiler.getFunction("example"); - std::cout << "Result: " << example(3.0, 4.0) << std::endl; - return 0; +int main() { + impalajit::Options options; + options.printIR = true; + options.printAST = true; + + impalajit::Compiler compiler("example.conf"); + + compiler.compile(options); + dasm_gen_func example = compiler.getFunction("example"); + std::cout << "Result: " << example(3.0, 4.0) << std::endl; + return 0; } diff --git a/example/cpp/impala_file/example.impala b/example/cpp/impala_file/example.impala index e55bae5..0aff28b 100644 --- a/example/cpp/impala_file/example.impala +++ b/example/cpp/impala_file/example.impala @@ -1,3 +1,3 @@ example(x,y){ - return x*y; + return pow(x,y); } diff --git a/example/cpp/root b/example/cpp/root new file mode 120000 index 0000000..c25bddb --- /dev/null +++ b/example/cpp/root @@ -0,0 +1 @@ +../.. \ No newline at end of file diff --git a/example/f90/CMakeLists.txt b/example/f90/CMakeLists.txt new file mode 100644 index 0000000..aa09cc0 --- /dev/null +++ b/example/f90/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 2.6) +project(impala-f90) +enable_language (Fortran) + +add_subdirectory(${PROJECT_SOURCE_DIR}/root) + +add_executable(${CMAKE_PROJECT_NAME} ${PROJECT_SOURCE_DIR}/example.F90) +target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/root/include) +target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE -ffree-line-length-512) +target_link_libraries(${CMAKE_PROJECT_NAME} impalajit-static) + + +file(COPY ${PROJECT_SOURCE_DIR}/example.conf DESTINATION .) +file(COPY ${PROJECT_SOURCE_DIR}/impala_file DESTINATION .) \ No newline at end of file diff --git a/example/f90/root b/example/f90/root new file mode 120000 index 0000000..c25bddb --- /dev/null +++ b/example/f90/root @@ -0,0 +1 @@ +../.. \ No newline at end of file diff --git a/impalajit.cc b/impalajit.cc index 55d0cee..ae97dd3 100644 --- a/impalajit.cc +++ b/impalajit.cc @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -67,20 +68,30 @@ void impalajit::Compiler::loadFunctionDefinitionsFromInputFiles(std::string _con start = end + 1; } - for(std::vector::iterator it = functionFiles.begin(); it != functionFiles.end(); ++it) { - std::ifstream in((*it).c_str()); + for (auto& file: functionFiles) { + std::ifstream in(file.c_str()); functionDefinitions.push_back(std::string((std::istreambuf_iterator(in)), (std::istreambuf_iterator()))); } } -void impalajit::Compiler::compile(){ - for(std::vector::iterator it = functionDefinitions.begin(); it != functionDefinitions.end(); ++it) { - std::map parsedFunctions = driver.parse_string((*it)); - functionMap.insert(parsedFunctions.begin(), parsedFunctions.end()); - parameterCountMap.insert(std::make_pair(parsedFunctions.begin()->first, driver.getParameterCount())); - driver.deleteFunctionContext(); - } +void impalajit::Compiler::compile(Options options) { + assert(options.isDoublePrecision && "impala: single precision support has not been fully implemented. Please, use double precision"); + + auto& jit = impala::engine::Jit::getJit(); + auto currentModule = jit.createModule(options.isDoublePrecision); + std::vector functionSignature; + for(auto& definition: functionDefinitions) { + functionSignature.emplace_back(driver.generateLLVMFunction(definition, *currentModule, options)); + driver.deleteFunctionContext(); + } + jit.addModule(currentModule, !options.debug); + + for (auto& signature: functionSignature) { + auto function = reinterpret_cast(jit.lookup(signature.first).getAddress()); + functionMap[signature.first] = function; + parameterCountMap[signature.first] = signature.second; + } } dasm_gen_func impalajit::Compiler::getFunction(std::string functionName) { @@ -97,7 +108,7 @@ unsigned int impalajit::Compiler::getParameterCount(std::string functionName) { return parameterCountMap.at(functionName); } -void impalajit::Compiler::close(){ +void impalajit::Compiler::close() { driver.~Driver(); } diff --git a/include/impalajit.f90 b/include/impalajit.f90 index 96fd972..127f5c5 100644 --- a/include/impalajit.f90 +++ b/include/impalajit.f90 @@ -42,7 +42,6 @@ function impalajit_compiler_get_parameter_count_c( handle, function_name ) bind( use, intrinsic :: iso_c_binding type( c_ptr ), value, intent(in) :: handle character( kind=c_char ), dimension(*), intent(in) :: function_name - type( c_int ) :: impalajit_compiler_get_parameter_count_c end function impalajit_compiler_get_parameter_count_c subroutine impalajit_compiler_close( handle ) bind( c, name="impalajit_compiler_close" ) diff --git a/include/impalajit.hh b/include/impalajit.hh index 2bc3d7a..a66e347 100644 --- a/include/impalajit.hh +++ b/include/impalajit.hh @@ -34,24 +34,24 @@ namespace impalajit{ class Compiler; } -class impalajit::Compiler{ -private: - std::vector functionDefinitions; - std::map functionMap; - std::map parameterCountMap; - - void loadFunctionDefinitionsFromInputFiles(std::string _configPath); +class impalajit::Compiler { public: - Compiler(std::string _configFilePath); Compiler(std::vector _functionDefinitions); Compiler(); - void compile(); + void compile(Options options = Options()); dasm_gen_func getFunction(std::string functionName); unsigned int getParameterCount(std::string functionName); void close(); + + +private: + std::vector functionDefinitions; + std::map functionMap; + std::map parameterCountMap; + void loadFunctionDefinitionsFromInputFiles(std::string _configPath); }; typedef impalajit::Compiler impalajit_compiler; diff --git a/include/impalajit/types.hh b/include/impalajit/types.hh index d5ce96a..d284e0b 100644 --- a/include/impalajit/types.hh +++ b/include/impalajit/types.hh @@ -22,4 +22,15 @@ typedef double (*dasm_gen_func)(...); +namespace impalajit { +struct Options { + Options() : debug(false), printAST(false), printIR(false), isDoublePrecision(true), weakLinkage(true) {} + bool debug; + bool printAST; + bool printIR; + bool isDoublePrecision; + bool weakLinkage; +}; +} + #endif //IMPALAJIT_DASM_GEN_FUNCTION_H diff --git a/share/ImpalaJITConfig.cmake.in b/share/ImpalaJITConfig.cmake.in new file mode 100644 index 0000000..7b9f9f8 --- /dev/null +++ b/share/ImpalaJITConfig.cmake.in @@ -0,0 +1,6 @@ +# - Config file for the ImpalaJIT package +# - Using imported targets + +get_filename_component(IMPALAJIT-LLVM_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +message(STATUS "Found ImpalaJIT-LLVM: ${IMPALAJIT-LLVM_DIR} (version ${ImpalaJIT-LLVM_VERSION})") +include("${IMPALAJIT-LLVM_DIR}/ImpalaJIT-LLVMTargets.cmake") diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 60bdeb2..b59d288 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,50 +1,24 @@ -# Copyright 2017 Manuel Fasching -# Distributed under the MIT License -# -# 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 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. - cmake_minimum_required(VERSION 2.6) -link_directories(${CMAKE_BINARY_DIR}) -include_directories(${CMAKE_SOURCE_DIR}/include) - -# Add test executable -function( add_test_executable name ) - set( sourceFiles - ${name}.cc ) +find_package(GTest REQUIRED) - add_executable( test_${name}.o ${sourceFiles} ) - add_test(${name} test_${name}.o) +include(CTest) - # Link with impalajit - target_link_libraries( test_${name}.o impalajit) -endfunction( add_test_executable ) +add_executable(basic_tests ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/basic.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/parameter_count.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/simple_conditionals.cpp) +target_include_directories(basic_tests PRIVATE ${GTEST_INCLUDE_DIRS} ../include) +target_link_libraries(basic_tests PRIVATE impalajit ${GTEST_LIBRARIES}) -include_directories(include) +add_executable(advanced_tests ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/complex_conditionals.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/many_ifs.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/multiple_functions.cpp) +target_include_directories(advanced_tests PRIVATE ${GTEST_INCLUDE_DIRS} ../include) +target_link_libraries(advanced_tests PRIVATE impalajit ${GTEST_LIBRARIES}) -add_test_executable(conditionals_eq) -add_test_executable(conditionals_lt) -add_test_executable(conditionals_gt) -add_test_executable(conditionals_neq) -add_test_executable(conditionals_lte) -add_test_executable(conditionals_gte) -add_test_executable(conditionals_nested) -add_test_executable(conditionals_complex_1) -add_test_executable(conditionals_complex_2) -add_test_executable(multiple_functions) -add_test_executable(expressions_basic) -add_test_executable(assignments) -add_test_executable(many_if) -add_test_executable(parameter_count) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/impala_files DESTINATION .) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/conf DESTINATION .) +add_test(NAME basic_tests COMMAND basic_tests) +add_test(NAME advanced_tests COMMAND advanced_tests) diff --git a/tests/assignments.cc b/tests/assignments.cc deleted file mode 100644 index c9e966f..0000000 --- a/tests/assignments.cc +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright 2017 Manuel Fasching - * Distributed under the MIT License - * - * 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 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 "impalajit.hh" -#include -#include -#include -#include -#include -using namespace std; - - -double reference_function(double x, double y){ - double a = 3*x+5*y; - a = a + 1.0; - return a; -} - -int main(int argc, char** argv) { - - ofstream configFile; - configFile.open(CONFIG_FILE_PATH); - configFile << "../../tests/impala_files/assignment.impala;"; - configFile.close(); - - impalajit::Compiler compiler(CONFIG_FILE_PATH); - compiler.compile(); - dasm_gen_func function = compiler.getFunction("assignment"); - compiler.close(); - - assert(double_equals(function(45.3, 43.6), reference_function(45.3, 43.6))); - assert(double_equals(function(-23.3, 456.6), reference_function(-23.3, 456.6))); - - return 0; -} \ No newline at end of file diff --git a/tests/basic.cpp b/tests/basic.cpp new file mode 100644 index 0000000..9606c5e --- /dev/null +++ b/tests/basic.cpp @@ -0,0 +1,55 @@ +#include "definitions.h" +#include "impalajit.hh" +#include "gtest/gtest.h" +#include +#include + +namespace impala { +namespace tests { +namespace assignment { +double reference_function(double x, double y) { + double a = 3 * x + 5 * y; + a = a + 1.0; + return a; +} +} // namespace assignment + +namespace math { +double reference_function(double x, double y) { + return std::pow(x, y) + std::pow(std::sqrt(3.01 * x + (-y + 12.65)), 2.54) / 3.4331; +} +} // namespace math +} // namespace tests +} // namespace impala + +TEST(Basic, Assignment) { + std::ofstream configFile; + configFile.open(CONFIG_FILE_PATH); + configFile << "./impala_files/assignment.impala;"; + configFile.close(); + + impalajit::Compiler compiler(CONFIG_FILE_PATH); + compiler.compile(); + dasm_gen_func function = compiler.getFunction("assignment"); + compiler.close(); + + using namespace impala::tests; + ASSERT_EQ(function(45.3, 43.6), assignment::reference_function(45.3, 43.6)); + ASSERT_EQ(function(-23.3, 456.6), assignment::reference_function(-23.3, 456.6)); +} + +TEST(Basic, Math) { + std::ofstream configFile; + configFile.open(CONFIG_FILE_PATH); + configFile << "./impala_files/math_expression.impala;"; + configFile.close(); + + impalajit::Compiler compiler(CONFIG_FILE_PATH); + compiler.compile(); + dasm_gen_func function = compiler.getFunction("math_expression"); + compiler.close(); + + using namespace impala::tests; + ASSERT_EQ(function(2.54, -4.21), math::reference_function(2.54, -4.21)); + ASSERT_EQ(function(212.421, -232.22), math::reference_function(212.421, -232.22)); +} \ No newline at end of file diff --git a/tests/complex_conditionals.cpp b/tests/complex_conditionals.cpp new file mode 100644 index 0000000..d8da796 --- /dev/null +++ b/tests/complex_conditionals.cpp @@ -0,0 +1,80 @@ +#include "definitions.h" +#include "impalajit.hh" +#include "gtest/gtest.h" +#include + +TEST(ComplexConditions, Version1) { + + std::ofstream configFile; + configFile.open(CONFIG_FILE_PATH); + configFile << "./impala_files/conditional_complex_1.impala;"; + configFile.close(); + + impalajit::Compiler compiler(CONFIG_FILE_PATH); + compiler.compile(); + dasm_gen_func function = compiler.getFunction("complex_1"); + compiler.close(); + + ASSERT_EQ(function(1.0, 1.0, 1.0, 1.0), 1.0); + ASSERT_EQ(function(1.0, 1.0, 1.0, 0.0), 1.0); + ASSERT_EQ(function(1.0, 1.0, 0.0, 1.0), 1.0); + ASSERT_EQ(function(1.0, 1.0, 0.0, 0.0), 1.0); + ASSERT_EQ(function(1.0, 0.0, 1.0, 1.0), 1.0); + ASSERT_EQ(function(1.0, 0.0, 1.0, 0.0), 2.0); + ASSERT_EQ(function(1.0, 0.0, 0.0, 1.0), 2.0); + ASSERT_EQ(function(1.0, 0.0, 0.0, 0.0), 2.0); + ASSERT_EQ(function(0.0, 1.0, 1.0, 1.0), 2.0); + ASSERT_EQ(function(0.0, 1.0, 1.0, 0.0), 2.0); + ASSERT_EQ(function(0.0, 1.0, 0.0, 1.0), 2.0); + ASSERT_EQ(function(0.0, 1.0, 0.0, 0.0), 2.0); + ASSERT_EQ(function(0.0, 0.0, 1.0, 1.0), 2.0); + ASSERT_EQ(function(0.0, 0.0, 1.0, 0.0), 2.0); + ASSERT_EQ(function(0.0, 0.0, 0.0, 1.0), 2.0); + ASSERT_EQ(function(0.0, 0.0, 0.0, 0.0), 2.0); +} + +TEST(ComplexConditions, Version2) { + std::ofstream configFile; + configFile.open(CONFIG_FILE_PATH); + configFile << "./impala_files/conditional_complex_2.impala;"; + configFile.close(); + + impalajit::Compiler compiler(CONFIG_FILE_PATH); + compiler.compile(); + dasm_gen_func function = compiler.getFunction("complex_2"); + compiler.close(); + + ASSERT_EQ(function(1.0, 1.0, 1.0, 1.0), 2.0); + ASSERT_EQ(function(1.0, 1.0, 1.0, 0.0), 2.0); + ASSERT_EQ(function(1.0, 1.0, 0.0, 1.0), 2.0); + ASSERT_EQ(function(1.0, 1.0, 0.0, 0.0), 2.0); + ASSERT_EQ(function(1.0, 0.0, 1.0, 1.0), 2.0); + ASSERT_EQ(function(1.0, 0.0, 1.0, 0.0), 2.0); + ASSERT_EQ(function(1.0, 0.0, 0.0, 1.0), 2.0); + ASSERT_EQ(function(1.0, 0.0, 0.0, 0.0), 2.0); + ASSERT_EQ(function(0.0, 1.0, 1.0, 1.0), 1.0); + ASSERT_EQ(function(0.0, 1.0, 1.0, 0.0), 2.0); + ASSERT_EQ(function(0.0, 1.0, 0.0, 1.0), 1.0); + ASSERT_EQ(function(0.0, 1.0, 0.0, 0.0), 2.0); + ASSERT_EQ(function(0.0, 0.0, 1.0, 1.0), 1.0); + ASSERT_EQ(function(0.0, 0.0, 1.0, 0.0), 2.0); + ASSERT_EQ(function(0.0, 0.0, 0.0, 1.0), 2.0); + ASSERT_EQ(function(0.0, 0.0, 0.0, 0.0), 2.0); +} + +TEST(ComplexConditions, NestedContions) { + std::ofstream configFile; + configFile.open(CONFIG_FILE_PATH); + configFile << "./impala_files/conditional_nested.impala;"; + configFile.close(); + + impalajit::Compiler compiler(CONFIG_FILE_PATH); + compiler.compile(); + dasm_gen_func function = compiler.getFunction("nested"); + compiler.close(); + + ASSERT_EQ(function(1.0, 1.0, 1.0, 1.0), 4.0); + ASSERT_EQ(function(1.0, 1.0, 1.0, 0.0), 3.0); + ASSERT_EQ(function(1.0, 0.0, 1.0, 1.0), 2.0); + ASSERT_EQ(function(1.0, 0.0, 1.0, 0.0), 1.0); +} \ No newline at end of file diff --git a/tests/conditionals_complex_1.cc b/tests/conditionals_complex_1.cc deleted file mode 100644 index b229a74..0000000 --- a/tests/conditionals_complex_1.cc +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright 2017 Manuel Fasching - * Distributed under the MIT License - * - * 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 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 "impalajit.hh" -#include -#include -#include -#include - -using namespace std; - -int main(int argc, char** argv) { - - ofstream configFile; - configFile.open(CONFIG_FILE_PATH); - configFile << "../../tests/impala_files/conditional_complex_1.impala;"; - configFile.close(); - - impalajit::Compiler compiler(CONFIG_FILE_PATH); - compiler.compile(); - dasm_gen_func function = compiler.getFunction("complex_1"); - compiler.close(); - - assert(function(1.0, 1.0, 1.0, 1.0) == 1.0); - assert(function(1.0, 1.0, 1.0, 0.0) == 1.0); - assert(function(1.0, 1.0, 0.0, 1.0) == 1.0); - assert(function(1.0, 1.0, 0.0, 0.0) == 1.0); - assert(function(1.0, 0.0, 1.0, 1.0) == 1.0); - assert(function(1.0, 0.0, 1.0, 0.0) == 2.0); - assert(function(1.0, 0.0, 0.0, 1.0) == 2.0); - assert(function(1.0, 0.0, 0.0, 0.0) == 2.0); - assert(function(0.0, 1.0, 1.0, 1.0) == 2.0); - assert(function(0.0, 1.0, 1.0, 0.0) == 2.0); - assert(function(0.0, 1.0, 0.0, 1.0) == 2.0); - assert(function(0.0, 1.0, 0.0, 0.0) == 2.0); - assert(function(0.0, 0.0, 1.0, 1.0) == 2.0); - assert(function(0.0, 0.0, 1.0, 0.0) == 2.0); - assert(function(0.0, 0.0, 0.0, 1.0) == 2.0); - assert(function(0.0, 0.0, 0.0, 0.0) == 2.0); - - return 0; -} \ No newline at end of file diff --git a/tests/conditionals_complex_2.cc b/tests/conditionals_complex_2.cc deleted file mode 100644 index 53d13f3..0000000 --- a/tests/conditionals_complex_2.cc +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright 2017 Manuel Fasching - * Distributed under the MIT License - * - * 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 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 "impalajit.hh" -#include -#include -#include -#include - -using namespace std; - -int main(int argc, char** argv) { - - ofstream configFile; - configFile.open(CONFIG_FILE_PATH); - configFile << "../../tests/impala_files/conditional_complex_2.impala;"; - configFile.close(); - - impalajit::Compiler compiler(CONFIG_FILE_PATH); - compiler.compile(); - dasm_gen_func function = compiler.getFunction("complex_2"); - compiler.close(); - - assert(function(1.0, 1.0, 1.0, 1.0) == 2.0); - assert(function(1.0, 1.0, 1.0, 0.0) == 2.0); - assert(function(1.0, 1.0, 0.0, 1.0) == 2.0); - assert(function(1.0, 1.0, 0.0, 0.0) == 2.0); - assert(function(1.0, 0.0, 1.0, 1.0) == 2.0); - assert(function(1.0, 0.0, 1.0, 0.0) == 2.0); - assert(function(1.0, 0.0, 0.0, 1.0) == 2.0); - assert(function(1.0, 0.0, 0.0, 0.0) == 2.0); - assert(function(0.0, 1.0, 1.0, 1.0) == 1.0); - assert(function(0.0, 1.0, 1.0, 0.0) == 2.0); - assert(function(0.0, 1.0, 0.0, 1.0) == 1.0); - assert(function(0.0, 1.0, 0.0, 0.0) == 2.0); - assert(function(0.0, 0.0, 1.0, 1.0) == 1.0); - assert(function(0.0, 0.0, 1.0, 0.0) == 2.0); - assert(function(0.0, 0.0, 0.0, 1.0) == 2.0); - assert(function(0.0, 0.0, 0.0, 0.0) == 2.0); - - return 0; -} \ No newline at end of file diff --git a/tests/conditionals_eq.cc b/tests/conditionals_eq.cc deleted file mode 100644 index 23235b4..0000000 --- a/tests/conditionals_eq.cc +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright 2017 Manuel Fasching - * Distributed under the MIT License - * - * 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 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 "impalajit.hh" -#include -#include -#include -#include - -using namespace std; - -int main(int argc, char** argv) { - - ofstream configFile; - configFile.open(CONFIG_FILE_PATH); - configFile << "../../tests/impala_files/conditional_eq.impala;"; - configFile.close(); - - impalajit::Compiler compiler(CONFIG_FILE_PATH); - compiler.compile(); - dasm_gen_func function = compiler.getFunction("eq"); - compiler.close(); - - assert(function(1.0,1.0) == 1.0); - assert(function(1.0,0.0) == 0.0); - - return 0; -} \ No newline at end of file diff --git a/tests/conditionals_gt.cc b/tests/conditionals_gt.cc deleted file mode 100644 index 6517a2e..0000000 --- a/tests/conditionals_gt.cc +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright 2017 Manuel Fasching - * Distributed under the MIT License - * - * 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 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 "impalajit.hh" -#include -#include -#include -#include -using namespace std; - -int main(int argc, char** argv) { - - ofstream configFile; - configFile.open(CONFIG_FILE_PATH); - configFile << "../../tests/impala_files/conditional_gt.impala;"; - configFile.close(); - - impalajit::Compiler compiler(CONFIG_FILE_PATH); - compiler.compile(); - dasm_gen_func function = compiler.getFunction("gt"); - compiler.close(); - - assert(function(1.0, 0.0) == 1.0); - assert(function(0.0, 1.0) == 0.0); - assert(function(0.0, 0.0) == 0.0); - return 0; -} \ No newline at end of file diff --git a/tests/conditionals_gte.cc b/tests/conditionals_gte.cc deleted file mode 100644 index 1ee2c54..0000000 --- a/tests/conditionals_gte.cc +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright 2017 Manuel Fasching - * Distributed under the MIT License - * - * 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 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 "impalajit.hh" -#include -#include -#include -#include -using namespace std; - -int main(int argc, char** argv) { - - ofstream configFile; - configFile.open(CONFIG_FILE_PATH); - configFile << "../../tests/impala_files/conditional_gte.impala;"; - configFile.close(); - - impalajit::Compiler compiler(CONFIG_FILE_PATH); - compiler.compile(); - dasm_gen_func function = compiler.getFunction("gte"); - compiler.close(); - - assert(function(2.0, 1.0) == 1.0); - assert(function(1.0, 1.0) == 1.0); - assert(function(0.0, 1.0) == 0.0); - return 0; -} \ No newline at end of file diff --git a/tests/conditionals_lt.cc b/tests/conditionals_lt.cc deleted file mode 100644 index e371485..0000000 --- a/tests/conditionals_lt.cc +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright 2017 Manuel Fasching - * Distributed under the MIT License - * - * 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 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 "impalajit.hh" -#include -#include -#include -#include -using namespace std; - -int main(int argc, char** argv) { - - ofstream configFile; - configFile.open(CONFIG_FILE_PATH); - configFile << "../../tests/impala_files/conditional_lt.impala;"; - configFile.close(); - - impalajit::Compiler compiler(CONFIG_FILE_PATH); - compiler.compile(); - dasm_gen_func function = compiler.getFunction("lt"); - compiler.close(); - - assert(function(1.0, 0.0) == 0.0); - assert(function(0.0, 1.0) == 1.0); - assert(function(0.0, 0.0) == 0.0); - - return 0; -} \ No newline at end of file diff --git a/tests/conditionals_lte.cc b/tests/conditionals_lte.cc deleted file mode 100644 index 2296695..0000000 --- a/tests/conditionals_lte.cc +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright 2017 Manuel Fasching - * Distributed under the MIT License - * - * 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 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 "impalajit.hh" -#include -#include -#include -#include -using namespace std; - -int main(int argc, char** argv) { - - ofstream configFile; - configFile.open(CONFIG_FILE_PATH); - configFile << "../../tests/impala_files/conditional_lte.impala;"; - configFile.close(); - - impalajit::Compiler compiler(CONFIG_FILE_PATH); - compiler.compile(); - dasm_gen_func function = compiler.getFunction("lte"); - compiler.close(); - - assert(function(2.0, 1.0) == 0.0); - assert(function(1.0, 1.0) == 1.0); - assert(function(0.0, 1.0) == 1.0); - return 0; -} \ No newline at end of file diff --git a/tests/conditionals_neq.cc b/tests/conditionals_neq.cc deleted file mode 100644 index c0c4925..0000000 --- a/tests/conditionals_neq.cc +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright 2017 Manuel Fasching - * Distributed under the MIT License - * - * 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 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 "impalajit.hh" -#include -#include -#include -#include -#include -using namespace std; - -int main(int argc, char** argv) { - - ofstream configFile; - configFile.open(CONFIG_FILE_PATH); - configFile << "../../tests/impala_files/conditional_neq.impala;"; - configFile.close(); - - impalajit::Compiler compiler(CONFIG_FILE_PATH); - compiler.compile(); - dasm_gen_func function = compiler.getFunction("neq"); - compiler.close(); - - assert(function(2.0, 1.0) == 1.0); - assert(function(1.0, 1.0) == 0.0); - assert(function(0.0, 1.0) == 1.0); - return 0; -} \ No newline at end of file diff --git a/tests/conditionals_nested.cc b/tests/conditionals_nested.cc deleted file mode 100644 index ab16e4d..0000000 --- a/tests/conditionals_nested.cc +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright 2017 Manuel Fasching - * Distributed under the MIT License - * - * 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 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 "impalajit.hh" -#include -#include -#include -#include -using namespace std; - -int main(int argc, char** argv) { - - ofstream configFile; - configFile.open(CONFIG_FILE_PATH); - configFile << "../../tests/impala_files/conditional_nested.impala;"; - configFile.close(); - - impalajit::Compiler compiler(CONFIG_FILE_PATH); - compiler.compile(); - dasm_gen_func function = compiler.getFunction("nested"); - compiler.close(); - - assert(function(1.0, 1.0, 1.0, 1.0) == 4.0); - assert(function(1.0, 1.0, 1.0, 0.0) == 3.0); - assert(function(1.0, 0.0, 1.0, 1.0) == 2.0); - assert(function(1.0, 0.0, 1.0, 0.0) == 1.0); - return 0; -} \ No newline at end of file diff --git a/tests/definitions.h b/tests/definitions.h new file mode 100644 index 0000000..b2d9ba3 --- /dev/null +++ b/tests/definitions.h @@ -0,0 +1,6 @@ +#ifndef IMPALA_CPP_DEFINITIONS_H +#define IMPALA_CPP_DEFINITIONS_H + +#define CONFIG_FILE_PATH "./conf/impala.conf" + +#endif // IMPALA_CPP_DEFINITIONS_H diff --git a/tests/expressions_basic.cc b/tests/expressions_basic.cc deleted file mode 100644 index 266bc7a..0000000 --- a/tests/expressions_basic.cc +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright 2017 Manuel Fasching - * Distributed under the MIT License - * - * 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 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 "impalajit.hh" -#include -#include -#include -#include -#include -using namespace std; - - -double reference_function(double x, double y){ - return pow(x, y)+pow(sqrt(3.01*x+(-y+12.65)), 2.54)/3.4331; -} - -int main(int argc, char** argv) { - - ofstream configFile; - configFile.open(CONFIG_FILE_PATH); - configFile << "../../tests/impala_files/expression_basic.impala;"; - configFile.close(); - - impalajit::Compiler compiler(CONFIG_FILE_PATH); - - compiler.compile(); - - dasm_gen_func function = compiler.getFunction("expression_basic"); - - compiler.close(); - - assert(double_equals(function(2.54, -4.21), reference_function(2.54, -4.21))); - assert(double_equals(function(212.421, -232.22), reference_function(212.421, -232.22))); - return 0; -} - diff --git a/tests/impala_files/assignment.impala b/tests/impala_files/assignment.impala index faafd8f..d4572e4 100644 --- a/tests/impala_files/assignment.impala +++ b/tests/impala_files/assignment.impala @@ -2,4 +2,4 @@ assignment(x,y){ a = 3*x+5*y; a = a + 1; return a; -} \ No newline at end of file +} diff --git a/tests/impala_files/four_params.impala b/tests/impala_files/four_params.impala new file mode 100644 index 0000000..782af79 --- /dev/null +++ b/tests/impala_files/four_params.impala @@ -0,0 +1,10 @@ +four_params(a, b, c, d) { + var1 = a + b; + if (c > d) { + var1 = var1 + 100; + } + else { + var1 = var1 + c / d; + } + return var1; +} \ No newline at end of file diff --git a/tests/impala_files/many_if.impala b/tests/impala_files/many_if.impala index 1c9a202..3f91e17 100644 --- a/tests/impala_files/many_if.impala +++ b/tests/impala_files/many_if.impala @@ -63,4 +63,5 @@ many_if(z, i){ if(i==3){ return 67122000000; } -} + return 0; +} \ No newline at end of file diff --git a/tests/impala_files/expression_basic.impala b/tests/impala_files/math_expression.impala similarity index 73% rename from tests/impala_files/expression_basic.impala rename to tests/impala_files/math_expression.impala index 466c865..cd3a438 100644 --- a/tests/impala_files/expression_basic.impala +++ b/tests/impala_files/math_expression.impala @@ -1,3 +1,3 @@ -expression_basic(x,y) { +math_expression(x,y) { return pow(x, y)+pow(sqrt(3.01*x+(-y+12.65)), 2.54)/3.4331; } \ No newline at end of file diff --git a/tests/impala_files/seven_params.impala b/tests/impala_files/seven_params.impala new file mode 100644 index 0000000..8d8e1bf --- /dev/null +++ b/tests/impala_files/seven_params.impala @@ -0,0 +1,5 @@ +seven_params(a, b, c, d, e, f, g) { + var1 = a + b - c; + var2 = d * e + f / g; + return pow(var1, var2); +} \ No newline at end of file diff --git a/tests/include/double_comparison.hh b/tests/include/double_comparison.hh deleted file mode 100644 index 20284de..0000000 --- a/tests/include/double_comparison.hh +++ /dev/null @@ -1,23 +0,0 @@ -// -// Created by manuel on 03.02.17. -// - -#ifndef IMPALAJIT_DOUBLE_COMPARISON_HH -#define IMPALAJIT_DOUBLE_COMPARISON_HH -#ifdef __INTEL_COMPILER -#include -#else -#include -#endif -bool double_equals(double a, double b, double epsilon = pow(10, -12)) -{ - if(a +#include -#define CONFIG_FILE_PATH "../../tests/conf/impala.conf" +int main() { + impalajit::Options options; + options.printIR = true; + options.printAST = true; -#endif //IMPALAJIT_DEFINES_HH + impalajit::Compiler compiler("example.conf"); + + compiler.compile(options); + dasm_gen_func example = compiler.getFunction("example"); + std::cout << "Result: " << example(3.0, 4.0) << std::endl; + return 0; +} diff --git a/tests/install_test/example.conf b/tests/install_test/example.conf new file mode 100644 index 0000000..3e4dd8e --- /dev/null +++ b/tests/install_test/example.conf @@ -0,0 +1 @@ +impala_file/example.impala; \ No newline at end of file diff --git a/tests/install_test/impala_file/example.impala b/tests/install_test/impala_file/example.impala new file mode 100644 index 0000000..0aff28b --- /dev/null +++ b/tests/install_test/impala_file/example.impala @@ -0,0 +1,3 @@ +example(x,y){ + return pow(x,y); +} diff --git a/tests/main.cpp b/tests/main.cpp new file mode 100644 index 0000000..1659be8 --- /dev/null +++ b/tests/main.cpp @@ -0,0 +1,6 @@ +#include "gtest/gtest.h" + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/tests/many_if.cc b/tests/many_if.cc deleted file mode 100644 index f1fd254..0000000 --- a/tests/many_if.cc +++ /dev/null @@ -1,114 +0,0 @@ -/** - * Copyright 2017 Manuel Fasching - * Distributed under the MIT License - * - * 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 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 "impalajit.hh" -#include -#include -#include -#include -#include -using namespace std; - - -double reference_function(double z, double i){ - if(z < 10000.0 && z >= 500.0) { - if(i==1.0){ - return 2100.0; - } - if(i==2.0){ - return 2100000000.0; - } - if(i==3.0){ - return 3381000000.0; - } - } - if(z < -500.0 && z >= -1500.0) { - if(i==1.0){ - return 2400.0; - } - if(i==2.0){ - return 9600000000.0; - } - if(i==3.0){ - return 19200000000.0; - } - } - if(z < -1500.0 && z >= -4000.0) { - if(i==1.0){ - return 2700.0; - } - if(i==2.0){ - return 27648000000.0; - } - if(i==3.0){ - return 26379000000.0; - } - } - if(z < -4000.0 && z >= -270000.0) { - if(i==1.0){ - return 2800.0; - } - if(i==2.0){ - return 36288000000.0; - } - if(i==3.0){ - return 38556000000.0; - } - } - if(z < -270000.0 && z >= -400000.0) { - if(i==1.0){ - return 2900.0; - } - if(i==2.0){ - return 44109000000.0; - } - if(i==3.0){ - return 45878000000.0; - } - } - if(i==1.0){ - return 3300.0; - } - if(i==2.0){ - return 66825000000.0; - } - if(i==3.0){ - return 67122000000.0; - } -} - -int main(int argc, char** argv) { - - ofstream configFile; - configFile.open(CONFIG_FILE_PATH); - configFile << "../../tests/impala_files/many_if.impala;"; - configFile.close(); - - impalajit::Compiler compiler(CONFIG_FILE_PATH); - compiler.compile(); - dasm_gen_func function = compiler.getFunction("many_if"); - compiler.close(); - for(int i=-500000; i< 500000; i++) { - assert(double_equals(function(static_cast(i), 1.0), reference_function(static_cast(i), 1.0))); - assert(double_equals(function(static_cast(i), 2.0), reference_function(static_cast(i), 2.0))); - assert(double_equals(function(static_cast(i), 3.0), reference_function(static_cast(i), 3.0))); - } - return 0; -} - diff --git a/tests/many_ifs.cpp b/tests/many_ifs.cpp new file mode 100644 index 0000000..7903e74 --- /dev/null +++ b/tests/many_ifs.cpp @@ -0,0 +1,98 @@ +#include "definitions.h" +#include "impalajit.hh" +#include "gtest/gtest.h" +#include +#include + +namespace impala { +namespace tests { +namespace many_conditions { +double reference_function(double z, double i) { + if (z < 10000.0 && z >= 500.0) { + if (i == 1.0) { + return 2100.0; + } + if (i == 2.0) { + return 2100000000.0; + } + if (i == 3.0) { + return 3381000000.0; + } + } + if (z < -500.0 && z >= -1500.0) { + if (i == 1.0) { + return 2400.0; + } + if (i == 2.0) { + return 9600000000.0; + } + if (i == 3.0) { + return 19200000000.0; + } + } + if (z < -1500.0 && z >= -4000.0) { + if (i == 1.0) { + return 2700.0; + } + if (i == 2.0) { + return 27648000000.0; + } + if (i == 3.0) { + return 26379000000.0; + } + } + if (z < -4000.0 && z >= -270000.0) { + if (i == 1.0) { + return 2800.0; + } + if (i == 2.0) { + return 36288000000.0; + } + if (i == 3.0) { + return 38556000000.0; + } + } + if (z < -270000.0 && z >= -400000.0) { + if (i == 1.0) { + return 2900.0; + } + if (i == 2.0) { + return 44109000000.0; + } + if (i == 3.0) { + return 45878000000.0; + } + } + if (i == 1.0) { + return 3300.0; + } + if (i == 2.0) { + return 66825000000.0; + } + if (i == 3.0) { + return 67122000000.0; + } + return std::numeric_limits::min(); +} +} // namespace many_conditions +} // namespace tests +} // namespace impala + +TEST(StressTest, ManyConditions) { + std::ofstream configFile; + configFile.open(CONFIG_FILE_PATH); + configFile << "./impala_files/many_if.impala;"; + configFile.close(); + + impalajit::Compiler compiler(CONFIG_FILE_PATH); + compiler.compile(); + dasm_gen_func function = compiler.getFunction("many_if"); + compiler.close(); + + using namespace impala::tests::many_conditions; + for (int i = -500000; i < 500000; i++) { + ASSERT_EQ(function(static_cast(i), 1.0), reference_function(static_cast(i), 1.0)); + ASSERT_EQ(function(static_cast(i), 2.0), reference_function(static_cast(i), 2.0)); + ASSERT_EQ(function(static_cast(i), 3.0), reference_function(static_cast(i), 3.0)); + } +} \ No newline at end of file diff --git a/tests/multiple_functions.cc b/tests/multiple_functions.cc deleted file mode 100644 index 5888d2a..0000000 --- a/tests/multiple_functions.cc +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Copyright 2017 Manuel Fasching - * Distributed under the MIT License - * - * 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 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 "impalajit.hh" -#include -#include -#include -#include -using namespace std; - -int main(int argc, char** argv) { - - ofstream configFile; - configFile.open(CONFIG_FILE_PATH); - configFile << "../../tests/impala_files/conditional_eq.impala;"; - configFile << "../../tests/impala_files/conditional_gt.impala;"; - configFile << "../../tests/impala_files/conditional_gte.impala;"; - configFile << "../../tests/impala_files/conditional_lt.impala;"; - configFile << "../../tests/impala_files/conditional_lte.impala;"; - configFile << "../../tests/impala_files/conditional_neq.impala;"; - configFile.close(); - - impalajit::Compiler compiler(CONFIG_FILE_PATH); - compiler.compile(); - - assert(compiler.getFunction("eq")(1.0,1.0) == 1.0); - assert(compiler.getFunction("eq")(1.0,0.0) == 0.0); - - assert(compiler.getFunction("gt")(1.0, 0.0) == 1.0); - assert(compiler.getFunction("gt")(0.0, 1.0) == 0.0); - assert(compiler.getFunction("gt")(0.0, 0.0) == 0.0); - - - assert(compiler.getFunction("gte")(2.0, 1.0) == 1.0); - assert(compiler.getFunction("gte")(1.0, 1.0) == 1.0); - assert(compiler.getFunction("gte")(0.0, 1.0) == 0.0); - - - assert(compiler.getFunction("lt")(1.0, 0.0) == 0.0); - assert(compiler.getFunction("lt")(0.0, 1.0) == 1.0); - assert(compiler.getFunction("lt")(0.0, 0.0) == 0.0); - - - assert(compiler.getFunction("lte")(2.0, 1.0) == 0.0); - assert(compiler.getFunction("lte")(1.0, 1.0) == 1.0); - assert(compiler.getFunction("lte")(0.0, 1.0) == 1.0); - - - assert(compiler.getFunction("neq")(2.0, 1.0) == 1.0); - assert(compiler.getFunction("neq")(1.0, 1.0) == 0.0); - assert(compiler.getFunction("neq")(0.0, 1.0) == 1.0); - - std::cout << compiler.getParameterCount("neq") << std::endl; - - compiler.close(); - return 0; -} \ No newline at end of file diff --git a/tests/multiple_functions.cpp b/tests/multiple_functions.cpp new file mode 100644 index 0000000..948a6d6 --- /dev/null +++ b/tests/multiple_functions.cpp @@ -0,0 +1,43 @@ +#include "definitions.h" +#include "impalajit.hh" +#include "gtest/gtest.h" +#include + +TEST(StressTest, MultipleFunctions) { + std::ofstream configFile; + configFile.open(CONFIG_FILE_PATH); + configFile << "./impala_files/conditional_eq.impala;"; + configFile << "./impala_files/conditional_gt.impala;"; + configFile << "./impala_files/conditional_gte.impala;"; + configFile << "./impala_files/conditional_lt.impala;"; + configFile << "./impala_files/conditional_lte.impala;"; + configFile << "./impala_files/conditional_neq.impala;"; + configFile.close(); + + impalajit::Compiler compiler(CONFIG_FILE_PATH); + compiler.compile(); + + ASSERT_EQ(compiler.getFunction("eq")(1.0, 1.0), 1.0); + ASSERT_EQ(compiler.getFunction("eq")(1.0, 0.0), 0.0); + + ASSERT_EQ(compiler.getFunction("gt")(1.0, 0.0), 1.0); + ASSERT_EQ(compiler.getFunction("gt")(0.0, 1.0), 0.0); + ASSERT_EQ(compiler.getFunction("gt")(0.0, 0.0), 0.0); + + ASSERT_EQ(compiler.getFunction("gte")(2.0, 1.0), 1.0); + ASSERT_EQ(compiler.getFunction("gte")(1.0, 1.0), 1.0); + ASSERT_EQ(compiler.getFunction("gte")(0.0, 1.0), 0.0); + + ASSERT_EQ(compiler.getFunction("lt")(1.0, 0.0), 0.0); + ASSERT_EQ(compiler.getFunction("lt")(0.0, 1.0), 1.0); + ASSERT_EQ(compiler.getFunction("lt")(0.0, 0.0), 0.0); + + ASSERT_EQ(compiler.getFunction("lte")(2.0, 1.0), 0.0); + ASSERT_EQ(compiler.getFunction("lte")(1.0, 1.0), 1.0); + ASSERT_EQ(compiler.getFunction("lte")(0.0, 1.0), 1.0); + + ASSERT_EQ(compiler.getFunction("neq")(2.0, 1.0), 1.0); + ASSERT_EQ(compiler.getFunction("neq")(1.0, 1.0), 0.0); + ASSERT_EQ(compiler.getFunction("neq")(0.0, 1.0), 1.0); + compiler.close(); +} \ No newline at end of file diff --git a/tests/parameter_count.cc b/tests/parameter_count.cc deleted file mode 100644 index b2bf2db..0000000 --- a/tests/parameter_count.cc +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright 2017 Manuel Fasching - * Distributed under the MIT License - * - * 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 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 "impalajit.hh" -#include -#include -#include -#include -using namespace std; - -int main(int argc, char** argv) { - - ofstream configFile; - configFile.open(CONFIG_FILE_PATH); - configFile << "../../tests/impala_files/conditional_eq.impala;"; - configFile << "../../tests/impala_files/conditional_nested.impala;"; - configFile.close(); - - impalajit::Compiler compiler(CONFIG_FILE_PATH); - compiler.compile(); - - assert(compiler.getParameterCount("eq")==2); - assert(compiler.getParameterCount("nested")==4); - - compiler.close(); - return 0; -} \ No newline at end of file diff --git a/tests/parameter_count.cpp b/tests/parameter_count.cpp new file mode 100644 index 0000000..0f68414 --- /dev/null +++ b/tests/parameter_count.cpp @@ -0,0 +1,20 @@ +#include "definitions.h" +#include "impalajit.hh" +#include "gtest/gtest.h" +#include + +TEST(FunctionParameters, Count) { + std::ofstream configFile; + configFile.open(CONFIG_FILE_PATH); + configFile << "./impala_files/four_params.impala;"; + configFile << "./impala_files/seven_params.impala;"; + configFile.close(); + + impalajit::Compiler compiler(CONFIG_FILE_PATH); + compiler.compile(); + + ASSERT_EQ(compiler.getParameterCount("four_params"), 4); + ASSERT_EQ(compiler.getParameterCount("seven_params"), 7); + + compiler.close(); +} \ No newline at end of file diff --git a/tests/simple_conditionals.cpp b/tests/simple_conditionals.cpp new file mode 100644 index 0000000..6dd345b --- /dev/null +++ b/tests/simple_conditionals.cpp @@ -0,0 +1,99 @@ +#include "definitions.h" +#include "impalajit.hh" +#include "gtest/gtest.h" +#include + +TEST(SimpleConditions, Equal) { + std::ofstream configFile; + configFile.open(CONFIG_FILE_PATH); + configFile << "./impala_files/conditional_eq.impala;"; + configFile.close(); + + impalajit::Compiler compiler(CONFIG_FILE_PATH); + compiler.compile(); + dasm_gen_func function = compiler.getFunction("eq"); + compiler.close(); + + ASSERT_EQ(function(1.0, 1.0), 1.0); + ASSERT_EQ(function(1.0, 0.0), 0.0); +} + +TEST(SimpleConditions, GreaterThan) { + std::ofstream configFile; + configFile.open(CONFIG_FILE_PATH); + configFile << "./impala_files/conditional_gt.impala;"; + configFile.close(); + + impalajit::Compiler compiler(CONFIG_FILE_PATH); + compiler.compile(); + dasm_gen_func function = compiler.getFunction("gt"); + compiler.close(); + + ASSERT_EQ(function(1.0, 0.0), 1.0); + ASSERT_EQ(function(0.0, 1.0), 0.0); + ASSERT_EQ(function(0.0, 0.0), 0.0); +} + +TEST(SimpleConditions, GreaterThanOrEqual) { + std::ofstream configFile; + configFile.open(CONFIG_FILE_PATH); + configFile << "./impala_files/conditional_gte.impala;"; + configFile.close(); + + impalajit::Compiler compiler(CONFIG_FILE_PATH); + compiler.compile(); + dasm_gen_func function = compiler.getFunction("gte"); + compiler.close(); + + ASSERT_EQ(function(2.0, 1.0), 1.0); + ASSERT_EQ(function(1.0, 1.0), 1.0); + ASSERT_EQ(function(0.0, 1.0), 0.0); +} + +TEST(SimpleConditions, LessThan) { + std::ofstream configFile; + configFile.open(CONFIG_FILE_PATH); + configFile << "./impala_files/conditional_lt.impala;"; + configFile.close(); + + impalajit::Compiler compiler(CONFIG_FILE_PATH); + compiler.compile(); + dasm_gen_func function = compiler.getFunction("lt"); + compiler.close(); + + ASSERT_EQ(function(1.0, 0.0), 0.0); + ASSERT_EQ(function(0.0, 1.0), 1.0); + ASSERT_EQ(function(0.0, 0.0), 0.0); +} + +TEST(SimpleConditions, LessThanOrEqual) { + std::ofstream configFile; + configFile.open(CONFIG_FILE_PATH); + configFile << "./impala_files/conditional_lte.impala;"; + configFile.close(); + + impalajit::Compiler compiler(CONFIG_FILE_PATH); + compiler.compile(); + dasm_gen_func function = compiler.getFunction("lte"); + compiler.close(); + + ASSERT_EQ(function(2.0, 1.0), 0.0); + ASSERT_EQ(function(1.0, 1.0), 1.0); + ASSERT_EQ(function(0.0, 1.0), 1.0); +} + +TEST(SimpleConditions, NotEqual) { + std::ofstream configFile; + configFile.open(CONFIG_FILE_PATH); + configFile << "./impala_files/conditional_neq.impala;"; + configFile.close(); + + impalajit::Compiler compiler(CONFIG_FILE_PATH); + compiler.compile(); + dasm_gen_func function = compiler.getFunction("neq"); + compiler.close(); + + ASSERT_EQ(function(2.0, 1.0), 1.0); + ASSERT_EQ(function(1.0, 1.0), 0.0); + ASSERT_EQ(function(0.0, 1.0), 1.0); +} \ No newline at end of file