From 0037f62ea81008428caed28876583aec0de3fa86 Mon Sep 17 00:00:00 2001 From: ravil Date: Tue, 1 Jun 2021 11:39:35 +0200 Subject: [PATCH 01/29] Added CMake for examples --- .gitignore | 1 + CMakeLists.txt | 5 ++--- example/c/CMakeLists.txt | 10 ++++++++++ example/c/root | 1 + example/cpp/CMakeLists.txt | 12 ++++++++++++ example/cpp/root | 1 + example/f90/CMakeLists.txt | 14 ++++++++++++++ example/f90/root | 1 + include/impalajit.f90 | 1 - 9 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 example/c/CMakeLists.txt create mode 120000 example/c/root create mode 100644 example/cpp/CMakeLists.txt create mode 120000 example/cpp/root create mode 100644 example/f90/CMakeLists.txt create mode 120000 example/f90/root diff --git a/.gitignore b/.gitignore index 8b402c2..583e1b4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ minilua build lib/* +cmake-build-* diff --git a/CMakeLists.txt b/CMakeLists.txt index ce0042e..9b79c5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,8 +35,7 @@ set(include_dirs compiler/frontend/include compiler/semantic_analysis/include compiler/code-gen/include - compiler/code-gen/assembly/include - ) + compiler/code-gen/assembly/include) include_directories(${include_dirs}) @@ -89,7 +88,7 @@ if( PKG_CONFIG_FOUND ) endif( PKG_CONFIG_FOUND ) if( SHARED_LIB ) - add_library( impalajit SHARED ${source_files}) + add_library( impalajit SHARED ${source_files} ) target_link_libraries( impalajit ${math_library} ) endif( SHARED_LIB ) 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..9b83695 --- /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-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/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/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" ) From 5224f0b54b73b95fc7e5116097bb9cc93c12395e Mon Sep 17 00:00:00 2001 From: ravil Date: Tue, 1 Jun 2021 20:43:57 +0200 Subject: [PATCH 02/29] Added LLVM jit engine --- CMakeLists.txt | 22 +++++-- compiler/code-gen/code_generator.cc | 13 ++++ compiler/code-gen/engine/engine.cpp | 57 ++++++++++++++++ compiler/code-gen/engine/engine.h | 66 +++++++++++++++++++ compiler/driver.cc | 2 +- compiler/include/nodes/assignment_nodes.h | 7 ++ compiler/include/nodes/boolean_nodes.h | 14 ++++ compiler/include/nodes/compare_nodes.h | 7 ++ compiler/include/nodes/conditional_nodes.h | 28 ++++++++ compiler/include/nodes/expression_nodes.h | 56 ++++++++++++++++ .../include/nodes/external_function_nodes.h | 14 ++++ compiler/include/nodes/node.h | 10 +++ compiler/include/nodes/return_nodes.h | 7 ++ .../semantic_analysis/semantic_analyzer.cc | 4 +- impalajit.cc | 10 +-- 15 files changed, 304 insertions(+), 13 deletions(-) create mode 100644 compiler/code-gen/engine/engine.cpp create mode 100644 compiler/code-gen/engine/engine.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b79c5a..15b8b5b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,7 @@ option( SHARED_LIB "Compile the shared library" OFF ) option( STATIC_LIB "Compile the static library" ON ) option( TESTS "Enable Tests" OFF ) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++98 -O3") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -O3") project(ImpalaJIT) @@ -56,7 +56,8 @@ set(source_files ${source_files} 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) + compiler/code-gen/assembly/assembly__sse_4_1.cc + compiler/code-gen/engine/engine.cpp) ##### pkg-config ##### find_package( PkgConfig ) @@ -87,15 +88,26 @@ if( PKG_CONFIG_FOUND ) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/impalajit.pc DESTINATION lib/pkgconfig ) endif( PKG_CONFIG_FOUND ) + +find_package(LLVM 10.0 REQUIRED CONFIG) +LLVM_MAP_COMPONENTS_TO_LIBNAMES(LLVM_LIBS core orcjit native) +message(STATUS "LLVM: ${LLVM_VERSION}") + + if( SHARED_LIB ) add_library( impalajit SHARED ${source_files} ) - target_link_libraries( impalajit ${math_library} ) + target_link_libraries( impalajit PRIVATE ${math_library} ${LLVM_LIBS} ) + target_include_directories( impalajit PRIVATE ${LLVM_INCLUDE_DIRS} ) + target_compile_definitions( impalajit PRIVATE ${LLVM_DEFINITIONS} ) endif( SHARED_LIB ) if( STATIC_LIB ) add_library( impalajit-static STATIC ${source_files} ) - set_target_properties( impalajit-static - PROPERTIES OUTPUT_NAME impalajit ) + set_target_properties( impalajit-static PROPERTIES OUTPUT_NAME impalajit ) + + target_link_libraries( impalajit-static PRIVATE ${math_library} ${LLVM_LIBS} ) + target_include_directories( impalajit-static PRIVATE ${LLVM_INCLUDE_DIRS} ) + target_compile_definitions( impalajit-static PRIVATE ${LLVM_DEFINITIONS} ) endif( STATIC_LIB ) # Tests diff --git a/compiler/code-gen/code_generator.cc b/compiler/code-gen/code_generator.cc index ef20106..cc604a8 100644 --- a/compiler/code-gen/code_generator.cc +++ b/compiler/code-gen/code_generator.cc @@ -17,6 +17,7 @@ * THE SOFTWARE. */ +#include "engine/engine.h" #include #include #include @@ -54,6 +55,18 @@ CodeGenerator::~CodeGenerator() dasm_gen_func CodeGenerator::generateCode(FunctionContext* &functionContext) { FunctionPtrMap::initialize_map(); + std::cout << "function name: " << functionContext->name << std::endl; + auto &jit = Jit::getJit(); + auto &dl = jit.getDataLayout(); + { + auto lock = jit.getLock(); + auto &context = jit.getContext(); + std::cout << "getIndexTypeSicd zeInBits: " << dl.getIndexTypeSizeInBits(llvm::Type::getVoidTy(context)) << std::endl; + } + + + functionContext->root->codegen(); + assembly.initialize(functionContext->parameters.size()); assembly.prologue(); diff --git a/compiler/code-gen/engine/engine.cpp b/compiler/code-gen/engine/engine.cpp new file mode 100644 index 0000000..6dcf99f --- /dev/null +++ b/compiler/code-gen/engine/engine.cpp @@ -0,0 +1,57 @@ +#include "engine.h" +#include + +#include "llvm/ExecutionEngine/Orc/LLJIT.h" + +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("cannot create jit machine builder"); + } + + auto expectedDataLayout = expectedJTMB->getDefaultDataLayoutForTarget(); + if (!expectedDataLayout) { + throw std::runtime_error("cannot detect data layout"); + } + + try { + auto memoryManager = []() { return std::make_unique(); }; + objectLayer = std::make_unique(ES, memoryManager); + auto compiler = std::make_unique(std::move(*expectedJTMB)); + dataLayout = std::make_unique(std::move(*expectedDataLayout)); + mangle = std::make_unique(ES, *dataLayout); + std::string dylibName{"jit_dylib"}; + ES.createJITDylib(dylibName); + jitDylib = ES.getJITDylibByName(dylibName); + 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) { + 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 + auto& m = *mangle; + llvm::Expected expected = ES.lookup({jitDylib}, (*mangle)(Name.str())); + if (!expected) { + llvm::errs() << expected.takeError() << '\n'; + } + return *expected; +} \ No newline at end of file diff --git a/compiler/code-gen/engine/engine.h b/compiler/code-gen/engine/engine.h new file mode 100644 index 0000000..f3a1f18 --- /dev/null +++ b/compiler/code-gen/engine/engine.h @@ -0,0 +1,66 @@ +#ifndef IMPALA_CPP_ENGINE_H +#define IMPALA_CPP_ENGINE_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/TargetSelect.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/RTDyldObjectLinkingLayer.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/ExecutionEngine/Orc/LLJIT.h" +#include +#include + +/* + * ExecutionSession - provides context for our running JIT’d code (including the string pool, + * global mutex, and error reporting facilities) + * + * RTDyldObjectLinkingLayer - can be used to add object files to our JIT + * + * IRCompileLayer - can be used to add LLVM Modules to our JIT (builds on the ObjectLayer) + * + * DataLayout and MangleAndInterner - used for symbol mangling + * + * LLVMContext - llvm core + * + * + * return std::make_unique() - builds a JIT memory manager + * for each module that is added + * + * ConcurrentIRCompiler - used the JITTargetMachineBuilder to build llvm TargetMachines + * + * JITDylib - A symbol table that supports asynchoronous symbol queries + * */ + +class Jit { +public: + 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); + + // looks up addresses for function and variable definitions added to the JIT based on their symbol names. + llvm::JITEvaluatedSymbol lookup(llvm::StringRef Name); + +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}; +}; + +#endif //IMPALA_CPP_ENGINE_H diff --git a/compiler/driver.cc b/compiler/driver.cc index 47c1e80..2ebaf65 100644 --- a/compiler/driver.cc +++ b/compiler/driver.cc @@ -65,7 +65,7 @@ std::map Driver::parse_string(const std::string &inpu void Driver::deleteFunctionContext(){ delete functionContext; - functionContext = NULL; + functionContext = nullptr; } void Driver::setFunctionContext(FunctionContext* _functionContext){ diff --git a/compiler/include/nodes/assignment_nodes.h b/compiler/include/nodes/assignment_nodes.h index 315ce5a..7451d1d 100644 --- a/compiler/include/nodes/assignment_nodes.h +++ b/compiler/include/nodes/assignment_nodes.h @@ -40,5 +40,12 @@ class AssignmentNode : public Node node->evaluate(); assembly.storeLocalVariable(); }*/ + + virtual void codegen() { + for (auto node: nodes) { + node->codegen(); + } + std::cout << "am root" << std::endl; + } }; #endif //IMPALAJIT_ASSIGNMENT_EXPRESSION_HH diff --git a/compiler/include/nodes/boolean_nodes.h b/compiler/include/nodes/boolean_nodes.h index 0bfbdb3..741b852 100644 --- a/compiler/include/nodes/boolean_nodes.h +++ b/compiler/include/nodes/boolean_nodes.h @@ -29,6 +29,13 @@ class BooleanAndNode : public Node { : Node(BOOLEAN_AND_JUNCTION) { } + + void codegen() override { + for (auto node: nodes) { + node->codegen(); + } + std::cout << "BooleanAndNode" << std::endl; + } }; @@ -39,6 +46,13 @@ class BooleanOrNode : public Node { : Node(BOOLEAN_OR_JUNCTION) { } + + void codegen() override { + for (auto node: nodes) { + node->codegen(); + } + std::cout << "BooleanOrNode" << std::endl; + } }; #endif //IMPALAJIT_BOOL_H diff --git a/compiler/include/nodes/compare_nodes.h b/compiler/include/nodes/compare_nodes.h index f06ce03..c6aef22 100644 --- a/compiler/include/nodes/compare_nodes.h +++ b/compiler/include/nodes/compare_nodes.h @@ -32,6 +32,13 @@ class CompareNode : public Node nodes.push_back(_right); nodes.push_back(_left); } + + void codegen() override { + for (auto node: nodes) { + node->codegen(); + } + std::cout << "CompareNode" << std::endl; + } }; diff --git a/compiler/include/nodes/conditional_nodes.h b/compiler/include/nodes/conditional_nodes.h index 94b8ada..57af2ed 100644 --- a/compiler/include/nodes/conditional_nodes.h +++ b/compiler/include/nodes/conditional_nodes.h @@ -31,6 +31,13 @@ class IfStmtNode : public Node nodes.push_back(_condition); nodes.push_back(_if_body); } + + void codegen() override { + for (auto node: nodes) { + node->codegen(); + } + std::cout << "IfStmtNode" << std::endl; + } }; class IfElseStmtNode : public Node @@ -44,6 +51,13 @@ class IfElseStmtNode : public Node nodes.push_back(_if_body); nodes.push_back(_else_body); } + + void codegen() override { + for (auto node: nodes) { + node->codegen(); + } + std::cout << "IfElseStmtNode" << std::endl; + } }; class IfBodyNode : public Node @@ -57,6 +71,13 @@ class IfBodyNode : public Node virtual ~IfBodyNode() { } + + void codegen() override { + for (auto node: nodes) { + node->codegen(); + } + std::cout << "IfBodyNode" << std::endl; + } }; class ElseBodyNode : public Node @@ -70,5 +91,12 @@ class ElseBodyNode : public Node virtual ~ElseBodyNode() { } + + void codegen() override { + for (auto node: nodes) { + node->codegen(); + } + std::cout << "ElseBodyNode" << std::endl; + } }; #endif //IMPALAJIT_COMPLEX_EXPRESSION_H diff --git a/compiler/include/nodes/expression_nodes.h b/compiler/include/nodes/expression_nodes.h index fb367d0..94d27d5 100644 --- a/compiler/include/nodes/expression_nodes.h +++ b/compiler/include/nodes/expression_nodes.h @@ -30,6 +30,13 @@ class ConstantNode : public Node : Node(CONSTANT), value(_value) { } + + void codegen() override { + for (auto node: nodes) { + node->codegen(); + } + std::cout << "ConstantNode" << std::endl; + } }; class VariableNode : public Node { @@ -39,6 +46,13 @@ class VariableNode : public Node { VariableNode(std::string &_name) : Node(VARIABLE), name(_name) { } + + void codegen() override { + for (auto node: nodes) { + node->codegen(); + } + std::cout << "VariableNode" << std::endl; + } }; class NegationNode : public Node @@ -49,6 +63,13 @@ class NegationNode : public Node { nodes.push_back(_node); } + + void codegen() override { + for (auto node: nodes) { + node->codegen(); + } + std::cout << "NegationNode" << std::endl; + } }; class AdditionNode : public Node @@ -60,6 +81,13 @@ class AdditionNode : public Node nodes.push_back(_left); nodes.push_back(_right); } + + void codegen() override { + for (auto node: nodes) { + node->codegen(); + } + std::cout << "AdditionNode" << std::endl; + } }; class SubtractionNode : public Node @@ -71,6 +99,13 @@ class SubtractionNode : public Node nodes.push_back(_left); nodes.push_back(_right); } + + void codegen() override { + for (auto node: nodes) { + node->codegen(); + } + std::cout << "SubtractionNode" << std::endl; + } }; class MultiplicationNode : public Node @@ -82,6 +117,13 @@ class MultiplicationNode : public Node nodes.push_back(_left); nodes.push_back(_right); } + + void codegen() override { + for (auto node: nodes) { + node->codegen(); + } + std::cout << "MultiplicationNode" << std::endl; + } }; class DivisionNode : public Node @@ -93,6 +135,13 @@ class DivisionNode : public Node nodes.push_back(_left); nodes.push_back(_right); } + + void codegen() override { + for (auto node: nodes) { + node->codegen(); + } + std::cout << "DivisionNode" << std::endl; + } }; class PowerNode : public Node @@ -104,6 +153,13 @@ class PowerNode : public Node nodes.push_back(_exponent); nodes.push_back(_base); } + + void codegen() override { + for (auto node: nodes) { + node->codegen(); + } + std::cout << "PowerNode" << std::endl; + } }; #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..3aa0c8e 100644 --- a/compiler/include/nodes/external_function_nodes.h +++ b/compiler/include/nodes/external_function_nodes.h @@ -39,6 +39,13 @@ class ExternalFunctionNode: public Node virtual ~ExternalFunctionNode() { } + + void codegen() override { + for (auto node: nodes) { + node->codegen(); + } + std::cout << "ExternalFunctionNode" << std::endl; + } }; class ExternalFunctionParametersNode : public Node @@ -52,6 +59,13 @@ class ExternalFunctionParametersNode : public Node virtual ~ExternalFunctionParametersNode() { } + + void codegen() override { + for (auto node: nodes) { + node->codegen(); + } + std::cout << "ExternalFunctionParametersNode" << std::endl; + } }; diff --git a/compiler/include/nodes/node.h b/compiler/include/nodes/node.h index 339f8df..0f3947b 100644 --- a/compiler/include/nodes/node.h +++ b/compiler/include/nodes/node.h @@ -22,6 +22,7 @@ #include #include +#include class Node { @@ -37,6 +38,8 @@ class Node { nodes.clear(); } + + virtual void codegen() = 0; }; class RootNode : public Node @@ -46,6 +49,13 @@ class RootNode : public Node : Node(ROOT) { } + + void codegen() override { + for (auto node: nodes) { + node->codegen(); + } + std::cout << "am root" << std::endl; + } }; #endif // EXPRESSION_H diff --git a/compiler/include/nodes/return_nodes.h b/compiler/include/nodes/return_nodes.h index fa22d0f..94918f3 100644 --- a/compiler/include/nodes/return_nodes.h +++ b/compiler/include/nodes/return_nodes.h @@ -30,5 +30,12 @@ class ReturnNode : public Node { nodes.push_back(_node); } + + void codegen() override { + for (auto node: nodes) { + node->codegen(); + } + std::cout << "am return" << std::endl; + } }; #endif //IMPALAJIT_RETURN_NODE_H diff --git a/compiler/semantic_analysis/semantic_analyzer.cc b/compiler/semantic_analysis/semantic_analyzer.cc index 91b26c3..4910385 100644 --- a/compiler/semantic_analysis/semantic_analyzer.cc +++ b/compiler/semantic_analysis/semantic_analyzer.cc @@ -84,8 +84,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/impalajit.cc b/impalajit.cc index 55d0cee..df62455 100644 --- a/impalajit.cc +++ b/impalajit.cc @@ -67,16 +67,16 @@ 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)); + for(auto& definition: functionDefinitions) { + auto parsedFunctions = driver.parse_string(definition); functionMap.insert(parsedFunctions.begin(), parsedFunctions.end()); parameterCountMap.insert(std::make_pair(parsedFunctions.begin()->first, driver.getParameterCount())); driver.deleteFunctionContext(); @@ -97,7 +97,7 @@ unsigned int impalajit::Compiler::getParameterCount(std::string functionName) { return parameterCountMap.at(functionName); } -void impalajit::Compiler::close(){ +void impalajit::Compiler::close() { driver.~Driver(); } From adfb6918d95956ac1259212cc51b6215597d9435 Mon Sep 17 00:00:00 2001 From: ravil Date: Tue, 1 Jun 2021 22:06:05 +0200 Subject: [PATCH 03/29] added compileLayer in the engine. * Propagated llvm::context to ast nodes * Propagated llvm::irbuilder to ast nodes * Initialized a function proto * Added function and module print pass --- CMakeLists.txt | 34 +++++------- compiler/code-gen/code_generator.cc | 51 +++++++++++++++--- compiler/code-gen/include/code_generator.hh | 5 ++ compiler/driver.cc | 2 +- compiler/{code-gen => }/engine/engine.cpp | 53 +++++++++++++++++-- compiler/{code-gen => }/engine/engine.h | 9 ++++ compiler/include/gen_tools.h | 20 +++++++ compiler/include/nodes/assignment_nodes.h | 15 +++--- compiler/include/nodes/boolean_nodes.h | 10 ++-- compiler/include/nodes/compare_nodes.h | 5 +- compiler/include/nodes/conditional_nodes.h | 20 ++++--- compiler/include/nodes/expression_nodes.h | 47 +++++++++------- .../include/nodes/external_function_nodes.h | 10 ++-- compiler/include/nodes/node.h | 10 ++-- compiler/include/nodes/return_nodes.h | 11 ++-- compiler/include/toolbox.h | 20 +++++++ impalajit.cc | 3 ++ tests/CMakeLists.txt | 2 +- 18 files changed, 236 insertions(+), 91 deletions(-) rename compiler/{code-gen => }/engine/engine.cpp (51%) rename compiler/{code-gen => }/engine/engine.h (89%) create mode 100644 compiler/include/gen_tools.h create mode 100644 compiler/include/toolbox.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 15b8b5b..5944429 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,8 @@ set(include_dirs compiler/frontend/include compiler/semantic_analysis/include compiler/code-gen/include - compiler/code-gen/assembly/include) + compiler/code-gen/assembly/include + compiler/engine) include_directories(${include_dirs}) @@ -57,7 +58,7 @@ set(source_files ${source_files} compiler/code-gen/include/calculation_helper.hh compiler/code-gen/code_generator.cc compiler/code-gen/assembly/assembly__sse_4_1.cc - compiler/code-gen/engine/engine.cpp) + compiler/engine/engine.cpp) ##### pkg-config ##### find_package( PkgConfig ) @@ -88,28 +89,26 @@ if( PKG_CONFIG_FOUND ) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/impalajit.pc DESTINATION lib/pkgconfig ) endif( PKG_CONFIG_FOUND ) - find_package(LLVM 10.0 REQUIRED CONFIG) LLVM_MAP_COMPONENTS_TO_LIBNAMES(LLVM_LIBS core orcjit native) message(STATUS "LLVM: ${LLVM_VERSION}") if( SHARED_LIB ) - add_library( impalajit SHARED ${source_files} ) - target_link_libraries( impalajit PRIVATE ${math_library} ${LLVM_LIBS} ) - target_include_directories( impalajit PRIVATE ${LLVM_INCLUDE_DIRS} ) - target_compile_definitions( impalajit PRIVATE ${LLVM_DEFINITIONS} ) + set(TARGET_NAME impalajit) + add_library( ${TARGET_NAME} SHARED ${source_files} ) endif( SHARED_LIB ) if( STATIC_LIB ) - add_library( impalajit-static STATIC ${source_files} ) - set_target_properties( impalajit-static PROPERTIES OUTPUT_NAME impalajit ) - - target_link_libraries( impalajit-static PRIVATE ${math_library} ${LLVM_LIBS} ) - target_include_directories( impalajit-static PRIVATE ${LLVM_INCLUDE_DIRS} ) - target_compile_definitions( impalajit-static PRIVATE ${LLVM_DEFINITIONS} ) + set(TARGET_NAME impalajit-static) + add_library( ${TARGET_NAME} STATIC ${source_files} ) + set_target_properties( ${TARGET_NAME} PROPERTIES OUTPUT_NAME impalajit ) endif( STATIC_LIB ) +target_link_libraries( ${TARGET_NAME} PUBLIC ${math_library} ${LLVM_LIBS} ) +target_include_directories( ${TARGET_NAME} PRIVATE ${LLVM_INCLUDE_DIRS} ) +target_compile_definitions( ${TARGET_NAME} PRIVATE ${LLVM_DEFINITIONS} ) + # Tests if( TESTS ) enable_testing() @@ -117,14 +116,7 @@ if( 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( TARGETS ${TARGET_NAME} DESTINATION lib ) install( FILES include/impalajit.hh DESTINATION include ) install( FILES include/impalajit.f90 diff --git a/compiler/code-gen/code_generator.cc b/compiler/code-gen/code_generator.cc index cc604a8..fa2cba3 100644 --- a/compiler/code-gen/code_generator.cc +++ b/compiler/code-gen/code_generator.cc @@ -17,7 +17,7 @@ * THE SOFTWARE. */ -#include "engine/engine.h" +#include "engine.h" #include #include #include @@ -25,6 +25,7 @@ #include #include #include +#include "llvm/IR/Verifier.h" #include @@ -55,17 +56,23 @@ CodeGenerator::~CodeGenerator() dasm_gen_func CodeGenerator::generateCode(FunctionContext* &functionContext) { FunctionPtrMap::initialize_map(); - std::cout << "function name: " << functionContext->name << std::endl; auto &jit = Jit::getJit(); - auto &dl = jit.getDataLayout(); { auto lock = jit.getLock(); - auto &context = jit.getContext(); - std::cout << "getIndexTypeSicd zeInBits: " << dl.getIndexTypeSizeInBits(llvm::Type::getVoidTy(context)) << std::endl; - } + auto& context = jit.getContext(); + auto builder = std::make_unique>(context); + + impala::Toolbox tools(context, *builder); + auto function = this->genFunctionProto(functionContext, *jit.getCurrentModule(), tools); + functionContext->root->codegen(tools); - functionContext->root->codegen(); + llvm::verifyFunction(*function, &llvm::outs()); + Jit::printIRFunction(function); + } + jit.registerModule(); + auto generatedFunction = reinterpret_cast(jit.lookup(functionContext->name).getAddress()); + std::cout << "hello: " << generatedFunction(2.0, 20.0) << std::endl; assembly.initialize(functionContext->parameters.size()); assembly.prologue(); @@ -77,6 +84,36 @@ dasm_gen_func CodeGenerator::generateCode(FunctionContext* &functionContext) return assembly.linkAndEncode(); } + +llvm::Function* CodeGenerator::genFunctionProto(FunctionContext* &functionContext, + llvm::Module& currModule, + impala::Toolbox &tools) { + + const auto numParams = functionContext->parameters.size(); + auto typeReal = llvm::Type::getDoubleTy(tools.context); + std::vector paramTypes(numParams, typeReal); + + // TODO: check whether a function proto has already been added + + llvm::FunctionType *functionProto = llvm::FunctionType::get(typeReal, paramTypes, false); + auto function = llvm::Function::Create(functionProto, + llvm::Function::ExternalLinkage, + functionContext->name, + currModule); + + const auto& params = functionContext->parameters; + for (size_t i = 0; i < params.size(); ++i) { + llvm::Argument* arg = function->getArg(i); + arg->setName(params[i]); + tools.table[params[i]] = arg; + } + llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(tools.context, "entry", function); + tools.builder.SetInsertPoint(entryBlock); + + return function; +} + + /** * @see code_generator.hh */ diff --git a/compiler/code-gen/include/code_generator.hh b/compiler/code-gen/include/code_generator.hh index cf36018..20980bd 100644 --- a/compiler/code-gen/include/code_generator.hh +++ b/compiler/code-gen/include/code_generator.hh @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,10 @@ private: Assembly__SSE_4_1 assembly; + llvm::Function* genFunctionProto(FunctionContext* &functionContext, + llvm::Module& currModule, + impala::Toolbox &tools); + /** * This functions performs the depth-first search algorithm. * Each Node of the AST carries a type. diff --git a/compiler/driver.cc b/compiler/driver.cc index 2ebaf65..3f7789c 100644 --- a/compiler/driver.cc +++ b/compiler/driver.cc @@ -51,7 +51,7 @@ std::map Driver::parse_stream(std::istream& in) CodeGenerator codeGenerator; dasm_gen_func function = codeGenerator.generateCode(functionContext); - std::map resultMap; + std::map resultMap; resultMap.insert(std::make_pair(functionContext->name, function)); return resultMap; diff --git a/compiler/code-gen/engine/engine.cpp b/compiler/engine/engine.cpp similarity index 51% rename from compiler/code-gen/engine/engine.cpp rename to compiler/engine/engine.cpp index 6dcf99f..434b791 100644 --- a/compiler/code-gen/engine/engine.cpp +++ b/compiler/engine/engine.cpp @@ -1,7 +1,8 @@ #include "engine.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/IRPrintingPasses.h" #include -#include "llvm/ExecutionEngine/Orc/LLJIT.h" Jit& Jit::getJit() { static Jit jit; @@ -15,23 +16,36 @@ Jit::Jit() { auto expectedJTMB = llvm::orc::JITTargetMachineBuilder::detectHost(); if (!expectedJTMB) { - throw std::runtime_error("cannot create jit machine builder"); + throw std::runtime_error("impala: cannot create jit machine builder"); } auto expectedDataLayout = expectedJTMB->getDefaultDataLayoutForTarget(); if (!expectedDataLayout) { - throw std::runtime_error("cannot detect data layout"); + 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); - auto compiler = std::make_unique(std::move(*expectedJTMB)); + 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); - std::string dylibName{"jit_dylib"}; + + // runtime dyn. layer + const std::string dylibName{"jit_dylib"}; ES.createJITDylib(dylibName); jitDylib = ES.getJITDylibByName(dylibName); + + // create llvm context context = std::make_unique(std::make_unique()); } catch (const std::exception& err) { @@ -52,6 +66,35 @@ llvm::JITEvaluatedSymbol Jit::lookup(llvm::StringRef Name) { 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; +} + +void Jit::reserveModule() { + static long long counter{0}; + std::string moduleName{"impala_module_" + std::to_string(counter)}; + module = (std::make_unique(std::move(moduleName), *context->getContext())); + ++counter; +} + +void Jit::registerModule() { + this->addModule(module); +} + +std::unique_ptr& Jit::getCurrentModule() { + return module; +} + +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); } \ No newline at end of file diff --git a/compiler/code-gen/engine/engine.h b/compiler/engine/engine.h similarity index 89% rename from compiler/code-gen/engine/engine.h rename to compiler/engine/engine.h index f3a1f18..2ca8abe 100644 --- a/compiler/code-gen/engine/engine.h +++ b/compiler/engine/engine.h @@ -16,6 +16,7 @@ #include "llvm/ExecutionEngine/Orc/LLJIT.h" #include #include +#include /* * ExecutionSession - provides context for our running JIT’d code (including the string pool, @@ -51,6 +52,13 @@ class Jit { // looks up addresses for function and variable definitions added to the JIT based on their symbol names. llvm::JITEvaluatedSymbol lookup(llvm::StringRef Name); + void reserveModule(); + std::unique_ptr& getCurrentModule(); + void registerModule(); + + static void printIRFunction(llvm::Function* function); + static void printIRModule(llvm::Module& module); + private: Jit(); llvm::orc::ExecutionSession ES; @@ -61,6 +69,7 @@ class Jit { std::unique_ptr dataLayout{nullptr}; std::unique_ptr mangle{nullptr}; std::unique_ptr context{nullptr}; + std::unique_ptr module; }; #endif //IMPALA_CPP_ENGINE_H diff --git a/compiler/include/gen_tools.h b/compiler/include/gen_tools.h new file mode 100644 index 0000000..dfb34f1 --- /dev/null +++ b/compiler/include/gen_tools.h @@ -0,0 +1,20 @@ +#ifndef IMPALA_CPP_STATE_H +#define IMPALA_CPP_STATE_H + +#include "llvm/IR/Value.h" +#include "llvm/IR/IRBuilder.h" +#include +#include + +namespace impala { +using TableT = std::unordered_map; +struct GenTools { + GenTools(llvm::LLVMContext& context) : context(context) {} + GenTools(const GenTools& other) = default; + llvm::IRBuilder<> *builder{nullptr}; + llvm::LLVMContext &context; + TableT table{}; +}; +} + +#endif //IMPALA_CPP_STATE_H diff --git a/compiler/include/nodes/assignment_nodes.h b/compiler/include/nodes/assignment_nodes.h index 7451d1d..59fc473 100644 --- a/compiler/include/nodes/assignment_nodes.h +++ b/compiler/include/nodes/assignment_nodes.h @@ -35,17 +35,14 @@ class AssignmentNode : public Node virtual ~AssignmentNode() { } -/* - virtual void evaluate() { - node->evaluate(); - assembly.storeLocalVariable(); - }*/ - virtual void codegen() { - for (auto node: nodes) { - node->codegen(); - } + + llvm::Value* codegen(impala::Toolbox& tools) override { + for (auto node: nodes) { + node->codegen(tools); + } std::cout << "am root" << std::endl; + return nullptr; } }; #endif //IMPALAJIT_ASSIGNMENT_EXPRESSION_HH diff --git a/compiler/include/nodes/boolean_nodes.h b/compiler/include/nodes/boolean_nodes.h index 741b852..a838ef1 100644 --- a/compiler/include/nodes/boolean_nodes.h +++ b/compiler/include/nodes/boolean_nodes.h @@ -30,11 +30,12 @@ class BooleanAndNode : public Node { { } - void codegen() override { + llvm::Value* codegen(impala::Toolbox& tools) override { for (auto node: nodes) { - node->codegen(); + node->codegen(tools); } std::cout << "BooleanAndNode" << std::endl; + return nullptr; } }; @@ -47,11 +48,12 @@ class BooleanOrNode : public Node { { } - void codegen() override { + llvm::Value* codegen(impala::Toolbox& tools) override { for (auto node: nodes) { - node->codegen(); + node->codegen(tools); } std::cout << "BooleanOrNode" << std::endl; + return nullptr; } }; diff --git a/compiler/include/nodes/compare_nodes.h b/compiler/include/nodes/compare_nodes.h index c6aef22..c8ea0f2 100644 --- a/compiler/include/nodes/compare_nodes.h +++ b/compiler/include/nodes/compare_nodes.h @@ -33,11 +33,12 @@ class CompareNode : public Node nodes.push_back(_left); } - void codegen() override { + llvm::Value* codegen(impala::Toolbox& tools) override { for (auto node: nodes) { - node->codegen(); + node->codegen(tools); } std::cout << "CompareNode" << std::endl; + return nullptr; } }; diff --git a/compiler/include/nodes/conditional_nodes.h b/compiler/include/nodes/conditional_nodes.h index 57af2ed..01da53c 100644 --- a/compiler/include/nodes/conditional_nodes.h +++ b/compiler/include/nodes/conditional_nodes.h @@ -32,11 +32,12 @@ class IfStmtNode : public Node nodes.push_back(_if_body); } - void codegen() override { + llvm::Value* codegen(impala::Toolbox& tools) override { for (auto node: nodes) { - node->codegen(); + node->codegen(tools); } std::cout << "IfStmtNode" << std::endl; + return nullptr; } }; @@ -52,11 +53,12 @@ class IfElseStmtNode : public Node nodes.push_back(_else_body); } - void codegen() override { + llvm::Value* codegen(impala::Toolbox& tools) override { for (auto node: nodes) { - node->codegen(); + node->codegen(tools); } std::cout << "IfElseStmtNode" << std::endl; + return nullptr; } }; @@ -72,11 +74,12 @@ class IfBodyNode : public Node { } - void codegen() override { + llvm::Value* codegen(impala::Toolbox& tools) override { for (auto node: nodes) { - node->codegen(); + node->codegen(tools); } std::cout << "IfBodyNode" << std::endl; + return nullptr; } }; @@ -92,11 +95,12 @@ class ElseBodyNode : public Node { } - void codegen() override { + llvm::Value* codegen(impala::Toolbox& tools) override { for (auto node: nodes) { - node->codegen(); + node->codegen(tools); } std::cout << "ElseBodyNode" << std::endl; + return nullptr; } }; #endif //IMPALAJIT_COMPLEX_EXPRESSION_H diff --git a/compiler/include/nodes/expression_nodes.h b/compiler/include/nodes/expression_nodes.h index 94d27d5..b8c0d24 100644 --- a/compiler/include/nodes/expression_nodes.h +++ b/compiler/include/nodes/expression_nodes.h @@ -31,11 +31,12 @@ class ConstantNode : public Node { } - void codegen() override { + llvm::Value* codegen(impala::Toolbox& tools) override { for (auto node: nodes) { - node->codegen(); + node->codegen(tools); } std::cout << "ConstantNode" << std::endl; + return nullptr; } }; @@ -47,11 +48,10 @@ class VariableNode : public Node { : Node(VARIABLE), name(_name) { } - void codegen() override { - for (auto node: nodes) { - node->codegen(); - } + llvm::Value* codegen(impala::Toolbox& tools) override { + assert(nodes.size() == 0 && "VariableNode must have no children"); std::cout << "VariableNode" << std::endl; + return tools.table.find(name) != tools.table.end() ? tools.table[name] : nullptr; } }; @@ -64,11 +64,12 @@ class NegationNode : public Node nodes.push_back(_node); } - void codegen() override { + llvm::Value* codegen(impala::Toolbox& tools) override { for (auto node: nodes) { - node->codegen(); + node->codegen(tools); } std::cout << "NegationNode" << std::endl; + return nullptr; } }; @@ -82,11 +83,12 @@ class AdditionNode : public Node nodes.push_back(_right); } - void codegen() override { + llvm::Value* codegen(impala::Toolbox& tools) override { for (auto node: nodes) { - node->codegen(); + node->codegen(tools); } std::cout << "AdditionNode" << std::endl; + return nullptr; } }; @@ -100,11 +102,12 @@ class SubtractionNode : public Node nodes.push_back(_right); } - void codegen() override { + llvm::Value* codegen(impala::Toolbox& tools) override { for (auto node: nodes) { - node->codegen(); + node->codegen(tools); } std::cout << "SubtractionNode" << std::endl; + return nullptr; } }; @@ -118,11 +121,13 @@ class MultiplicationNode : public Node nodes.push_back(_right); } - void codegen() override { - for (auto node: nodes) { - node->codegen(); - } + llvm::Value* codegen(impala::Toolbox& tools) override { + assert(nodes.size() == 2 && "MultiplicationNode must be a binary op"); + auto lhs = nodes[0]->codegen(tools); + auto rhs = nodes[1]->codegen(tools); + std::cout << "MultiplicationNode" << std::endl; + return tools.builder.CreateFMul(lhs, rhs); } }; @@ -136,11 +141,12 @@ class DivisionNode : public Node nodes.push_back(_right); } - void codegen() override { + llvm::Value* codegen(impala::Toolbox& tools) override { for (auto node: nodes) { - node->codegen(); + node->codegen(tools); } std::cout << "DivisionNode" << std::endl; + return nullptr; } }; @@ -154,11 +160,12 @@ class PowerNode : public Node nodes.push_back(_base); } - void codegen() override { + llvm::Value* codegen(impala::Toolbox& tools) override { for (auto node: nodes) { - node->codegen(); + node->codegen(tools); } std::cout << "PowerNode" << std::endl; + return nullptr; } }; diff --git a/compiler/include/nodes/external_function_nodes.h b/compiler/include/nodes/external_function_nodes.h index 3aa0c8e..c98366d 100644 --- a/compiler/include/nodes/external_function_nodes.h +++ b/compiler/include/nodes/external_function_nodes.h @@ -40,11 +40,12 @@ class ExternalFunctionNode: public Node { } - void codegen() override { + llvm::Value* codegen(impala::Toolbox& tools) override { for (auto node: nodes) { - node->codegen(); + node->codegen(tools); } std::cout << "ExternalFunctionNode" << std::endl; + return nullptr; } }; @@ -60,11 +61,12 @@ class ExternalFunctionParametersNode : public Node { } - void codegen() override { + llvm::Value* codegen(impala::Toolbox& tools) override { for (auto node: nodes) { - node->codegen(); + node->codegen(tools); } std::cout << "ExternalFunctionParametersNode" << std::endl; + return nullptr; } }; diff --git a/compiler/include/nodes/node.h b/compiler/include/nodes/node.h index 0f3947b..31894ed 100644 --- a/compiler/include/nodes/node.h +++ b/compiler/include/nodes/node.h @@ -21,6 +21,7 @@ #define EXPRESSION_H #include +#include #include #include @@ -39,7 +40,7 @@ class Node nodes.clear(); } - virtual void codegen() = 0; + virtual llvm::Value* codegen(impala::Toolbox& tools) = 0; }; class RootNode : public Node @@ -50,11 +51,12 @@ class RootNode : public Node { } - void codegen() override { + llvm::Value* codegen(impala::Toolbox& tools) override { for (auto node: nodes) { - node->codegen(); + node->codegen(tools); } - std::cout << "am root" << std::endl; + std::cout << "Im root" << std::endl; + return nullptr; } }; diff --git a/compiler/include/nodes/return_nodes.h b/compiler/include/nodes/return_nodes.h index 94918f3..f7f651e 100644 --- a/compiler/include/nodes/return_nodes.h +++ b/compiler/include/nodes/return_nodes.h @@ -31,11 +31,12 @@ class ReturnNode : public Node nodes.push_back(_node); } - void codegen() override { - for (auto node: nodes) { - node->codegen(); - } - std::cout << "am return" << std::endl; + llvm::Value* codegen(impala::Toolbox& tools) override { + assert(nodes.size() == 1 && "VariableNode must have one child"); + std::cout << "ReturnNode" << std::endl; + + auto returnValue = nodes[0]->codegen(tools); + return tools.builder.CreateRet(returnValue); } }; #endif //IMPALAJIT_RETURN_NODE_H diff --git a/compiler/include/toolbox.h b/compiler/include/toolbox.h new file mode 100644 index 0000000..c673070 --- /dev/null +++ b/compiler/include/toolbox.h @@ -0,0 +1,20 @@ +#ifndef IMPALA_CPP_STATE_H +#define IMPALA_CPP_STATE_H + +#include "llvm/IR/Value.h" +#include "llvm/IR/IRBuilder.h" +#include +#include + +namespace impala { +using TableT = std::unordered_map; +struct Toolbox { + Toolbox(llvm::LLVMContext& context, llvm::IRBuilder<> &builder) : context(context), builder(builder) {} + Toolbox(const Toolbox& other) = default; + llvm::IRBuilder<> &builder; + llvm::LLVMContext &context; + TableT table{}; +}; +} + +#endif //IMPALA_CPP_STATE_H diff --git a/impalajit.cc b/impalajit.cc index df62455..511ac10 100644 --- a/impalajit.cc +++ b/impalajit.cc @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -75,12 +76,14 @@ void impalajit::Compiler::loadFunctionDefinitionsFromInputFiles(std::string _con } void impalajit::Compiler::compile(){ + Jit::getJit().reserveModule(); for(auto& definition: functionDefinitions) { auto parsedFunctions = driver.parse_string(definition); functionMap.insert(parsedFunctions.begin(), parsedFunctions.end()); parameterCountMap.insert(std::make_pair(parsedFunctions.begin()->first, driver.getParameterCount())); driver.deleteFunctionContext(); } + // TODO: register a module } dasm_gen_func impalajit::Compiler::getFunction(std::string functionName) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 60bdeb2..f99c7c8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -28,7 +28,7 @@ function( add_test_executable name ) add_test(${name} test_${name}.o) # Link with impalajit - target_link_libraries( test_${name}.o impalajit) + target_link_libraries( test_${name}.o ${TARGET_NAME} ) endfunction( add_test_executable ) include_directories(include) From 13ce3099ee93d386d4efd4d05650c2d2ade97a6f Mon Sep 17 00:00:00 2001 From: ravil Date: Wed, 2 Jun 2021 18:10:42 +0200 Subject: [PATCH 04/29] Re-ordered a file structure and generation mechanism --- .../code-gen/assembly/include/assembly.hh | 6 +-- compiler/code-gen/code_generator.cc | 42 ++++++++++--------- compiler/code-gen/include/code_generator.hh | 2 + compiler/driver.cc | 24 +++++++++++ compiler/engine/engine.cpp | 12 +----- compiler/engine/engine.h | 6 +-- compiler/include/driver.h | 4 ++ compiler/include/function_context.h | 2 + impalajit.cc | 19 ++++++++- include/impalajit.hh | 1 + 10 files changed, 79 insertions(+), 39 deletions(-) diff --git a/compiler/code-gen/assembly/include/assembly.hh b/compiler/code-gen/assembly/include/assembly.hh index ff888fd..171e961 100644 --- a/compiler/code-gen/assembly/include/assembly.hh +++ b/compiler/code-gen/assembly/include/assembly.hh @@ -182,9 +182,9 @@ public: virtual dasm_gen_func linkAndEncode()= 0; protected: - dasm_State* d; - dasm_State** Dst; - void** labels; + dasm_State* d{nullptr}; + dasm_State** Dst{nullptr}; + void** labels{nullptr}; int stackPos; // The head of the rpn stack std::stack stackPosStack; }; diff --git a/compiler/code-gen/code_generator.cc b/compiler/code-gen/code_generator.cc index fa2cba3..77c4b40 100644 --- a/compiler/code-gen/code_generator.cc +++ b/compiler/code-gen/code_generator.cc @@ -56,23 +56,6 @@ CodeGenerator::~CodeGenerator() dasm_gen_func CodeGenerator::generateCode(FunctionContext* &functionContext) { FunctionPtrMap::initialize_map(); - auto &jit = Jit::getJit(); - { - auto lock = jit.getLock(); - - auto& context = jit.getContext(); - auto builder = std::make_unique>(context); - - impala::Toolbox tools(context, *builder); - auto function = this->genFunctionProto(functionContext, *jit.getCurrentModule(), tools); - functionContext->root->codegen(tools); - - llvm::verifyFunction(*function, &llvm::outs()); - Jit::printIRFunction(function); - } - jit.registerModule(); - auto generatedFunction = reinterpret_cast(jit.lookup(functionContext->name).getAddress()); - std::cout << "hello: " << generatedFunction(2.0, 20.0) << std::endl; assembly.initialize(functionContext->parameters.size()); assembly.prologue(); @@ -85,9 +68,30 @@ dasm_gen_func CodeGenerator::generateCode(FunctionContext* &functionContext) } +void CodeGenerator::generateLLVMCode(FunctionContext* &functionContext, llvm::Module& module) { + auto &jit = Jit::getJit(); + { + auto lock = jit.getLock(); + + auto& context = jit.getContext(); + auto builder = std::make_unique>(context); + impala::Toolbox tools(context, *builder); + + auto function = this->genFunctionProto(functionContext, module, tools); + functionContext->root->codegen(tools); + + llvm::verifyFunction(*function, &llvm::outs()); + Jit::printIRFunction(function); + + // TODO: delete this one (memory de-allocation bug) + generateCode(functionContext); + } +} + + llvm::Function* CodeGenerator::genFunctionProto(FunctionContext* &functionContext, - llvm::Module& currModule, - impala::Toolbox &tools) { + llvm::Module& currModule, + impala::Toolbox &tools) { const auto numParams = functionContext->parameters.size(); auto typeReal = llvm::Type::getDoubleTy(tools.context); diff --git a/compiler/code-gen/include/code_generator.hh b/compiler/code-gen/include/code_generator.hh index 20980bd..769bde3 100644 --- a/compiler/code-gen/include/code_generator.hh +++ b/compiler/code-gen/include/code_generator.hh @@ -114,5 +114,7 @@ public: * @return the function pointer */ dasm_gen_func generateCode(FunctionContext* &functionContext); + + void generateLLVMCode(FunctionContext* &functionContext, llvm::Module& module); }; #endif //IMPALAJIT_CODE_GENERATOR_HH diff --git a/compiler/driver.cc b/compiler/driver.cc index 3f7789c..fd0eb95 100644 --- a/compiler/driver.cc +++ b/compiler/driver.cc @@ -63,6 +63,30 @@ std::map Driver::parse_string(const std::string &inpu return parse_stream(iss); } +FunctionContext::FunctionSinatureT Driver::generateLLVMFunction(std::istream& in, llvm::Module& module) { + Scanner scanner(&in); + scanner.set_debug(false); + this->lexer = &scanner; + + Parser parser(*this); + parser.set_debug_level(false); + parser.parse(); + + SemanticAnalyzer semanticAnalyzer; + semanticAnalyzer.performSemanticAnalysis(functionContext); + + CodeGenerator codeGenerator; + codeGenerator.generateLLVMCode(functionContext, module); + return std::make_pair(functionContext->name, functionContext->parameters.size()); +} + +FunctionContext::FunctionSinatureT Driver::generateLLVMFunction(const std::string &input, + llvm::Module& module) { + std::istringstream iss(input); + auto signature = generateLLVMFunction(iss, module); + return signature; +} + void Driver::deleteFunctionContext(){ delete functionContext; functionContext = nullptr; diff --git a/compiler/engine/engine.cpp b/compiler/engine/engine.cpp index 434b791..4471aff 100644 --- a/compiler/engine/engine.cpp +++ b/compiler/engine/engine.cpp @@ -71,19 +71,11 @@ llvm::JITEvaluatedSymbol Jit::lookup(llvm::StringRef Name) { return *expected; } -void Jit::reserveModule() { +std::unique_ptr Jit::createModule() { static long long counter{0}; std::string moduleName{"impala_module_" + std::to_string(counter)}; - module = (std::make_unique(std::move(moduleName), *context->getContext())); ++counter; -} - -void Jit::registerModule() { - this->addModule(module); -} - -std::unique_ptr& Jit::getCurrentModule() { - return module; + return std::make_unique(std::move(moduleName), *context->getContext()); } void Jit::printIRFunction(llvm::Function* function) { diff --git a/compiler/engine/engine.h b/compiler/engine/engine.h index 2ca8abe..2c7a1ea 100644 --- a/compiler/engine/engine.h +++ b/compiler/engine/engine.h @@ -52,10 +52,7 @@ class Jit { // looks up addresses for function and variable definitions added to the JIT based on their symbol names. llvm::JITEvaluatedSymbol lookup(llvm::StringRef Name); - void reserveModule(); - std::unique_ptr& getCurrentModule(); - void registerModule(); - + std::unique_ptr createModule(); static void printIRFunction(llvm::Function* function); static void printIRModule(llvm::Module& module); @@ -69,7 +66,6 @@ class Jit { std::unique_ptr dataLayout{nullptr}; std::unique_ptr mangle{nullptr}; std::unique_ptr context{nullptr}; - std::unique_ptr module; }; #endif //IMPALA_CPP_ENGINE_H diff --git a/compiler/include/driver.h b/compiler/include/driver.h index 20e4176..3d07c3b 100644 --- a/compiler/include/driver.h +++ b/compiler/include/driver.h @@ -46,6 +46,10 @@ class Driver std::map parse_string(const std::string& input); + FunctionContext::FunctionSinatureT generateLLVMFunction(std::istream& in, llvm::Module& module); + + FunctionContext::FunctionSinatureT generateLLVMFunction(const std::string& input, llvm::Module& module); + void setFunctionContext(FunctionContext* _functionContext); void deleteFunctionContext(); diff --git a/compiler/include/function_context.h b/compiler/include/function_context.h index 09318fa..30fba9a 100644 --- a/compiler/include/function_context.h +++ b/compiler/include/function_context.h @@ -27,6 +27,8 @@ class FunctionContext { public: + using FunctionSinatureT = std::pair; + std::vector parameters; std::vector variables; Node* root; diff --git a/impalajit.cc b/impalajit.cc index 511ac10..e50c78d 100644 --- a/impalajit.cc +++ b/impalajit.cc @@ -75,15 +75,30 @@ void impalajit::Compiler::loadFunctionDefinitionsFromInputFiles(std::string _con } } +void impalajit::Compiler::compileWithLLVM() { + auto& jit = Jit::getJit(); + auto currentModule = jit.createModule(); + std::vector functionSignature; + for(auto& definition: functionDefinitions) { + functionSignature.emplace_back(driver.generateLLVMFunction(definition, *currentModule)); + driver.deleteFunctionContext(); + } + jit.addModule(currentModule); + + for (auto& signature: functionSignature) { + auto function = reinterpret_cast(jit.lookup(signature.first).getAddress()); + functionMap[signature.first] = function; + parameterCountMap[signature.first] = signature.second; + } +} + void impalajit::Compiler::compile(){ - Jit::getJit().reserveModule(); for(auto& definition: functionDefinitions) { auto parsedFunctions = driver.parse_string(definition); functionMap.insert(parsedFunctions.begin(), parsedFunctions.end()); parameterCountMap.insert(std::make_pair(parsedFunctions.begin()->first, driver.getParameterCount())); driver.deleteFunctionContext(); } - // TODO: register a module } dasm_gen_func impalajit::Compiler::getFunction(std::string functionName) { diff --git a/include/impalajit.hh b/include/impalajit.hh index 2bc3d7a..932e2f0 100644 --- a/include/impalajit.hh +++ b/include/impalajit.hh @@ -48,6 +48,7 @@ public: Compiler(); void compile(); + void compileWithLLVM(); dasm_gen_func getFunction(std::string functionName); unsigned int getParameterCount(std::string functionName); From 0b01ec224fba4f05329f743efd087f4b9bd587f8 Mon Sep 17 00:00:00 2001 From: ravil Date: Wed, 2 Jun 2021 23:48:22 +0200 Subject: [PATCH 05/29] Added LLVM code generation (except external math functions) --- .clang-format | 135 ++++++++++++++++ CMakeLists.txt | 3 +- compiler/code-gen/code_generator.cc | 20 ++- compiler/engine/engine.cpp | 42 +++-- compiler/engine/engine.h | 36 +++-- compiler/engine/engine_types.h | 17 ++ compiler/engine/hashers.h | 37 +++++ compiler/engine/std_math_lib.cpp | 31 ++++ compiler/engine/std_math_lib.h | 26 +++ compiler/include/gen_tools.h | 20 --- compiler/include/nodes/assignment_nodes.h | 15 +- compiler/include/nodes/boolean_nodes.h | 18 ++- compiler/include/nodes/compare_nodes.h | 39 ++++- compiler/include/nodes/conditional_nodes.h | 150 +++++++++++------- compiler/include/nodes/expression_nodes.h | 53 ++++--- .../include/nodes/external_function_nodes.h | 36 ++++- compiler/include/nodes/node.h | 4 +- compiler/include/toolbox.h | 13 +- example/cpp/example.cc | 3 +- example/cpp/impala_file/example.impala | 2 +- impalajit.cc | 2 +- 21 files changed, 537 insertions(+), 165 deletions(-) create mode 100644 .clang-format create mode 100644 compiler/engine/engine_types.h create mode 100644 compiler/engine/hashers.h create mode 100644 compiler/engine/std_math_lib.cpp create mode 100644 compiler/engine/std_math_lib.h delete mode 100644 compiler/include/gen_tools.h 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/CMakeLists.txt b/CMakeLists.txt index 5944429..50e4235 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,7 +58,8 @@ set(source_files ${source_files} compiler/code-gen/include/calculation_helper.hh compiler/code-gen/code_generator.cc compiler/code-gen/assembly/assembly__sse_4_1.cc - compiler/engine/engine.cpp) + compiler/engine/engine.cpp + compiler/engine/std_math_lib.cpp) ##### pkg-config ##### find_package( PkgConfig ) diff --git a/compiler/code-gen/code_generator.cc b/compiler/code-gen/code_generator.cc index 77c4b40..725feaa 100644 --- a/compiler/code-gen/code_generator.cc +++ b/compiler/code-gen/code_generator.cc @@ -69,19 +69,20 @@ dasm_gen_func CodeGenerator::generateCode(FunctionContext* &functionContext) void CodeGenerator::generateLLVMCode(FunctionContext* &functionContext, llvm::Module& module) { - auto &jit = Jit::getJit(); + auto &jit = impala::engine::Jit::getJit(); { auto lock = jit.getLock(); - auto& context = jit.getContext(); + llvm::LLVMContext& context = jit.getContext(); auto builder = std::make_unique>(context); - impala::Toolbox tools(context, *builder); + auto& externalFunctions = jit.getExternalMathFunctions(); + impala::Toolbox tools(context, *builder, externalFunctions); auto function = this->genFunctionProto(functionContext, module, tools); functionContext->root->codegen(tools); llvm::verifyFunction(*function, &llvm::outs()); - Jit::printIRFunction(function); + impala::engine::Jit::printIRModule(module); // TODO: delete this one (memory de-allocation bug) generateCode(functionContext); @@ -105,14 +106,19 @@ llvm::Function* CodeGenerator::genFunctionProto(FunctionContext* &functionContex functionContext->name, currModule); + llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(tools.context, "entry", function); + tools.builder.SetInsertPoint(entryBlock); + const auto& params = functionContext->parameters; + auto realType = llvm::Type::getDoubleTy(tools.context); for (size_t i = 0; i < params.size(); ++i) { llvm::Argument* arg = function->getArg(i); arg->setName(params[i]); - tools.table[params[i]] = arg; + + auto argPtr = tools.builder.CreateAlloca(realType); + tools.table[params[i]] = argPtr; + tools.builder.CreateStore(arg, argPtr); } - llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(tools.context, "entry", function); - tools.builder.SetInsertPoint(entryBlock); return function; } diff --git a/compiler/engine/engine.cpp b/compiler/engine/engine.cpp index 4471aff..007b8e4 100644 --- a/compiler/engine/engine.cpp +++ b/compiler/engine/engine.cpp @@ -1,10 +1,11 @@ #include "engine.h" -#include "llvm/IR/PassManager.h" #include "llvm/IR/IRPrintingPasses.h" +#include "llvm/IR/PassManager.h" #include - -Jit& Jit::getJit() { +namespace impala { +namespace engine { +Jit &Jit::getJit() { static Jit jit; return jit; } @@ -47,22 +48,28 @@ Jit::Jit() { // create llvm context context = std::make_unique(std::make_unique()); - } - catch (const std::exception& err) { + + this->createMathModule(); + } catch (const std::exception &err) { llvm::errs() << err.what() << '\n'; throw err; } } +void Jit::createMathModule() { + mathModule = this->createModule(); + llvm::Type *realType = llvm::Type::getDoubleTy(*(context->getContext())); + externalMathFunctions = StdMathLib::fillModule(mathModule, realType); + //this->addModule(mathModule); +} -void Jit::addModule(std::unique_ptr& module) { +void Jit::addModule(std::unique_ptr &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 - auto& m = *mangle; + auto &m = *mangle; llvm::Expected expected = ES.lookup({jitDylib}, (*mangle)(Name.str())); if (!expected) { llvm::errs() << expected.takeError() << '\n'; @@ -75,18 +82,23 @@ std::unique_ptr Jit::createModule() { static long long counter{0}; std::string moduleName{"impala_module_" + std::to_string(counter)}; ++counter; - return std::make_unique(std::move(moduleName), *context->getContext()); + + auto module = std::make_unique(std::move(moduleName), *context->getContext()); + llvm::Type *realType = llvm::Type::getDoubleTy(*(context->getContext())); + externalMathFunctions = StdMathLib::fillModule(module, realType); + return module; } -void Jit::printIRFunction(llvm::Function* function) { +void Jit::printIRFunction(llvm::Function *function) { llvm::raw_fd_ostream stream(fileno(stdout), false); - llvm::FunctionPass* printPass = llvm::createPrintFunctionPass(llvm::outs()); + llvm::FunctionPass *printPass = llvm::createPrintFunctionPass(llvm::outs()); printPass->runOnFunction(*function); } - -void Jit::printIRModule(llvm::Module& module) { +void Jit::printIRModule(llvm::Module &module) { llvm::raw_fd_ostream stream(fileno(stdout), false); - llvm::ModulePass* printPass = llvm::createPrintModulePass(llvm::outs()); + llvm::ModulePass *printPass = llvm::createPrintModulePass(llvm::outs()); printPass->runOnModule(module); -} \ No newline at end of file +} +} // namespace engine +} // namespace impala \ No newline at end of file diff --git a/compiler/engine/engine.h b/compiler/engine/engine.h index 2c7a1ea..ead14e3 100644 --- a/compiler/engine/engine.h +++ b/compiler/engine/engine.h @@ -1,21 +1,22 @@ #ifndef IMPALA_CPP_ENGINE_H #define IMPALA_CPP_ENGINE_H +#include "std_math_lib.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/TargetSelect.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/ExecutionEngine/Orc/LLJIT.h" -#include +#include "llvm/Support/TargetSelect.h" #include +#include #include /* @@ -38,26 +39,36 @@ * * JITDylib - A symbol table that supports asynchoronous symbol queries * */ - +namespace impala { +namespace engine { class Jit { public: - static Jit& getJit(); + 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); + void addModule(std::unique_ptr &module); // 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(); - static void printIRFunction(llvm::Function* function); - static void printIRModule(llvm::Module& module); + + types::FunctionProtosT &getExternalMathFunctions() { return externalMathFunctions; } + + static void printIRFunction(llvm::Function *function); + + static void printIRModule(llvm::Module &module); private: Jit(); + void createMathModule(); + llvm::orc::ExecutionSession ES; std::unique_ptr objectLayer{nullptr}; std::unique_ptr compileLayer{nullptr}; @@ -66,6 +77,9 @@ class Jit { std::unique_ptr dataLayout{nullptr}; std::unique_ptr mangle{nullptr}; std::unique_ptr context{nullptr}; -}; - -#endif //IMPALA_CPP_ENGINE_H + std::unique_ptr mathModule{nullptr}; + types::FunctionProtosT externalMathFunctions; +}; // 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..a941ac8 --- /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 + +namespace impala { +namespace engine { +namespace types { +using FunctionProtosT = std::unordered_map; +using FunctionSinatureT = std::pair; +} +} // 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..4a14d1a --- /dev/null +++ b/compiler/engine/hashers.h @@ -0,0 +1,37 @@ +#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; + } +}; +} + +#endif // IMPALA_CPP_HASHERS_H diff --git a/compiler/engine/std_math_lib.cpp b/compiler/engine/std_math_lib.cpp new file mode 100644 index 0000000..24739e1 --- /dev/null +++ b/compiler/engine/std_math_lib.cpp @@ -0,0 +1,31 @@ +#include "std_math_lib.h" + +namespace impala { +namespace engine { +decltype(StdMathLib::supportedFunctions) StdMathLib::supportedFunctions = decltype(supportedFunctions){ + {"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}}; + +bool StdMathLib::isSupported(const types::FunctionSinatureT &signature) { + return StdMathLib::supportedFunctions.find(signature) != StdMathLib::supportedFunctions.end(); +} + +types::FunctionProtosT StdMathLib::fillModule(std::unique_ptr &module, llvm::Type *realType) { + std::unordered_map functionProtoTable; + + for (const auto &signature : StdMathLib::supportedFunctions) { + const auto &name = signature.first; + const unsigned numParams = signature.second; + + std::vector params(numParams, realType); + llvm::FunctionType *functionType = llvm::FunctionType::get(realType, params, false); + llvm::Function *function = llvm::Function::Create(functionType, llvm::Function::ExternalLinkage, name, *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..12d40ef --- /dev/null +++ b/compiler/engine/std_math_lib.h @@ -0,0 +1,26 @@ +#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, llvm::Type *realType); + static bool isSupported(const types::FunctionSinatureT &signature); + +private: + static const std::unordered_set supportedFunctions; + std::unordered_map functionTable; +}; +} // namespace engine +} // namespace impala + +#endif // IMPALA_CPP_STD_MATH_LIB_HPP diff --git a/compiler/include/gen_tools.h b/compiler/include/gen_tools.h deleted file mode 100644 index dfb34f1..0000000 --- a/compiler/include/gen_tools.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef IMPALA_CPP_STATE_H -#define IMPALA_CPP_STATE_H - -#include "llvm/IR/Value.h" -#include "llvm/IR/IRBuilder.h" -#include -#include - -namespace impala { -using TableT = std::unordered_map; -struct GenTools { - GenTools(llvm::LLVMContext& context) : context(context) {} - GenTools(const GenTools& other) = default; - llvm::IRBuilder<> *builder{nullptr}; - llvm::LLVMContext &context; - TableT table{}; -}; -} - -#endif //IMPALA_CPP_STATE_H diff --git a/compiler/include/nodes/assignment_nodes.h b/compiler/include/nodes/assignment_nodes.h index 59fc473..f78530b 100644 --- a/compiler/include/nodes/assignment_nodes.h +++ b/compiler/include/nodes/assignment_nodes.h @@ -38,10 +38,19 @@ class AssignmentNode : public Node llvm::Value* codegen(impala::Toolbox& tools) override { - for (auto node: nodes) { - node->codegen(tools); + assert(nodes.size() == 1 && "AssignmentNode must have one child expr"); + auto expr = nodes[0]->codegen(tools); + + if (tools.table.find(name) != tools.table.end()) { + auto lhs = tools.table[name]; + tools.builder.CreateStore(expr, lhs); + } + else { + // TODO: add support for scopes + auto varDef = tools.builder.CreateAlloca(llvm::Type::getDoubleTy(tools.context)); + tools.builder.CreateStore(expr, varDef); + tools.table[name] = varDef; } - std::cout << "am root" << std::endl; return nullptr; } }; diff --git a/compiler/include/nodes/boolean_nodes.h b/compiler/include/nodes/boolean_nodes.h index a838ef1..ff2c5b3 100644 --- a/compiler/include/nodes/boolean_nodes.h +++ b/compiler/include/nodes/boolean_nodes.h @@ -31,11 +31,12 @@ class BooleanAndNode : public Node { } llvm::Value* codegen(impala::Toolbox& tools) override { - for (auto node: nodes) { - node->codegen(tools); - } + assert(nodes.size() == 2 && "BooleanAndNode must be a binary op"); + auto lhs = nodes[0]->codegen(tools); + auto rhs = nodes[1]->codegen(tools); + std::cout << "BooleanAndNode" << std::endl; - return nullptr; + return tools.builder.CreateAnd(lhs, rhs); } }; @@ -49,11 +50,12 @@ class BooleanOrNode : public Node { } llvm::Value* codegen(impala::Toolbox& tools) override { - for (auto node: nodes) { - node->codegen(tools); - } + assert(nodes.size() == 2 && "BooleanOrNode must be a binary op"); + auto lhs = nodes[0]->codegen(tools); + auto rhs = nodes[1]->codegen(tools); + std::cout << "BooleanOrNode" << std::endl; - return nullptr; + return tools.builder.CreateOr(lhs, rhs); } }; diff --git a/compiler/include/nodes/compare_nodes.h b/compiler/include/nodes/compare_nodes.h index c8ea0f2..9cafa8d 100644 --- a/compiler/include/nodes/compare_nodes.h +++ b/compiler/include/nodes/compare_nodes.h @@ -34,11 +34,44 @@ class CompareNode : public Node } llvm::Value* codegen(impala::Toolbox& tools) override { - for (auto node: nodes) { - node->codegen(tools); + assert(nodes.size() == 2 && "CompareNode must be a binary op"); + auto lhs = nodes[0]->codegen(tools); + auto rhs = nodes[1]->codegen(tools); + + llvm::Value* cmpResult{nullptr}; + switch (compareOperator) { + case CompareOperatorType::EQ: { + cmpResult = tools.builder.CreateFCmpOEQ(lhs, rhs); + break; + } + case CompareOperatorType::NE: { + cmpResult = tools.builder.CreateFCmpONE(lhs, rhs); + break; + } + case CompareOperatorType::GT: { + cmpResult = tools.builder.CreateFCmpOGT(lhs, rhs); + break; + } + case CompareOperatorType::LT: { + cmpResult = tools.builder.CreateFCmpOLT(lhs, rhs); + break; + } + case CompareOperatorType::GTE: { + cmpResult = tools.builder.CreateFCmpOGE(lhs, rhs); + break; + } + case CompareOperatorType::LTE: { + cmpResult = tools.builder.CreateFCmpOLE(lhs, rhs); + break; + } + default: { + std::string msg = "Unknown comparison operator: " + std::to_string(static_cast(compareOperator)); + throw std::runtime_error(std::move(msg)); + } } + std::cout << "CompareNode" << std::endl; - return nullptr; + return cmpResult; } }; diff --git a/compiler/include/nodes/conditional_nodes.h b/compiler/include/nodes/conditional_nodes.h index 01da53c..6b7a83e 100644 --- a/compiler/include/nodes/conditional_nodes.h +++ b/compiler/include/nodes/conditional_nodes.h @@ -22,85 +22,121 @@ #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); + } - llvm::Value* codegen(impala::Toolbox& tools) override { - for (auto node: nodes) { - node->codegen(tools); - } - std::cout << "IfStmtNode" << std::endl; - return nullptr; + llvm::Value *codegen(impala::Toolbox &tools) override { + assert(nodes.size() == 2 && "IfStmtNode must have two children nodes"); + auto cond = nodes[0]->codegen(tools); + + auto currFunction = tools.builder.GetInsertBlock()->getParent(); + auto thenBlock = llvm::BasicBlock::Create(tools.context); + auto mergeBlock = llvm::BasicBlock::Create(tools.context); + tools.builder.CreateCondBr(cond, thenBlock, mergeBlock); + + currFunction->getBasicBlockList().push_back(thenBlock); + currFunction->getBasicBlockList().push_back(mergeBlock); + + tools.builder.SetInsertPoint(thenBlock); + auto lastInstr = nodes[1]->codegen(tools); + if (llvm::dyn_cast(lastInstr) != nullptr) { + tools.builder.CreateBr(mergeBlock); } + + tools.builder.SetInsertPoint(mergeBlock); + + std::cout << "IfStmtNode" << std::endl; + return nullptr; + } }; -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); + } + + llvm::Value *codegen(impala::Toolbox &tools) override { + assert(nodes.size() == 3 && "IfStmtNode must have three children nodes"); + auto cond = nodes[0]->codegen(tools); + + auto currFunction = tools.builder.GetInsertBlock()->getParent(); + auto thenBlock = llvm::BasicBlock::Create(tools.context); + auto elseBlock = llvm::BasicBlock::Create(tools.context); + auto mergeBlock = llvm::BasicBlock::Create(tools.context); + + currFunction->getBasicBlockList().push_back(thenBlock); + currFunction->getBasicBlockList().push_back(elseBlock); - 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); + tools.builder.CreateCondBr(cond, thenBlock, elseBlock); + + tools.builder.SetInsertPoint(thenBlock); + auto lastThenBlockInstr = nodes[1]->codegen(tools); + bool noReturnInThenBlock = llvm::dyn_cast(lastThenBlockInstr) == nullptr; + if (noReturnInThenBlock) { + tools.builder.CreateBr(mergeBlock); } - llvm::Value* codegen(impala::Toolbox& tools) override { - for (auto node: nodes) { - node->codegen(tools); - } - std::cout << "IfElseStmtNode" << std::endl; - return nullptr; + tools.builder.SetInsertPoint(elseBlock); + auto lastElseBlockInstr = nodes[2]->codegen(tools); + bool noReturnInElseBlock = llvm::dyn_cast(lastElseBlockInstr) == nullptr; + if (noReturnInElseBlock) { + tools.builder.CreateBr(mergeBlock); } + + if (noReturnInThenBlock || noReturnInElseBlock) { + currFunction->getBasicBlockList().push_back(mergeBlock); + tools.builder.SetInsertPoint(mergeBlock); + } + + std::cout << "IfElseStmtNode" << std::endl; + return nullptr; + } }; -class IfBodyNode : public Node -{ +class IfBodyNode : public Node { public: - IfBodyNode() - : Node(IF_BODY) - { - } + IfBodyNode() : Node(IF_BODY) {} - virtual ~IfBodyNode() - { - } + virtual ~IfBodyNode() {} - llvm::Value* codegen(impala::Toolbox& tools) override { - for (auto node: nodes) { - node->codegen(tools); + llvm::Value *codegen(impala::Toolbox &tools) override { + llvm::Value *lastInstruction{nullptr}; + for (auto node : nodes) { + lastInstruction = node->codegen(tools); + if (llvm::dyn_cast(lastInstruction)) { + // a return instruction found. Doesn't make sense to generate the rest of the instructions + break; } - std::cout << "IfBodyNode" << std::endl; - return nullptr; } + std::cout << "IfBodyNode" << std::endl; + return lastInstruction; + } }; -class ElseBodyNode : public Node -{ +class ElseBodyNode : public Node { public: - ElseBodyNode() - : Node(ELSE_BODY) - { - } + ElseBodyNode() : Node(ELSE_BODY) {} - virtual ~ElseBodyNode() - { - } + virtual ~ElseBodyNode() {} - llvm::Value* codegen(impala::Toolbox& tools) override { - for (auto node: nodes) { - node->codegen(tools); + llvm::Value *codegen(impala::Toolbox &tools) override { + llvm::Value *lastInstruction{nullptr}; + for (auto node : nodes) { + lastInstruction = node->codegen(tools); + if (llvm::dyn_cast(lastInstruction)) { + // a return instruction found. Doesn't make sense to generate the rest of the instructions + break; } - std::cout << "ElseBodyNode" << std::endl; - return nullptr; } + std::cout << "ElseBodyNode" << std::endl; + return lastInstruction; + } }; -#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 b8c0d24..03c765a 100644 --- a/compiler/include/nodes/expression_nodes.h +++ b/compiler/include/nodes/expression_nodes.h @@ -32,11 +32,10 @@ class ConstantNode : public Node } llvm::Value* codegen(impala::Toolbox& tools) override { - for (auto node: nodes) { - node->codegen(tools); - } + assert(nodes.empty() && "ConstantNode must be a leaf node"); std::cout << "ConstantNode" << std::endl; - return nullptr; + auto realType = llvm::Type::getDoubleTy(tools.context); + return llvm::ConstantFP::get(realType, value); } }; @@ -51,7 +50,10 @@ class VariableNode : public Node { llvm::Value* codegen(impala::Toolbox& tools) override { assert(nodes.size() == 0 && "VariableNode must have no children"); std::cout << "VariableNode" << std::endl; - return tools.table.find(name) != tools.table.end() ? tools.table[name] : nullptr; + if (tools.table.find(name) == tools.table.end()) { + std::runtime_error("symbol `" + name + "` have not been found"); + } + return tools.builder.CreateLoad(tools.table[name]); } }; @@ -65,11 +67,10 @@ class NegationNode : public Node } llvm::Value* codegen(impala::Toolbox& tools) override { - for (auto node: nodes) { - node->codegen(tools); - } + assert(nodes.size() == 1 && "NegationNode must be a unary operation"); + auto expr = nodes[0]->codegen(tools); std::cout << "NegationNode" << std::endl; - return nullptr; + return tools.builder.CreateFNeg(expr); } }; @@ -84,11 +85,12 @@ class AdditionNode : public Node } llvm::Value* codegen(impala::Toolbox& tools) override { - for (auto node: nodes) { - node->codegen(tools); - } + assert(nodes.size() == 2 && "AdditionNode must be a binary op"); + auto lhs = nodes[0]->codegen(tools); + auto rhs = nodes[1]->codegen(tools); + std::cout << "AdditionNode" << std::endl; - return nullptr; + return tools.builder.CreateFAdd(lhs, rhs); } }; @@ -103,11 +105,12 @@ class SubtractionNode : public Node } llvm::Value* codegen(impala::Toolbox& tools) override { - for (auto node: nodes) { - node->codegen(tools); - } + assert(nodes.size() == 2 && "SubtractionNode must be a binary op"); + auto lhs = nodes[0]->codegen(tools); + auto rhs = nodes[1]->codegen(tools); + std::cout << "SubtractionNode" << std::endl; - return nullptr; + return tools.builder.CreateFSub(lhs, rhs); } }; @@ -142,11 +145,12 @@ class DivisionNode : public Node } llvm::Value* codegen(impala::Toolbox& tools) override { - for (auto node: nodes) { - node->codegen(tools); - } + assert(nodes.size() == 2 && "DivisionNode must be a binary op"); + auto lhs = nodes[0]->codegen(tools); + auto rhs = nodes[1]->codegen(tools); + std::cout << "DivisionNode" << std::endl; - return nullptr; + return tools.builder.CreateFDiv(lhs, rhs); } }; @@ -161,9 +165,10 @@ class PowerNode : public Node } llvm::Value* codegen(impala::Toolbox& tools) override { - for (auto node: nodes) { - node->codegen(tools); - } + assert(nodes.size() == 2 && "DivisionNode must be a binary op"); + auto lhs = nodes[0]->codegen(tools); + auto rhs = nodes[1]->codegen(tools); + std::cout << "PowerNode" << std::endl; return nullptr; } diff --git a/compiler/include/nodes/external_function_nodes.h b/compiler/include/nodes/external_function_nodes.h index c98366d..74f5dc3 100644 --- a/compiler/include/nodes/external_function_nodes.h +++ b/compiler/include/nodes/external_function_nodes.h @@ -20,7 +20,9 @@ #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 @@ -41,11 +43,35 @@ class ExternalFunctionNode: public Node } llvm::Value* codegen(impala::Toolbox& tools) override { + std::stringstream errStream; + if (tools.externalMathFunctions.find(name) == tools.externalMathFunctions.end()) { + errStream << "impala: function `" << name << "` doesn't belong to the standard math library"; + throw std::runtime_error(errStream.str()); + } + + auto proto = tools.externalMathFunctions[name]; + if (nodes.size() != proto->arg_size()) { + errStream << "impala: function `" << name + << "` takes " << proto->arg_size() << " parameters, " + << "given " << nodes.size(); + throw std::runtime_error(errStream.str()); + } + + std::vector args; for (auto node: nodes) { - node->codegen(tools); + auto arg = node->codegen(tools); + if (arg) { + args.push_back(arg); + } + else { + errStream << "impala: found a statement in a list of formal parameters. " + << "Please, check `" << name << "` function call"; + throw std::runtime_error(errStream.str()); + } } + std::cout << "ExternalFunctionNode" << std::endl; - return nullptr; + return tools.builder.CreateCall(proto, args); } }; @@ -62,10 +88,8 @@ class ExternalFunctionParametersNode : public Node } llvm::Value* codegen(impala::Toolbox& tools) override { - for (auto node: nodes) { - node->codegen(tools); - } std::cout << "ExternalFunctionParametersNode" << std::endl; + throw std::runtime_error("impala: never been suported by the language"); return nullptr; } }; diff --git a/compiler/include/nodes/node.h b/compiler/include/nodes/node.h index 31894ed..87d10ab 100644 --- a/compiler/include/nodes/node.h +++ b/compiler/include/nodes/node.h @@ -52,8 +52,8 @@ class RootNode : public Node } llvm::Value* codegen(impala::Toolbox& tools) override { - for (auto node: nodes) { - node->codegen(tools); + for (auto statements: nodes) { + statements->codegen(tools); } std::cout << "Im root" << std::endl; return nullptr; diff --git a/compiler/include/toolbox.h b/compiler/include/toolbox.h index c673070..fa458e3 100644 --- a/compiler/include/toolbox.h +++ b/compiler/include/toolbox.h @@ -1,20 +1,23 @@ #ifndef IMPALA_CPP_STATE_H #define IMPALA_CPP_STATE_H -#include "llvm/IR/Value.h" +#include "engine_types.h" #include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Value.h" #include #include namespace impala { using TableT = std::unordered_map; struct Toolbox { - Toolbox(llvm::LLVMContext& context, llvm::IRBuilder<> &builder) : context(context), builder(builder) {} - Toolbox(const Toolbox& other) = default; + Toolbox(llvm::LLVMContext &context, llvm::IRBuilder<> &builder, engine::types::FunctionProtosT &externalMathFunctions) + : context(context), builder(builder), externalMathFunctions(externalMathFunctions) {} + Toolbox(const Toolbox &other) = default; llvm::IRBuilder<> &builder; llvm::LLVMContext &context; + engine::types::FunctionProtosT &externalMathFunctions; TableT table{}; }; -} +} // namespace impala -#endif //IMPALA_CPP_STATE_H +#endif // IMPALA_CPP_STATE_H diff --git a/example/cpp/example.cc b/example/cpp/example.cc index d96ffb1..92b3b24 100644 --- a/example/cpp/example.cc +++ b/example/cpp/example.cc @@ -24,7 +24,8 @@ int main() { impalajit::Compiler compiler("example.conf"); - compiler.compile(); + compiler.compileWithLLVM(); + //compiler.compile(); 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/impalajit.cc b/impalajit.cc index e50c78d..6b88f03 100644 --- a/impalajit.cc +++ b/impalajit.cc @@ -76,7 +76,7 @@ void impalajit::Compiler::loadFunctionDefinitionsFromInputFiles(std::string _con } void impalajit::Compiler::compileWithLLVM() { - auto& jit = Jit::getJit(); + auto& jit = impala::engine::Jit::getJit(); auto currentModule = jit.createModule(); std::vector functionSignature; for(auto& definition: functionDefinitions) { From f8abae8c1ebb55e7052fe58ed3a9bd2dff8b4e56 Mon Sep 17 00:00:00 2001 From: ravil Date: Thu, 3 Jun 2021 20:24:45 +0200 Subject: [PATCH 06/29] Added a simple symbol table --- compiler/include/toolbox.h | 42 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/compiler/include/toolbox.h b/compiler/include/toolbox.h index fa458e3..79a65ac 100644 --- a/compiler/include/toolbox.h +++ b/compiler/include/toolbox.h @@ -4,10 +4,52 @@ #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.push_back(TableT{});} + size_t getNumScopes() {return scopes.size();} + + llvm::Value* findSymbol(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(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; + } + } + + using TableT = std::unordered_map; + +private: + std::vector scopes{}; +}; + + using TableT = std::unordered_map; struct Toolbox { Toolbox(llvm::LLVMContext &context, llvm::IRBuilder<> &builder, engine::types::FunctionProtosT &externalMathFunctions) From f94b9b78513eec0ba730d95815eef6a75f27152a Mon Sep 17 00:00:00 2001 From: ravil Date: Fri, 4 Jun 2021 02:38:41 +0200 Subject: [PATCH 07/29] Applied symbol table. Handle returns with llvm::isa --- CMakeLists.txt | 2 +- compiler/code-gen/code_generator.cc | 2 +- compiler/engine/engine.cpp | 17 ++++++++++- compiler/include/nodes/assignment_nodes.h | 16 +++++----- compiler/include/nodes/conditional_nodes.h | 35 +++++++++++++--------- compiler/include/nodes/expression_nodes.h | 12 ++++---- compiler/include/toolbox.h | 9 +++--- 7 files changed, 57 insertions(+), 36 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 50e4235..7ed8912 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,7 +106,7 @@ if( STATIC_LIB ) set_target_properties( ${TARGET_NAME} PROPERTIES OUTPUT_NAME impalajit ) endif( STATIC_LIB ) -target_link_libraries( ${TARGET_NAME} PUBLIC ${math_library} ${LLVM_LIBS} ) +target_link_libraries( ${TARGET_NAME} PUBLIC -rdynamic -lm ${math_library} ${LLVM_LIBS}) target_include_directories( ${TARGET_NAME} PRIVATE ${LLVM_INCLUDE_DIRS} ) target_compile_definitions( ${TARGET_NAME} PRIVATE ${LLVM_DEFINITIONS} ) diff --git a/compiler/code-gen/code_generator.cc b/compiler/code-gen/code_generator.cc index 725feaa..a219798 100644 --- a/compiler/code-gen/code_generator.cc +++ b/compiler/code-gen/code_generator.cc @@ -116,7 +116,7 @@ llvm::Function* CodeGenerator::genFunctionProto(FunctionContext* &functionContex arg->setName(params[i]); auto argPtr = tools.builder.CreateAlloca(realType); - tools.table[params[i]] = argPtr; + tools.symbolTable.addSymbol(params[i], argPtr); tools.builder.CreateStore(arg, argPtr); } diff --git a/compiler/engine/engine.cpp b/compiler/engine/engine.cpp index 007b8e4..501bc6f 100644 --- a/compiler/engine/engine.cpp +++ b/compiler/engine/engine.cpp @@ -60,7 +60,22 @@ void Jit::createMathModule() { mathModule = this->createModule(); llvm::Type *realType = llvm::Type::getDoubleTy(*(context->getContext())); externalMathFunctions = StdMathLib::fillModule(mathModule, realType); - //this->addModule(mathModule); + llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); + /* + llvm::DenseSet allowList({ + (*mangle)("puts"), + (*mangle)("pow") + }); + + auto expected = llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( + dataLayout->getGlobalPrefix(), + [&allowList](const llvm::orc::SymbolStringPtr &symbol) { return allowList.count(symbol); }); + + if (!expected) { + throw std::runtime_error("impala: cannot resolve math symbols"); + } + jitDylib->addGenerator(std::move(*expected)); + */ } void Jit::addModule(std::unique_ptr &module) { diff --git a/compiler/include/nodes/assignment_nodes.h b/compiler/include/nodes/assignment_nodes.h index f78530b..cc2a302 100644 --- a/compiler/include/nodes/assignment_nodes.h +++ b/compiler/include/nodes/assignment_nodes.h @@ -41,16 +41,14 @@ class AssignmentNode : public Node assert(nodes.size() == 1 && "AssignmentNode must have one child expr"); auto expr = nodes[0]->codegen(tools); - if (tools.table.find(name) != tools.table.end()) { - auto lhs = tools.table[name]; - tools.builder.CreateStore(expr, lhs); - } - else { - // TODO: add support for scopes - auto varDef = tools.builder.CreateAlloca(llvm::Type::getDoubleTy(tools.context)); - tools.builder.CreateStore(expr, varDef); - tools.table[name] = varDef; + auto address = tools.symbolTable[name]; + if (!address) { + auto realType = llvm::Type::getDoubleTy(tools.context); + address = tools.builder.CreateAlloca(realType); + tools.symbolTable.addSymbol(name, address); } + std::cout << "AssignmentNode" << std::endl; + tools.builder.CreateStore(expr, address); return nullptr; } }; diff --git a/compiler/include/nodes/conditional_nodes.h b/compiler/include/nodes/conditional_nodes.h index 6b7a83e..a870667 100644 --- a/compiler/include/nodes/conditional_nodes.h +++ b/compiler/include/nodes/conditional_nodes.h @@ -42,8 +42,9 @@ class IfStmtNode : public Node { currFunction->getBasicBlockList().push_back(mergeBlock); tools.builder.SetInsertPoint(thenBlock); - auto lastInstr = nodes[1]->codegen(tools); - if (llvm::dyn_cast(lastInstr) != nullptr) { + nodes[1]->codegen(tools); + auto &lastInstr = tools.builder.GetInsertBlock()->back(); + if (!llvm::isa(lastInstr)) { tools.builder.CreateBr(mergeBlock); } @@ -77,15 +78,17 @@ class IfElseStmtNode : public Node { tools.builder.CreateCondBr(cond, thenBlock, elseBlock); tools.builder.SetInsertPoint(thenBlock); - auto lastThenBlockInstr = nodes[1]->codegen(tools); - bool noReturnInThenBlock = llvm::dyn_cast(lastThenBlockInstr) == nullptr; + nodes[1]->codegen(tools); + auto &lastThenBlockInstr = tools.builder.GetInsertBlock()->back(); + bool noReturnInThenBlock = !llvm::isa(lastThenBlockInstr); if (noReturnInThenBlock) { tools.builder.CreateBr(mergeBlock); } tools.builder.SetInsertPoint(elseBlock); - auto lastElseBlockInstr = nodes[2]->codegen(tools); - bool noReturnInElseBlock = llvm::dyn_cast(lastElseBlockInstr) == nullptr; + nodes[2]->codegen(tools); + auto& lastElseBlockInstr = tools.builder.GetInsertBlock()->back(); + bool noReturnInElseBlock = !llvm::isa(lastElseBlockInstr); if (noReturnInElseBlock) { tools.builder.CreateBr(mergeBlock); } @@ -107,16 +110,18 @@ class IfBodyNode : public Node { virtual ~IfBodyNode() {} llvm::Value *codegen(impala::Toolbox &tools) override { - llvm::Value *lastInstruction{nullptr}; + tools.symbolTable.addScope(); for (auto node : nodes) { - lastInstruction = node->codegen(tools); - if (llvm::dyn_cast(lastInstruction)) { + node->codegen(tools); + auto& lastInstruction = tools.builder.GetInsertBlock()->back(); + if (llvm::isa(lastInstruction)) { // a return instruction found. Doesn't make sense to generate the rest of the instructions break; } } + tools.symbolTable.removeScope(); std::cout << "IfBodyNode" << std::endl; - return lastInstruction; + return nullptr; } }; @@ -127,16 +132,18 @@ class ElseBodyNode : public Node { virtual ~ElseBodyNode() {} llvm::Value *codegen(impala::Toolbox &tools) override { - llvm::Value *lastInstruction{nullptr}; + tools.symbolTable.addScope(); for (auto node : nodes) { - lastInstruction = node->codegen(tools); - if (llvm::dyn_cast(lastInstruction)) { + node->codegen(tools); + auto &lastInstruction = tools.builder.GetInsertBlock()->back(); + if (llvm::isa(lastInstruction)) { // a return instruction found. Doesn't make sense to generate the rest of the instructions break; } } + tools.symbolTable.removeScope(); std::cout << "ElseBodyNode" << std::endl; - return lastInstruction; + return nullptr; } }; #endif // IMPALAJIT_COMPLEX_EXPRESSION_H diff --git a/compiler/include/nodes/expression_nodes.h b/compiler/include/nodes/expression_nodes.h index 03c765a..0d89fd7 100644 --- a/compiler/include/nodes/expression_nodes.h +++ b/compiler/include/nodes/expression_nodes.h @@ -48,12 +48,13 @@ class VariableNode : public Node { } llvm::Value* codegen(impala::Toolbox& tools) override { - assert(nodes.size() == 0 && "VariableNode must have no children"); - std::cout << "VariableNode" << std::endl; - if (tools.table.find(name) == tools.table.end()) { - std::runtime_error("symbol `" + name + "` have not been found"); + assert(nodes.empty() && "VariableNode must have no children"); + auto address = tools.symbolTable[name]; + if (!address) { + throw std::runtime_error("symbol `" + name + "` have not been defined"); } - return tools.builder.CreateLoad(tools.table[name]); + std::cout << "VariableNode" << std::endl; + return tools.builder.CreateLoad(address); } }; @@ -170,6 +171,7 @@ class PowerNode : public Node auto rhs = nodes[1]->codegen(tools); std::cout << "PowerNode" << std::endl; + // TODO: return result return nullptr; } }; diff --git a/compiler/include/toolbox.h b/compiler/include/toolbox.h index 79a65ac..975b71e 100644 --- a/compiler/include/toolbox.h +++ b/compiler/include/toolbox.h @@ -16,10 +16,10 @@ struct SymbolTable { SymbolTable() = default; void removeScope() { scopes.pop_back(); } - void addScope() { scopes.push_back(TableT{});} + void addScope() { scopes.emplace_back(TableT{});} size_t getNumScopes() {return scopes.size();} - llvm::Value* findSymbol(std::string name) { + 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]; @@ -28,7 +28,7 @@ struct SymbolTable { return nullptr; } - void addSymbol(std::string name, llvm::Value* value) { + void addSymbol(const std::string& name, llvm::Value* value) { if (scopes.empty()) { this->addScope(); } @@ -50,7 +50,6 @@ struct SymbolTable { }; -using TableT = std::unordered_map; struct Toolbox { Toolbox(llvm::LLVMContext &context, llvm::IRBuilder<> &builder, engine::types::FunctionProtosT &externalMathFunctions) : context(context), builder(builder), externalMathFunctions(externalMathFunctions) {} @@ -58,7 +57,7 @@ struct Toolbox { llvm::IRBuilder<> &builder; llvm::LLVMContext &context; engine::types::FunctionProtosT &externalMathFunctions; - TableT table{}; + SymbolTable symbolTable{}; }; } // namespace impala From 92bf619a68bd01b3459cba84836e895a0f48c455 Mon Sep 17 00:00:00 2001 From: ravil Date: Fri, 4 Jun 2021 12:00:28 +0200 Subject: [PATCH 08/29] Fixed external linking --- compiler/engine/engine.cpp | 26 +++----------------------- compiler/engine/engine.h | 6 ++---- compiler/engine/std_math_lib.cpp | 32 +++++++++++++++++++++++++------- compiler/engine/std_math_lib.h | 7 +++++-- 4 files changed, 35 insertions(+), 36 deletions(-) diff --git a/compiler/engine/engine.cpp b/compiler/engine/engine.cpp index 501bc6f..cf426dc 100644 --- a/compiler/engine/engine.cpp +++ b/compiler/engine/engine.cpp @@ -1,4 +1,5 @@ #include "engine.h" +#include "std_math_lib.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/PassManager.h" #include @@ -45,39 +46,18 @@ Jit::Jit() { 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()); - this->createMathModule(); } catch (const std::exception &err) { llvm::errs() << err.what() << '\n'; throw err; } } -void Jit::createMathModule() { - mathModule = this->createModule(); - llvm::Type *realType = llvm::Type::getDoubleTy(*(context->getContext())); - externalMathFunctions = StdMathLib::fillModule(mathModule, realType); - llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); - /* - llvm::DenseSet allowList({ - (*mangle)("puts"), - (*mangle)("pow") - }); - - auto expected = llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( - dataLayout->getGlobalPrefix(), - [&allowList](const llvm::orc::SymbolStringPtr &symbol) { return allowList.count(symbol); }); - - if (!expected) { - throw std::runtime_error("impala: cannot resolve math symbols"); - } - jitDylib->addGenerator(std::move(*expected)); - */ -} - void Jit::addModule(std::unique_ptr &module) { llvm::cantFail(compileLayer->add(*jitDylib, llvm::orc::ThreadSafeModule(std::move(module), *context))); } diff --git a/compiler/engine/engine.h b/compiler/engine/engine.h index ead14e3..039299c 100644 --- a/compiler/engine/engine.h +++ b/compiler/engine/engine.h @@ -1,7 +1,8 @@ #ifndef IMPALA_CPP_ENGINE_H #define IMPALA_CPP_ENGINE_H -#include "std_math_lib.h" +#include "engine_types.h" +#include "toolbox.h" #include "llvm/ADT/StringRef.h" #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/Orc/CompileUtils.h" @@ -67,8 +68,6 @@ class Jit { private: Jit(); - void createMathModule(); - llvm::orc::ExecutionSession ES; std::unique_ptr objectLayer{nullptr}; std::unique_ptr compileLayer{nullptr}; @@ -77,7 +76,6 @@ class Jit { std::unique_ptr dataLayout{nullptr}; std::unique_ptr mangle{nullptr}; std::unique_ptr context{nullptr}; - std::unique_ptr mathModule{nullptr}; types::FunctionProtosT externalMathFunctions; }; // namespace Jit } // namespace engine diff --git a/compiler/engine/std_math_lib.cpp b/compiler/engine/std_math_lib.cpp index 24739e1..2c62128 100644 --- a/compiler/engine/std_math_lib.cpp +++ b/compiler/engine/std_math_lib.cpp @@ -2,25 +2,43 @@ namespace impala { namespace engine { -decltype(StdMathLib::supportedFunctions) StdMathLib::supportedFunctions = decltype(supportedFunctions){ - {"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}}; + +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) { - return StdMathLib::supportedFunctions.find(signature) != StdMathLib::supportedFunctions.end(); + auto &supportedSet = StdMathLib::getSupportedFunctionSet(); + return supportedSet.find(signature) != supportedSet.end(); } types::FunctionProtosT StdMathLib::fillModule(std::unique_ptr &module, llvm::Type *realType) { std::unordered_map functionProtoTable; - for (const auto &signature : StdMathLib::supportedFunctions) { + 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, name, *module); + llvm::Function *function = llvm::Function::Create(functionType, llvm::Function::ExternalLinkage, realName, *module); functionProtoTable[name] = function; } diff --git a/compiler/engine/std_math_lib.h b/compiler/engine/std_math_lib.h index 12d40ef..f58acdc 100644 --- a/compiler/engine/std_math_lib.h +++ b/compiler/engine/std_math_lib.h @@ -17,8 +17,11 @@ class StdMathLib { static bool isSupported(const types::FunctionSinatureT &signature); private: - static const std::unordered_set supportedFunctions; - std::unordered_map functionTable; + using SupportedFunctionSetT = std::unordered_set; + using FunctionAliasingMapT = std::unordered_map; + + static SupportedFunctionSetT& getSupportedFunctionSet(); + static FunctionAliasingMapT& getFunctionAliasingMap(); }; } // namespace engine } // namespace impala From b38677a11f38f89ead7773a6ba9996605be2cc20 Mon Sep 17 00:00:00 2001 From: ravil Date: Fri, 4 Jun 2021 17:22:06 +0200 Subject: [PATCH 09/29] Added a factory method for toolboxes --- compiler/code-gen/code_generator.cc | 11 ++-- compiler/code-gen/include/code_generator.hh | 5 +- compiler/engine/engine.cpp | 7 ++- compiler/engine/engine.h | 15 +++++- compiler/include/nodes/assignment_nodes.h | 6 +-- compiler/include/nodes/boolean_nodes.h | 8 +-- compiler/include/nodes/compare_nodes.h | 16 +++--- compiler/include/nodes/conditional_nodes.h | 42 +++++++-------- compiler/include/nodes/expression_nodes.h | 28 +++++----- .../include/nodes/external_function_nodes.h | 6 +-- compiler/include/nodes/node.h | 6 +-- compiler/include/nodes/return_nodes.h | 4 +- compiler/include/symbol_table.h | 51 +++++++++++++++++++ 13 files changed, 139 insertions(+), 66 deletions(-) create mode 100644 compiler/include/symbol_table.h diff --git a/compiler/code-gen/code_generator.cc b/compiler/code-gen/code_generator.cc index a219798..e47af3f 100644 --- a/compiler/code-gen/code_generator.cc +++ b/compiler/code-gen/code_generator.cc @@ -73,10 +73,13 @@ void CodeGenerator::generateLLVMCode(FunctionContext* &functionContext, llvm::Mo { auto lock = jit.getLock(); + /* llvm::LLVMContext& context = jit.getContext(); auto builder = std::make_unique>(context); auto& externalFunctions = jit.getExternalMathFunctions(); impala::Toolbox tools(context, *builder, externalFunctions); + */ + impala::engine::Jit::Toolbox tools = jit.createToolbox(); auto function = this->genFunctionProto(functionContext, module, tools); functionContext->root->codegen(tools); @@ -92,7 +95,7 @@ void CodeGenerator::generateLLVMCode(FunctionContext* &functionContext, llvm::Mo llvm::Function* CodeGenerator::genFunctionProto(FunctionContext* &functionContext, llvm::Module& currModule, - impala::Toolbox &tools) { + impala::engine::Jit::Toolbox &tools) { const auto numParams = functionContext->parameters.size(); auto typeReal = llvm::Type::getDoubleTy(tools.context); @@ -107,7 +110,7 @@ llvm::Function* CodeGenerator::genFunctionProto(FunctionContext* &functionContex currModule); llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(tools.context, "entry", function); - tools.builder.SetInsertPoint(entryBlock); + tools.builder->SetInsertPoint(entryBlock); const auto& params = functionContext->parameters; auto realType = llvm::Type::getDoubleTy(tools.context); @@ -115,9 +118,9 @@ llvm::Function* CodeGenerator::genFunctionProto(FunctionContext* &functionContex llvm::Argument* arg = function->getArg(i); arg->setName(params[i]); - auto argPtr = tools.builder.CreateAlloca(realType); + auto argPtr = tools.builder->CreateAlloca(realType); tools.symbolTable.addSymbol(params[i], argPtr); - tools.builder.CreateStore(arg, argPtr); + tools.builder->CreateStore(arg, argPtr); } return function; diff --git a/compiler/code-gen/include/code_generator.hh b/compiler/code-gen/include/code_generator.hh index 769bde3..9ba929b 100644 --- a/compiler/code-gen/include/code_generator.hh +++ b/compiler/code-gen/include/code_generator.hh @@ -23,7 +23,8 @@ #include #include #include -#include +#include "engine_types.h" +#include "engine.h" #include #include #include @@ -41,7 +42,7 @@ private: llvm::Function* genFunctionProto(FunctionContext* &functionContext, llvm::Module& currModule, - impala::Toolbox &tools); + impala::engine::Jit::Toolbox &tools); /** * This functions performs the depth-first search algorithm. diff --git a/compiler/engine/engine.cpp b/compiler/engine/engine.cpp index cf426dc..5910cd7 100644 --- a/compiler/engine/engine.cpp +++ b/compiler/engine/engine.cpp @@ -64,7 +64,6 @@ void Jit::addModule(std::unique_ptr &module) { llvm::JITEvaluatedSymbol Jit::lookup(llvm::StringRef Name) { // lookup will implicitly trigger compilation for any symbol that has not already been compiled - auto &m = *mangle; llvm::Expected expected = ES.lookup({jitDylib}, (*mangle)(Name.str())); if (!expected) { llvm::errs() << expected.takeError() << '\n'; @@ -79,11 +78,17 @@ std::unique_ptr Jit::createModule() { ++counter; auto module = std::make_unique(std::move(moduleName), *context->getContext()); + + // fill with libmath function definitions llvm::Type *realType = llvm::Type::getDoubleTy(*(context->getContext())); externalMathFunctions = StdMathLib::fillModule(module, realType); 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()); diff --git a/compiler/engine/engine.h b/compiler/engine/engine.h index 039299c..c4e33ce 100644 --- a/compiler/engine/engine.h +++ b/compiler/engine/engine.h @@ -2,7 +2,7 @@ #define IMPALA_CPP_ENGINE_H #include "engine_types.h" -#include "toolbox.h" +#include "symbol_table.h" #include "llvm/ADT/StringRef.h" #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/Orc/CompileUtils.h" @@ -44,6 +44,17 @@ 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; } @@ -62,6 +73,8 @@ class Jit { types::FunctionProtosT &getExternalMathFunctions() { return externalMathFunctions; } + Jit::Toolbox createToolbox(); + static void printIRFunction(llvm::Function *function); static void printIRModule(llvm::Module &module); diff --git a/compiler/include/nodes/assignment_nodes.h b/compiler/include/nodes/assignment_nodes.h index cc2a302..d006ae7 100644 --- a/compiler/include/nodes/assignment_nodes.h +++ b/compiler/include/nodes/assignment_nodes.h @@ -37,18 +37,18 @@ class AssignmentNode : public Node } - llvm::Value* codegen(impala::Toolbox& tools) override { + llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { assert(nodes.size() == 1 && "AssignmentNode must have one child expr"); auto expr = nodes[0]->codegen(tools); auto address = tools.symbolTable[name]; if (!address) { auto realType = llvm::Type::getDoubleTy(tools.context); - address = tools.builder.CreateAlloca(realType); + address = tools.builder->CreateAlloca(realType); tools.symbolTable.addSymbol(name, address); } std::cout << "AssignmentNode" << std::endl; - tools.builder.CreateStore(expr, address); + tools.builder->CreateStore(expr, address); return nullptr; } }; diff --git a/compiler/include/nodes/boolean_nodes.h b/compiler/include/nodes/boolean_nodes.h index ff2c5b3..ae088a3 100644 --- a/compiler/include/nodes/boolean_nodes.h +++ b/compiler/include/nodes/boolean_nodes.h @@ -30,13 +30,13 @@ class BooleanAndNode : public Node { { } - llvm::Value* codegen(impala::Toolbox& tools) override { + llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { assert(nodes.size() == 2 && "BooleanAndNode must be a binary op"); auto lhs = nodes[0]->codegen(tools); auto rhs = nodes[1]->codegen(tools); std::cout << "BooleanAndNode" << std::endl; - return tools.builder.CreateAnd(lhs, rhs); + return tools.builder->CreateAnd(lhs, rhs); } }; @@ -49,13 +49,13 @@ class BooleanOrNode : public Node { { } - llvm::Value* codegen(impala::Toolbox& tools) override { + llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { assert(nodes.size() == 2 && "BooleanOrNode must be a binary op"); auto lhs = nodes[0]->codegen(tools); auto rhs = nodes[1]->codegen(tools); std::cout << "BooleanOrNode" << std::endl; - return tools.builder.CreateOr(lhs, rhs); + return tools.builder->CreateOr(lhs, rhs); } }; diff --git a/compiler/include/nodes/compare_nodes.h b/compiler/include/nodes/compare_nodes.h index 9cafa8d..4c57d89 100644 --- a/compiler/include/nodes/compare_nodes.h +++ b/compiler/include/nodes/compare_nodes.h @@ -33,7 +33,7 @@ class CompareNode : public Node nodes.push_back(_left); } - llvm::Value* codegen(impala::Toolbox& tools) override { + llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { assert(nodes.size() == 2 && "CompareNode must be a binary op"); auto lhs = nodes[0]->codegen(tools); auto rhs = nodes[1]->codegen(tools); @@ -41,32 +41,32 @@ class CompareNode : public Node llvm::Value* cmpResult{nullptr}; switch (compareOperator) { case CompareOperatorType::EQ: { - cmpResult = tools.builder.CreateFCmpOEQ(lhs, rhs); + cmpResult = tools.builder->CreateFCmpOEQ(lhs, rhs); break; } case CompareOperatorType::NE: { - cmpResult = tools.builder.CreateFCmpONE(lhs, rhs); + cmpResult = tools.builder->CreateFCmpONE(lhs, rhs); break; } case CompareOperatorType::GT: { - cmpResult = tools.builder.CreateFCmpOGT(lhs, rhs); + cmpResult = tools.builder->CreateFCmpOGT(lhs, rhs); break; } case CompareOperatorType::LT: { - cmpResult = tools.builder.CreateFCmpOLT(lhs, rhs); + cmpResult = tools.builder->CreateFCmpOLT(lhs, rhs); break; } case CompareOperatorType::GTE: { - cmpResult = tools.builder.CreateFCmpOGE(lhs, rhs); + cmpResult = tools.builder->CreateFCmpOGE(lhs, rhs); break; } case CompareOperatorType::LTE: { - cmpResult = tools.builder.CreateFCmpOLE(lhs, rhs); + cmpResult = tools.builder->CreateFCmpOLE(lhs, rhs); break; } default: { std::string msg = "Unknown comparison operator: " + std::to_string(static_cast(compareOperator)); - throw std::runtime_error(std::move(msg)); + throw std::runtime_error(msg); } } diff --git a/compiler/include/nodes/conditional_nodes.h b/compiler/include/nodes/conditional_nodes.h index a870667..4babd0a 100644 --- a/compiler/include/nodes/conditional_nodes.h +++ b/compiler/include/nodes/conditional_nodes.h @@ -29,26 +29,26 @@ class IfStmtNode : public Node { nodes.push_back(_if_body); } - llvm::Value *codegen(impala::Toolbox &tools) override { + llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { assert(nodes.size() == 2 && "IfStmtNode must have two children nodes"); auto cond = nodes[0]->codegen(tools); - auto currFunction = tools.builder.GetInsertBlock()->getParent(); + auto currFunction = tools.builder->GetInsertBlock()->getParent(); auto thenBlock = llvm::BasicBlock::Create(tools.context); auto mergeBlock = llvm::BasicBlock::Create(tools.context); - tools.builder.CreateCondBr(cond, thenBlock, mergeBlock); + tools.builder->CreateCondBr(cond, thenBlock, mergeBlock); currFunction->getBasicBlockList().push_back(thenBlock); currFunction->getBasicBlockList().push_back(mergeBlock); - tools.builder.SetInsertPoint(thenBlock); + tools.builder->SetInsertPoint(thenBlock); nodes[1]->codegen(tools); - auto &lastInstr = tools.builder.GetInsertBlock()->back(); + auto &lastInstr = tools.builder->GetInsertBlock()->back(); if (!llvm::isa(lastInstr)) { - tools.builder.CreateBr(mergeBlock); + tools.builder->CreateBr(mergeBlock); } - tools.builder.SetInsertPoint(mergeBlock); + tools.builder->SetInsertPoint(mergeBlock); std::cout << "IfStmtNode" << std::endl; return nullptr; @@ -63,11 +63,11 @@ class IfElseStmtNode : public Node { nodes.push_back(_else_body); } - llvm::Value *codegen(impala::Toolbox &tools) override { + llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { assert(nodes.size() == 3 && "IfStmtNode must have three children nodes"); auto cond = nodes[0]->codegen(tools); - auto currFunction = tools.builder.GetInsertBlock()->getParent(); + auto currFunction = tools.builder->GetInsertBlock()->getParent(); auto thenBlock = llvm::BasicBlock::Create(tools.context); auto elseBlock = llvm::BasicBlock::Create(tools.context); auto mergeBlock = llvm::BasicBlock::Create(tools.context); @@ -75,27 +75,27 @@ class IfElseStmtNode : public Node { currFunction->getBasicBlockList().push_back(thenBlock); currFunction->getBasicBlockList().push_back(elseBlock); - tools.builder.CreateCondBr(cond, thenBlock, elseBlock); + tools.builder->CreateCondBr(cond, thenBlock, elseBlock); - tools.builder.SetInsertPoint(thenBlock); + tools.builder->SetInsertPoint(thenBlock); nodes[1]->codegen(tools); - auto &lastThenBlockInstr = tools.builder.GetInsertBlock()->back(); + auto &lastThenBlockInstr = tools.builder->GetInsertBlock()->back(); bool noReturnInThenBlock = !llvm::isa(lastThenBlockInstr); if (noReturnInThenBlock) { - tools.builder.CreateBr(mergeBlock); + tools.builder->CreateBr(mergeBlock); } - tools.builder.SetInsertPoint(elseBlock); + tools.builder->SetInsertPoint(elseBlock); nodes[2]->codegen(tools); - auto& lastElseBlockInstr = tools.builder.GetInsertBlock()->back(); + auto& lastElseBlockInstr = tools.builder->GetInsertBlock()->back(); bool noReturnInElseBlock = !llvm::isa(lastElseBlockInstr); if (noReturnInElseBlock) { - tools.builder.CreateBr(mergeBlock); + tools.builder->CreateBr(mergeBlock); } if (noReturnInThenBlock || noReturnInElseBlock) { currFunction->getBasicBlockList().push_back(mergeBlock); - tools.builder.SetInsertPoint(mergeBlock); + tools.builder->SetInsertPoint(mergeBlock); } std::cout << "IfElseStmtNode" << std::endl; @@ -109,11 +109,11 @@ class IfBodyNode : public Node { virtual ~IfBodyNode() {} - llvm::Value *codegen(impala::Toolbox &tools) override { + llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { tools.symbolTable.addScope(); for (auto node : nodes) { node->codegen(tools); - auto& lastInstruction = tools.builder.GetInsertBlock()->back(); + auto& lastInstruction = tools.builder->GetInsertBlock()->back(); if (llvm::isa(lastInstruction)) { // a return instruction found. Doesn't make sense to generate the rest of the instructions break; @@ -131,11 +131,11 @@ class ElseBodyNode : public Node { virtual ~ElseBodyNode() {} - llvm::Value *codegen(impala::Toolbox &tools) override { + llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { tools.symbolTable.addScope(); for (auto node : nodes) { node->codegen(tools); - auto &lastInstruction = tools.builder.GetInsertBlock()->back(); + auto &lastInstruction = tools.builder->GetInsertBlock()->back(); if (llvm::isa(lastInstruction)) { // a return instruction found. Doesn't make sense to generate the rest of the instructions break; diff --git a/compiler/include/nodes/expression_nodes.h b/compiler/include/nodes/expression_nodes.h index 0d89fd7..cd63d09 100644 --- a/compiler/include/nodes/expression_nodes.h +++ b/compiler/include/nodes/expression_nodes.h @@ -31,7 +31,7 @@ class ConstantNode : public Node { } - llvm::Value* codegen(impala::Toolbox& tools) override { + llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { assert(nodes.empty() && "ConstantNode must be a leaf node"); std::cout << "ConstantNode" << std::endl; auto realType = llvm::Type::getDoubleTy(tools.context); @@ -47,14 +47,14 @@ class VariableNode : public Node { : Node(VARIABLE), name(_name) { } - llvm::Value* codegen(impala::Toolbox& tools) override { + llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { assert(nodes.empty() && "VariableNode must have no children"); auto address = tools.symbolTable[name]; if (!address) { throw std::runtime_error("symbol `" + name + "` have not been defined"); } std::cout << "VariableNode" << std::endl; - return tools.builder.CreateLoad(address); + return tools.builder->CreateLoad(address); } }; @@ -67,11 +67,11 @@ class NegationNode : public Node nodes.push_back(_node); } - llvm::Value* codegen(impala::Toolbox& tools) override { + llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { assert(nodes.size() == 1 && "NegationNode must be a unary operation"); auto expr = nodes[0]->codegen(tools); std::cout << "NegationNode" << std::endl; - return tools.builder.CreateFNeg(expr); + return tools.builder->CreateFNeg(expr); } }; @@ -85,13 +85,13 @@ class AdditionNode : public Node nodes.push_back(_right); } - llvm::Value* codegen(impala::Toolbox& tools) override { + llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { assert(nodes.size() == 2 && "AdditionNode must be a binary op"); auto lhs = nodes[0]->codegen(tools); auto rhs = nodes[1]->codegen(tools); std::cout << "AdditionNode" << std::endl; - return tools.builder.CreateFAdd(lhs, rhs); + return tools.builder->CreateFAdd(lhs, rhs); } }; @@ -105,13 +105,13 @@ class SubtractionNode : public Node nodes.push_back(_right); } - llvm::Value* codegen(impala::Toolbox& tools) override { + llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { assert(nodes.size() == 2 && "SubtractionNode must be a binary op"); auto lhs = nodes[0]->codegen(tools); auto rhs = nodes[1]->codegen(tools); std::cout << "SubtractionNode" << std::endl; - return tools.builder.CreateFSub(lhs, rhs); + return tools.builder->CreateFSub(lhs, rhs); } }; @@ -125,13 +125,13 @@ class MultiplicationNode : public Node nodes.push_back(_right); } - llvm::Value* codegen(impala::Toolbox& tools) override { + llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { assert(nodes.size() == 2 && "MultiplicationNode must be a binary op"); auto lhs = nodes[0]->codegen(tools); auto rhs = nodes[1]->codegen(tools); std::cout << "MultiplicationNode" << std::endl; - return tools.builder.CreateFMul(lhs, rhs); + return tools.builder->CreateFMul(lhs, rhs); } }; @@ -145,13 +145,13 @@ class DivisionNode : public Node nodes.push_back(_right); } - llvm::Value* codegen(impala::Toolbox& tools) override { + llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { assert(nodes.size() == 2 && "DivisionNode must be a binary op"); auto lhs = nodes[0]->codegen(tools); auto rhs = nodes[1]->codegen(tools); std::cout << "DivisionNode" << std::endl; - return tools.builder.CreateFDiv(lhs, rhs); + return tools.builder->CreateFDiv(lhs, rhs); } }; @@ -165,7 +165,7 @@ class PowerNode : public Node nodes.push_back(_base); } - llvm::Value* codegen(impala::Toolbox& tools) override { + llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { assert(nodes.size() == 2 && "DivisionNode must be a binary op"); auto lhs = nodes[0]->codegen(tools); auto rhs = nodes[1]->codegen(tools); diff --git a/compiler/include/nodes/external_function_nodes.h b/compiler/include/nodes/external_function_nodes.h index 74f5dc3..8587545 100644 --- a/compiler/include/nodes/external_function_nodes.h +++ b/compiler/include/nodes/external_function_nodes.h @@ -42,7 +42,7 @@ class ExternalFunctionNode: public Node { } - llvm::Value* codegen(impala::Toolbox& tools) override { + llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { std::stringstream errStream; if (tools.externalMathFunctions.find(name) == tools.externalMathFunctions.end()) { errStream << "impala: function `" << name << "` doesn't belong to the standard math library"; @@ -71,7 +71,7 @@ class ExternalFunctionNode: public Node } std::cout << "ExternalFunctionNode" << std::endl; - return tools.builder.CreateCall(proto, args); + return tools.builder->CreateCall(proto, args); } }; @@ -87,7 +87,7 @@ class ExternalFunctionParametersNode : public Node { } - llvm::Value* codegen(impala::Toolbox& tools) override { + llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { std::cout << "ExternalFunctionParametersNode" << std::endl; throw std::runtime_error("impala: never been suported by the language"); return nullptr; diff --git a/compiler/include/nodes/node.h b/compiler/include/nodes/node.h index 87d10ab..ef3b9fe 100644 --- a/compiler/include/nodes/node.h +++ b/compiler/include/nodes/node.h @@ -21,7 +21,7 @@ #define EXPRESSION_H #include -#include +#include "engine.h" #include #include @@ -40,7 +40,7 @@ class Node nodes.clear(); } - virtual llvm::Value* codegen(impala::Toolbox& tools) = 0; + virtual llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) = 0; }; class RootNode : public Node @@ -51,7 +51,7 @@ class RootNode : public Node { } - llvm::Value* codegen(impala::Toolbox& tools) override { + llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { for (auto statements: nodes) { statements->codegen(tools); } diff --git a/compiler/include/nodes/return_nodes.h b/compiler/include/nodes/return_nodes.h index f7f651e..0cce415 100644 --- a/compiler/include/nodes/return_nodes.h +++ b/compiler/include/nodes/return_nodes.h @@ -31,12 +31,12 @@ class ReturnNode : public Node nodes.push_back(_node); } - llvm::Value* codegen(impala::Toolbox& tools) override { + llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { assert(nodes.size() == 1 && "VariableNode must have one child"); std::cout << "ReturnNode" << std::endl; auto returnValue = nodes[0]->codegen(tools); - return tools.builder.CreateRet(returnValue); + return tools.builder->CreateRet(returnValue); } }; #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..8ea4396 --- /dev/null +++ b/compiler/include/symbol_table.h @@ -0,0 +1,51 @@ +#ifndef IMPALA_CPP_STATE_H +#define IMPALA_CPP_STATE_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_STATE_H From cff6c15f2515eae4c9ffb70678cc3e41509eae06 Mon Sep 17 00:00:00 2001 From: ravil Date: Fri, 4 Jun 2021 17:28:04 +0200 Subject: [PATCH 10/29] applied formating for some files --- compiler/code-gen/code_generator.cc | 554 ++++++++---------- .../code-gen/include/calculation_helper.hh | 18 +- compiler/code-gen/include/code_generator.hh | 153 +++-- compiler/engine/engine.cpp | 8 +- compiler/engine/engine_types.h | 3 +- compiler/engine/hashers.h | 11 +- compiler/engine/std_math_lib.h | 4 +- compiler/include/driver.h | 35 +- compiler/include/function_context.h | 35 +- compiler/include/nodes/assignment_nodes.h | 42 +- compiler/include/nodes/boolean_nodes.h | 49 +- compiler/include/nodes/compare_nodes.h | 95 ++- compiler/include/nodes/conditional_nodes.h | 4 +- compiler/include/nodes/expression_nodes.h | 232 ++++---- .../include/nodes/external_function_nodes.h | 99 ++-- compiler/include/nodes/node.h | 43 +- compiler/include/nodes/return_nodes.h | 23 +- compiler/include/types/internal_types.hh | 50 +- 18 files changed, 663 insertions(+), 795 deletions(-) diff --git a/compiler/code-gen/code_generator.cc b/compiler/code-gen/code_generator.cc index e47af3f..60fb2f1 100644 --- a/compiler/code-gen/code_generator.cc +++ b/compiler/code-gen/code_generator.cc @@ -18,19 +18,16 @@ */ #include "engine.h" -#include -#include +#include "llvm/IR/Verifier.h" #include +#include +#include #include +#include #include -#include #include -#include "llvm/IR/Verifier.h" #include - - - /** * @see ptr_map_container.hh */ @@ -39,36 +36,30 @@ std::map FunctionPtrMap::map; /** * @see code_generator.hh */ -CodeGenerator::CodeGenerator() { - dynamicLabelCount = 0; -} +CodeGenerator::CodeGenerator() { dynamicLabelCount = 0; } /** * @see code_generator.hh */ -CodeGenerator::~CodeGenerator() -{ -} +CodeGenerator::~CodeGenerator() {} /** * @see code_generator.hh */ -dasm_gen_func CodeGenerator::generateCode(FunctionContext* &functionContext) -{ - FunctionPtrMap::initialize_map(); +dasm_gen_func CodeGenerator::generateCode(FunctionContext *&functionContext) { + FunctionPtrMap::initialize_map(); - assembly.initialize(functionContext->parameters.size()); - assembly.prologue(); + assembly.initialize(functionContext->parameters.size()); + assembly.prologue(); - assembly.reserveMemoryForLocalVariables(functionContext->variables.size()); + assembly.reserveMemoryForLocalVariables(functionContext->variables.size()); - evaluateAst(functionContext, functionContext->root); + evaluateAst(functionContext, functionContext->root); - return assembly.linkAndEncode(); + return assembly.linkAndEncode(); } - -void CodeGenerator::generateLLVMCode(FunctionContext* &functionContext, llvm::Module& module) { +void CodeGenerator::generateLLVMCode(FunctionContext *&functionContext, llvm::Module &module) { auto &jit = impala::engine::Jit::getJit(); { auto lock = jit.getLock(); @@ -92,30 +83,26 @@ void CodeGenerator::generateLLVMCode(FunctionContext* &functionContext, llvm::Mo } } - -llvm::Function* CodeGenerator::genFunctionProto(FunctionContext* &functionContext, - llvm::Module& currModule, +llvm::Function *CodeGenerator::genFunctionProto(FunctionContext *&functionContext, llvm::Module &currModule, impala::engine::Jit::Toolbox &tools) { const auto numParams = functionContext->parameters.size(); auto typeReal = llvm::Type::getDoubleTy(tools.context); - std::vector paramTypes(numParams, typeReal); + std::vector paramTypes(numParams, typeReal); // TODO: check whether a function proto has already been added llvm::FunctionType *functionProto = llvm::FunctionType::get(typeReal, paramTypes, false); - auto function = llvm::Function::Create(functionProto, - llvm::Function::ExternalLinkage, - functionContext->name, - currModule); + auto function = + llvm::Function::Create(functionProto, llvm::Function::ExternalLinkage, functionContext->name, currModule); llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(tools.context, "entry", function); tools.builder->SetInsertPoint(entryBlock); - const auto& params = functionContext->parameters; + const auto ¶ms = functionContext->parameters; auto realType = llvm::Type::getDoubleTy(tools.context); for (size_t i = 0; i < params.size(); ++i) { - llvm::Argument* arg = function->getArg(i); + llvm::Argument *arg = function->getArg(i); arg->setName(params[i]); auto argPtr = tools.builder->CreateAlloca(realType); @@ -126,288 +113,263 @@ llvm::Function* CodeGenerator::genFunctionProto(FunctionContext* &functionContex return function; } - /** * @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; - } +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)); - } +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)); +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++; + } } - return 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; +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; } - // 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); + // 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/include/calculation_helper.hh b/compiler/code-gen/include/calculation_helper.hh index 9f4dbe3..67e3295 100644 --- a/compiler/code-gen/include/calculation_helper.hh +++ b/compiler/code-gen/include/calculation_helper.hh @@ -27,14 +27,12 @@ */ class CalculationHelper { public: - /** - * Trivial... - * - * @param value value - * @return -value - */ - static double changeSign(double value) { - return -value; - } + /** + * Trivial... + * + * @param value value + * @return -value + */ + static double changeSign(double value) { return -value; } }; -#endif //IMPALAJIT_CALCULATION_HELPER_HH +#endif // IMPALAJIT_CALCULATION_HELPER_HH diff --git a/compiler/code-gen/include/code_generator.hh b/compiler/code-gen/include/code_generator.hh index 9ba929b..818483e 100644 --- a/compiler/code-gen/include/code_generator.hh +++ b/compiler/code-gen/include/code_generator.hh @@ -20,15 +20,15 @@ #ifndef IMPALAJIT_CODE_GENERATOR_HH #define IMPALAJIT_CODE_GENERATOR_HH -#include -#include -#include -#include "engine_types.h" #include "engine.h" -#include -#include +#include "engine_types.h" #include #include +#include +#include +#include +#include +#include /** * This class traverses the AST and calls appropriate functions in the @@ -36,86 +36,85 @@ */ class CodeGenerator { private: - unsigned dynamicLabelCount; // Global count of assigned + unsigned dynamicLabelCount; // Global count of assigned - Assembly__SSE_4_1 assembly; + Assembly__SSE_4_1 assembly; - llvm::Function* genFunctionProto(FunctionContext* &functionContext, - llvm::Module& currModule, - impala::engine::Jit::Toolbox &tools); + llvm::Function *genFunctionProto(FunctionContext *&functionContext, llvm::Module &currModule, + impala::engine::Jit::Toolbox &tools); - /** - * 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); + /** + * 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); + /** + * 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); + /** + * 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); + /** + * 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(); + /** + * Constructor. Initializes the dynamic label count; + */ + CodeGenerator(); - /** - * Destructor - */ - ~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); + /** + * 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); - void generateLLVMCode(FunctionContext* &functionContext, llvm::Module& module); + void generateLLVMCode(FunctionContext *&functionContext, llvm::Module &module); }; -#endif //IMPALAJIT_CODE_GENERATOR_HH +#endif // IMPALAJIT_CODE_GENERATOR_HH diff --git a/compiler/engine/engine.cpp b/compiler/engine/engine.cpp index 5910cd7..d2bc64f 100644 --- a/compiler/engine/engine.cpp +++ b/compiler/engine/engine.cpp @@ -46,8 +46,8 @@ Jit::Jit() { const std::string dylibName{"jit_dylib"}; ES.createJITDylib(dylibName); jitDylib = ES.getJITDylibByName(dylibName); - jitDylib->addGenerator(llvm::cantFail(llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( - dataLayout->getGlobalPrefix()))); + jitDylib->addGenerator( + llvm::cantFail(llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(dataLayout->getGlobalPrefix()))); // create llvm context context = std::make_unique(std::make_unique()); @@ -85,9 +85,7 @@ std::unique_ptr Jit::createModule() { return module; } -Jit::Toolbox Jit::createToolbox() { - return Jit::Toolbox(*(context->getContext()), externalMathFunctions); -} +Jit::Toolbox Jit::createToolbox() { return Jit::Toolbox(*(context->getContext()), externalMathFunctions); } void Jit::printIRFunction(llvm::Function *function) { llvm::raw_fd_ostream stream(fileno(stdout), false); diff --git a/compiler/engine/engine_types.h b/compiler/engine/engine_types.h index a941ac8..4f43c28 100644 --- a/compiler/engine/engine_types.h +++ b/compiler/engine/engine_types.h @@ -1,7 +1,6 @@ #ifndef IMPALA_CPP_ENGINE_TYPES_H #define IMPALA_CPP_ENGINE_TYPES_H - #include "llvm/ExecutionEngine/Orc/Core.h" #include @@ -10,7 +9,7 @@ namespace engine { namespace types { using FunctionProtosT = std::unordered_map; using FunctionSinatureT = std::pair; -} +} // namespace types } // namespace engine }; // namespace impala diff --git a/compiler/engine/hashers.h b/compiler/engine/hashers.h index 4a14d1a..7a49366 100644 --- a/compiler/engine/hashers.h +++ b/compiler/engine/hashers.h @@ -7,15 +7,12 @@ #include namespace impala { -template -inline void hashValue(std::size_t &seed, const T &value) { - std::hash hasher; +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 { +template struct PairHash { std::size_t operator()(std::pair const &instance) const { std::size_t result = 0; hashValue(result, instance.first); @@ -32,6 +29,6 @@ struct FunctionSignatureHash { return result; } }; -} +} // namespace impala #endif // IMPALA_CPP_HASHERS_H diff --git a/compiler/engine/std_math_lib.h b/compiler/engine/std_math_lib.h index f58acdc..7df57d8 100644 --- a/compiler/engine/std_math_lib.h +++ b/compiler/engine/std_math_lib.h @@ -20,8 +20,8 @@ class StdMathLib { using SupportedFunctionSetT = std::unordered_set; using FunctionAliasingMapT = std::unordered_map; - static SupportedFunctionSetT& getSupportedFunctionSet(); - static FunctionAliasingMapT& getFunctionAliasingMap(); + static SupportedFunctionSetT &getSupportedFunctionSet(); + static FunctionAliasingMapT &getFunctionAliasingMap(); }; } // namespace engine } // namespace impala diff --git a/compiler/include/driver.h b/compiler/include/driver.h index 3d07c3b..7938975 100644 --- a/compiler/include/driver.h +++ b/compiler/include/driver.h @@ -20,45 +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); + std::map parse_stream(std::istream &in); - std::map parse_string(const std::string& input); + std::map parse_string(const std::string &input); - FunctionContext::FunctionSinatureT generateLLVMFunction(std::istream& in, llvm::Module& module); + FunctionContext::FunctionSinatureT generateLLVMFunction(std::istream &in, llvm::Module &module); - FunctionContext::FunctionSinatureT generateLLVMFunction(const std::string& input, llvm::Module& module); + FunctionContext::FunctionSinatureT generateLLVMFunction(const std::string &input, llvm::Module &module); - 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 30fba9a..c6864f2 100644 --- a/compiler/include/function_context.h +++ b/compiler/include/function_context.h @@ -19,36 +19,35 @@ #ifndef IMPALAJIT_FUNCTION_CONTEXT_HH #define IMPALAJIT_FUNCTION_CONTEXT_HH -#include -#include -#include #include +#include +#include +#include class FunctionContext { public: - using FunctionSinatureT = std::pair; - - 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 d006ae7..bcd6991 100644 --- a/compiler/include/nodes/assignment_nodes.h +++ b/compiler/include/nodes/assignment_nodes.h @@ -22,34 +22,26 @@ #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); - } - - virtual ~AssignmentNode() - { - } + std::string &name; + AssignmentNode(std::string &_name, Node *_node) : name(_name), Node(ASSIGNMENT) { nodes.push_back(_node); } + virtual ~AssignmentNode() {} - llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { - assert(nodes.size() == 1 && "AssignmentNode must have one child expr"); - auto expr = nodes[0]->codegen(tools); + llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { + assert(nodes.size() == 1 && "AssignmentNode must have one child expr"); + auto expr = nodes[0]->codegen(tools); - auto address = tools.symbolTable[name]; - if (!address) { - auto realType = llvm::Type::getDoubleTy(tools.context); - address = tools.builder->CreateAlloca(realType); - tools.symbolTable.addSymbol(name, address); - } - std::cout << "AssignmentNode" << std::endl; - tools.builder->CreateStore(expr, address); - return nullptr; + auto address = tools.symbolTable[name]; + if (!address) { + auto realType = llvm::Type::getDoubleTy(tools.context); + address = tools.builder->CreateAlloca(realType); + tools.symbolTable.addSymbol(name, address); } + std::cout << "AssignmentNode" << std::endl; + tools.builder->CreateStore(expr, address); + return nullptr; + } }; -#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 ae088a3..d9eeb50 100644 --- a/compiler/include/nodes/boolean_nodes.h +++ b/compiler/include/nodes/boolean_nodes.h @@ -25,38 +25,31 @@ class BooleanAndNode : public Node { public: - BooleanAndNode() - : Node(BOOLEAN_AND_JUNCTION) - { - } - - llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { - assert(nodes.size() == 2 && "BooleanAndNode must be a binary op"); - auto lhs = nodes[0]->codegen(tools); - auto rhs = nodes[1]->codegen(tools); - - std::cout << "BooleanAndNode" << std::endl; - return tools.builder->CreateAnd(lhs, rhs); - } -}; + BooleanAndNode() : Node(BOOLEAN_AND_JUNCTION) {} + + llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { + assert(nodes.size() == 2 && "BooleanAndNode must be a binary op"); + auto lhs = nodes[0]->codegen(tools); + auto rhs = nodes[1]->codegen(tools); + std::cout << "BooleanAndNode" << std::endl; + return tools.builder->CreateAnd(lhs, rhs); + } +}; class BooleanOrNode : public Node { public: - BooleanOrNode() - : Node(BOOLEAN_OR_JUNCTION) - { - } - - llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { - assert(nodes.size() == 2 && "BooleanOrNode must be a binary op"); - auto lhs = nodes[0]->codegen(tools); - auto rhs = nodes[1]->codegen(tools); - - std::cout << "BooleanOrNode" << std::endl; - return tools.builder->CreateOr(lhs, rhs); - } + BooleanOrNode() : Node(BOOLEAN_OR_JUNCTION) {} + + llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { + assert(nodes.size() == 2 && "BooleanOrNode must be a binary op"); + auto lhs = nodes[0]->codegen(tools); + auto rhs = nodes[1]->codegen(tools); + + std::cout << "BooleanOrNode" << std::endl; + return tools.builder->CreateOr(lhs, rhs); + } }; -#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 4c57d89..c7a0f74 100644 --- a/compiler/include/nodes/compare_nodes.h +++ b/compiler/include/nodes/compare_nodes.h @@ -22,58 +22,55 @@ #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); - } - - llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { - assert(nodes.size() == 2 && "CompareNode must be a binary op"); - auto lhs = nodes[0]->codegen(tools); - auto rhs = nodes[1]->codegen(tools); + CompareOperatorType compareOperator; + CompareNode(Node *_left, Node *_right, CompareOperatorType _compareOperator) + : Node(COMPARISON), compareOperator(_compareOperator) { + nodes.push_back(_right); + nodes.push_back(_left); + } - llvm::Value* cmpResult{nullptr}; - switch (compareOperator) { - case CompareOperatorType::EQ: { - cmpResult = tools.builder->CreateFCmpOEQ(lhs, rhs); - break; - } - case CompareOperatorType::NE: { - cmpResult = tools.builder->CreateFCmpONE(lhs, rhs); - break; - } - case CompareOperatorType::GT: { - cmpResult = tools.builder->CreateFCmpOGT(lhs, rhs); - break; - } - case CompareOperatorType::LT: { - cmpResult = tools.builder->CreateFCmpOLT(lhs, rhs); - break; - } - case CompareOperatorType::GTE: { - cmpResult = tools.builder->CreateFCmpOGE(lhs, rhs); - break; - } - case CompareOperatorType::LTE: { - cmpResult = tools.builder->CreateFCmpOLE(lhs, rhs); - break; - } - default: { - std::string msg = "Unknown comparison operator: " + std::to_string(static_cast(compareOperator)); - throw std::runtime_error(msg); - } - } + llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { + assert(nodes.size() == 2 && "CompareNode must be a binary op"); + auto lhs = nodes[0]->codegen(tools); + auto rhs = nodes[1]->codegen(tools); - std::cout << "CompareNode" << std::endl; - return cmpResult; + llvm::Value *cmpResult{nullptr}; + switch (compareOperator) { + case CompareOperatorType::EQ: { + cmpResult = tools.builder->CreateFCmpOEQ(lhs, rhs); + break; + } + case CompareOperatorType::NE: { + cmpResult = tools.builder->CreateFCmpONE(lhs, rhs); + break; + } + case CompareOperatorType::GT: { + cmpResult = tools.builder->CreateFCmpOGT(lhs, rhs); + break; + } + case CompareOperatorType::LT: { + cmpResult = tools.builder->CreateFCmpOLT(lhs, rhs); + break; + } + case CompareOperatorType::GTE: { + cmpResult = tools.builder->CreateFCmpOGE(lhs, rhs); + break; + } + case CompareOperatorType::LTE: { + cmpResult = tools.builder->CreateFCmpOLE(lhs, rhs); + break; + } + default: { + std::string msg = "Unknown comparison operator: " + std::to_string(static_cast(compareOperator)); + throw std::runtime_error(msg); + } } -}; + std::cout << "CompareNode" << std::endl; + return cmpResult; + } +}; -#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 4babd0a..314f75b 100644 --- a/compiler/include/nodes/conditional_nodes.h +++ b/compiler/include/nodes/conditional_nodes.h @@ -87,7 +87,7 @@ class IfElseStmtNode : public Node { tools.builder->SetInsertPoint(elseBlock); nodes[2]->codegen(tools); - auto& lastElseBlockInstr = tools.builder->GetInsertBlock()->back(); + auto &lastElseBlockInstr = tools.builder->GetInsertBlock()->back(); bool noReturnInElseBlock = !llvm::isa(lastElseBlockInstr); if (noReturnInElseBlock) { tools.builder->CreateBr(mergeBlock); @@ -113,7 +113,7 @@ class IfBodyNode : public Node { tools.symbolTable.addScope(); for (auto node : nodes) { node->codegen(tools); - auto& lastInstruction = tools.builder->GetInsertBlock()->back(); + auto &lastInstruction = tools.builder->GetInsertBlock()->back(); if (llvm::isa(lastInstruction)) { // a return instruction found. Doesn't make sense to generate the rest of the instructions break; diff --git a/compiler/include/nodes/expression_nodes.h b/compiler/include/nodes/expression_nodes.h index cd63d09..ecee03a 100644 --- a/compiler/include/nodes/expression_nodes.h +++ b/compiler/include/nodes/expression_nodes.h @@ -22,158 +22,132 @@ #include -class ConstantNode : public Node -{ +class ConstantNode : public Node { public: - double value; - explicit ConstantNode(double _value) - : Node(CONSTANT), value(_value) - { - } - - llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { - assert(nodes.empty() && "ConstantNode must be a leaf node"); - std::cout << "ConstantNode" << std::endl; - auto realType = llvm::Type::getDoubleTy(tools.context); - return llvm::ConstantFP::get(realType, value); - } + double value; + explicit ConstantNode(double _value) : Node(CONSTANT), value(_value) {} + + llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { + assert(nodes.empty() && "ConstantNode must be a leaf node"); + std::cout << "ConstantNode" << std::endl; + auto realType = llvm::Type::getDoubleTy(tools.context); + return llvm::ConstantFP::get(realType, value); + } }; class VariableNode : public Node { public: - std::string &name; - VariableNode(std::string &_name) - : Node(VARIABLE), name(_name) { - } - - llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { - assert(nodes.empty() && "VariableNode must have no children"); - auto address = tools.symbolTable[name]; - if (!address) { - throw std::runtime_error("symbol `" + name + "` have not been defined"); - } - std::cout << "VariableNode" << std::endl; - return tools.builder->CreateLoad(address); - } + std::string &name; + VariableNode(std::string &_name) : Node(VARIABLE), name(_name) {} + + llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { + assert(nodes.empty() && "VariableNode must have no children"); + auto address = tools.symbolTable[name]; + if (!address) { + throw std::runtime_error("symbol `" + name + "` have not been defined"); + } + std::cout << "VariableNode" << std::endl; + return tools.builder->CreateLoad(address); + } }; -class NegationNode : public Node -{ +class NegationNode : public Node { public: - NegationNode(Node* _node) - : Node(NEGATION) - { - nodes.push_back(_node); - } - - llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { - assert(nodes.size() == 1 && "NegationNode must be a unary operation"); - auto expr = nodes[0]->codegen(tools); - std::cout << "NegationNode" << std::endl; - return tools.builder->CreateFNeg(expr); - } + NegationNode(Node *_node) : Node(NEGATION) { nodes.push_back(_node); } + + llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { + assert(nodes.size() == 1 && "NegationNode must be a unary operation"); + auto expr = nodes[0]->codegen(tools); + std::cout << "NegationNode" << std::endl; + return tools.builder->CreateFNeg(expr); + } }; -class AdditionNode : public Node -{ +class AdditionNode : public Node { public: - AdditionNode(Node* _left, Node* _right) - : Node(ADDITION) - { - nodes.push_back(_left); - nodes.push_back(_right); - } - - llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { - assert(nodes.size() == 2 && "AdditionNode must be a binary op"); - auto lhs = nodes[0]->codegen(tools); - auto rhs = nodes[1]->codegen(tools); - - std::cout << "AdditionNode" << std::endl; - return tools.builder->CreateFAdd(lhs, rhs); - } + AdditionNode(Node *_left, Node *_right) : Node(ADDITION) { + nodes.push_back(_left); + nodes.push_back(_right); + } + + llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { + assert(nodes.size() == 2 && "AdditionNode must be a binary op"); + auto lhs = nodes[0]->codegen(tools); + auto rhs = nodes[1]->codegen(tools); + + std::cout << "AdditionNode" << std::endl; + return tools.builder->CreateFAdd(lhs, rhs); + } }; -class SubtractionNode : public Node -{ +class SubtractionNode : public Node { public: - SubtractionNode(Node* _left, Node* _right) - : Node(SUBTRACTION) - { - nodes.push_back(_left); - nodes.push_back(_right); - } - - llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { - assert(nodes.size() == 2 && "SubtractionNode must be a binary op"); - auto lhs = nodes[0]->codegen(tools); - auto rhs = nodes[1]->codegen(tools); - - std::cout << "SubtractionNode" << std::endl; - return tools.builder->CreateFSub(lhs, rhs); - } + SubtractionNode(Node *_left, Node *_right) : Node(SUBTRACTION) { + nodes.push_back(_left); + nodes.push_back(_right); + } + + llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { + assert(nodes.size() == 2 && "SubtractionNode must be a binary op"); + auto lhs = nodes[0]->codegen(tools); + auto rhs = nodes[1]->codegen(tools); + + std::cout << "SubtractionNode" << std::endl; + return tools.builder->CreateFSub(lhs, rhs); + } }; -class MultiplicationNode : public Node -{ +class MultiplicationNode : public Node { public: - MultiplicationNode(Node* _left, Node* _right) - : Node(MULTIPLICATION) - { - nodes.push_back(_left); - nodes.push_back(_right); - } - - llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { - assert(nodes.size() == 2 && "MultiplicationNode must be a binary op"); - auto lhs = nodes[0]->codegen(tools); - auto rhs = nodes[1]->codegen(tools); - - std::cout << "MultiplicationNode" << std::endl; - return tools.builder->CreateFMul(lhs, rhs); - } + MultiplicationNode(Node *_left, Node *_right) : Node(MULTIPLICATION) { + nodes.push_back(_left); + nodes.push_back(_right); + } + + llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { + assert(nodes.size() == 2 && "MultiplicationNode must be a binary op"); + auto lhs = nodes[0]->codegen(tools); + auto rhs = nodes[1]->codegen(tools); + + std::cout << "MultiplicationNode" << std::endl; + return tools.builder->CreateFMul(lhs, rhs); + } }; -class DivisionNode : public Node -{ +class DivisionNode : public Node { public: - DivisionNode(Node* &_left, Node* &_right) - : Node(DIVISION) - { - nodes.push_back(_left); - nodes.push_back(_right); - } - - llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { - assert(nodes.size() == 2 && "DivisionNode must be a binary op"); - auto lhs = nodes[0]->codegen(tools); - auto rhs = nodes[1]->codegen(tools); - - std::cout << "DivisionNode" << std::endl; - return tools.builder->CreateFDiv(lhs, rhs); - } + DivisionNode(Node *&_left, Node *&_right) : Node(DIVISION) { + nodes.push_back(_left); + nodes.push_back(_right); + } + + llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { + assert(nodes.size() == 2 && "DivisionNode must be a binary op"); + auto lhs = nodes[0]->codegen(tools); + auto rhs = nodes[1]->codegen(tools); + + std::cout << "DivisionNode" << std::endl; + return tools.builder->CreateFDiv(lhs, rhs); + } }; -class PowerNode : public Node -{ +class PowerNode : public Node { public: - PowerNode(Node* _base, Node* _exponent) - : Node(POWER) - { - nodes.push_back(_exponent); - nodes.push_back(_base); - } - - llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { - assert(nodes.size() == 2 && "DivisionNode must be a binary op"); - auto lhs = nodes[0]->codegen(tools); - auto rhs = nodes[1]->codegen(tools); - - std::cout << "PowerNode" << std::endl; - // TODO: return result - return nullptr; - } + PowerNode(Node *_base, Node *_exponent) : Node(POWER) { + nodes.push_back(_exponent); + nodes.push_back(_base); + } + + llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { + assert(nodes.size() == 2 && "DivisionNode must be a binary op"); + auto lhs = nodes[0]->codegen(tools); + auto rhs = nodes[1]->codegen(tools); + + std::cout << "PowerNode" << std::endl; + // TODO: return result + return nullptr; + } }; -#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 8587545..d1020b7 100644 --- a/compiler/include/nodes/external_function_nodes.h +++ b/compiler/include/nodes/external_function_nodes.h @@ -22,77 +22,60 @@ #include "node.h" #include "std_math_lib.h" -#include #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() {} + + llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { + std::stringstream errStream; + if (tools.externalMathFunctions.find(name) == tools.externalMathFunctions.end()) { + errStream << "impala: function `" << name << "` doesn't belong to the standard math library"; + throw std::runtime_error(errStream.str()); } - llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { - std::stringstream errStream; - if (tools.externalMathFunctions.find(name) == tools.externalMathFunctions.end()) { - errStream << "impala: function `" << name << "` doesn't belong to the standard math library"; - throw std::runtime_error(errStream.str()); - } + auto proto = tools.externalMathFunctions[name]; + if (nodes.size() != proto->arg_size()) { + errStream << "impala: function `" << name << "` takes " << proto->arg_size() << " parameters, " + << "given " << nodes.size(); + throw std::runtime_error(errStream.str()); + } - auto proto = tools.externalMathFunctions[name]; - if (nodes.size() != proto->arg_size()) { - errStream << "impala: function `" << name - << "` takes " << proto->arg_size() << " parameters, " - << "given " << nodes.size(); + std::vector args; + for (auto node : nodes) { + auto arg = node->codegen(tools); + if (arg) { + args.push_back(arg); + } else { + errStream << "impala: found a statement in a list of formal parameters. " + << "Please, check `" << name << "` function call"; throw std::runtime_error(errStream.str()); } - - std::vector args; - for (auto node: nodes) { - auto arg = node->codegen(tools); - if (arg) { - args.push_back(arg); - } - else { - errStream << "impala: found a statement in a list of formal parameters. " - << "Please, check `" << name << "` function call"; - throw std::runtime_error(errStream.str()); - } - } - - std::cout << "ExternalFunctionNode" << std::endl; - return tools.builder->CreateCall(proto, args); } + + std::cout << "ExternalFunctionNode" << std::endl; + return tools.builder->CreateCall(proto, args); + } }; -class ExternalFunctionParametersNode : public Node -{ +class ExternalFunctionParametersNode : public Node { public: - ExternalFunctionParametersNode() - : Node(EXTERNAL_FUNCTION_PARAMETER) - { - } + ExternalFunctionParametersNode() : Node(EXTERNAL_FUNCTION_PARAMETER) {} - virtual ~ExternalFunctionParametersNode() - { - } + virtual ~ExternalFunctionParametersNode() {} - llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { - std::cout << "ExternalFunctionParametersNode" << std::endl; - throw std::runtime_error("impala: never been suported by the language"); - return nullptr; - } + llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { + std::cout << "ExternalFunctionParametersNode" << std::endl; + throw std::runtime_error("impala: never been suported by the language"); + return nullptr; + } }; - -#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 ef3b9fe..3aecaa9 100644 --- a/compiler/include/nodes/node.h +++ b/compiler/include/nodes/node.h @@ -20,44 +20,33 @@ #ifndef EXPRESSION_H #define EXPRESSION_H -#include #include "engine.h" -#include +#include #include +#include -class Node -{ +class Node { public: - NodeType nodeType; - std::vector nodes; + NodeType nodeType; + std::vector nodes; - Node(NodeType _nodeType) : - nodeType(_nodeType) - { - } - virtual ~Node() - { - nodes.clear(); - } + Node(NodeType _nodeType) : nodeType(_nodeType) {} + virtual ~Node() { nodes.clear(); } - virtual llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) = 0; + virtual llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) = 0; }; -class RootNode : public Node -{ +class RootNode : public Node { public: - RootNode() - : Node(ROOT) - { - } + RootNode() : Node(ROOT) {} - llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { - for (auto statements: nodes) { - statements->codegen(tools); - } - std::cout << "Im root" << std::endl; - return nullptr; + llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { + for (auto statements : nodes) { + statements->codegen(tools); } + std::cout << "Im root" << std::endl; + return nullptr; + } }; #endif // EXPRESSION_H diff --git a/compiler/include/nodes/return_nodes.h b/compiler/include/nodes/return_nodes.h index 0cce415..e5d9f65 100644 --- a/compiler/include/nodes/return_nodes.h +++ b/compiler/include/nodes/return_nodes.h @@ -22,21 +22,16 @@ #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); } - llvm::Value* codegen(impala::engine::Jit::Toolbox& tools) override { - assert(nodes.size() == 1 && "VariableNode must have one child"); - std::cout << "ReturnNode" << std::endl; + llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { + assert(nodes.size() == 1 && "VariableNode must have one child"); + std::cout << "ReturnNode" << std::endl; - auto returnValue = nodes[0]->codegen(tools); - return tools.builder->CreateRet(returnValue); - } + auto returnValue = nodes[0]->codegen(tools); + return tools.builder->CreateRet(returnValue); + } }; -#endif //IMPALAJIT_RETURN_NODE_H +#endif // IMPALAJIT_RETURN_NODE_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 From d908899f69713d15a1ae814d3cb6b8d87b830d4a Mon Sep 17 00:00:00 2001 From: ravil Date: Fri, 4 Jun 2021 22:07:00 +0200 Subject: [PATCH 11/29] Switched to google tests --- CMakeLists.txt | 7 +- compiler/code-gen/code_generator.cc | 10 +- compiler/include/nodes/compare_nodes.h | 4 +- compiler/include/symbol_table.h | 6 +- compiler/include/toolbox.h | 64 ---------- example/cpp/example.cc | 2 +- impalajit.cc | 4 +- include/impalajit.hh | 2 +- tests/CMakeLists.txt | 62 +++------- tests/assignments.cc | 51 -------- tests/basic.cpp | 55 +++++++++ tests/complex_conditionals.cpp | 80 ++++++++++++ tests/conditionals_complex_1.cc | 58 --------- tests/conditionals_complex_2.cc | 58 --------- tests/conditionals_eq.cc | 44 ------- tests/conditionals_gt.cc | 43 ------- tests/conditionals_gte.cc | 43 ------- tests/conditionals_lt.cc | 44 ------- tests/conditionals_lte.cc | 43 ------- tests/conditionals_neq.cc | 44 ------- tests/conditionals_nested.cc | 44 ------- tests/definitions.h | 6 + tests/expressions_basic.cc | 52 -------- tests/impala_files/assignment.impala | 2 +- tests/impala_files/four_params.impala | 10 ++ ...on_basic.impala => math_expression.impala} | 2 +- tests/impala_files/seven_params.impala | 5 + tests/include/defines.hh | 25 ---- tests/include/double_comparison.hh | 23 ---- tests/main.cpp | 6 + tests/many_if.cc | 114 ------------------ tests/many_ifs.cpp | 98 +++++++++++++++ tests/multiple_functions.cc | 73 ----------- tests/multiple_functions.cpp | 43 +++++++ tests/parameter_count.cc | 43 ------- tests/parameter_count.cpp | 20 +++ tests/simple_conditionals.cpp | 99 +++++++++++++++ 37 files changed, 456 insertions(+), 933 deletions(-) delete mode 100644 compiler/include/toolbox.h delete mode 100644 tests/assignments.cc create mode 100644 tests/basic.cpp create mode 100644 tests/complex_conditionals.cpp delete mode 100644 tests/conditionals_complex_1.cc delete mode 100644 tests/conditionals_complex_2.cc delete mode 100644 tests/conditionals_eq.cc delete mode 100644 tests/conditionals_gt.cc delete mode 100644 tests/conditionals_gte.cc delete mode 100644 tests/conditionals_lt.cc delete mode 100644 tests/conditionals_lte.cc delete mode 100644 tests/conditionals_neq.cc delete mode 100644 tests/conditionals_nested.cc create mode 100644 tests/definitions.h delete mode 100644 tests/expressions_basic.cc create mode 100644 tests/impala_files/four_params.impala rename tests/impala_files/{expression_basic.impala => math_expression.impala} (73%) create mode 100644 tests/impala_files/seven_params.impala delete mode 100644 tests/include/defines.hh delete mode 100644 tests/include/double_comparison.hh create mode 100644 tests/main.cpp delete mode 100644 tests/many_if.cc create mode 100644 tests/many_ifs.cpp delete mode 100644 tests/multiple_functions.cc create mode 100644 tests/multiple_functions.cpp delete mode 100644 tests/parameter_count.cc create mode 100644 tests/parameter_count.cpp create mode 100644 tests/simple_conditionals.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ed8912..4aa135b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,10 +111,11 @@ target_include_directories( ${TARGET_NAME} PRIVATE ${LLVM_INCLUDE_DIRS} ) target_compile_definitions( ${TARGET_NAME} PRIVATE ${LLVM_DEFINITIONS} ) # Tests -if( TESTS ) +if (TESTS) enable_testing() - add_subdirectory( tests ) -endif( TESTS ) + add_subdirectory(tests) +endif() + # install target install( TARGETS ${TARGET_NAME} DESTINATION lib ) diff --git a/compiler/code-gen/code_generator.cc b/compiler/code-gen/code_generator.cc index 60fb2f1..d579fbc 100644 --- a/compiler/code-gen/code_generator.cc +++ b/compiler/code-gen/code_generator.cc @@ -63,20 +63,12 @@ void CodeGenerator::generateLLVMCode(FunctionContext *&functionContext, llvm::Mo auto &jit = impala::engine::Jit::getJit(); { auto lock = jit.getLock(); - - /* - llvm::LLVMContext& context = jit.getContext(); - auto builder = std::make_unique>(context); - auto& externalFunctions = jit.getExternalMathFunctions(); - impala::Toolbox tools(context, *builder, externalFunctions); - */ impala::engine::Jit::Toolbox tools = jit.createToolbox(); - auto function = this->genFunctionProto(functionContext, module, tools); functionContext->root->codegen(tools); llvm::verifyFunction(*function, &llvm::outs()); - impala::engine::Jit::printIRModule(module); + impala::engine::Jit::printIRFunction(function); // TODO: delete this one (memory de-allocation bug) generateCode(functionContext); diff --git a/compiler/include/nodes/compare_nodes.h b/compiler/include/nodes/compare_nodes.h index c7a0f74..78d1d49 100644 --- a/compiler/include/nodes/compare_nodes.h +++ b/compiler/include/nodes/compare_nodes.h @@ -33,8 +33,8 @@ class CompareNode : public Node { llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { assert(nodes.size() == 2 && "CompareNode must be a binary op"); - auto lhs = nodes[0]->codegen(tools); - auto rhs = nodes[1]->codegen(tools); + auto lhs = nodes[1]->codegen(tools); + auto rhs = nodes[0]->codegen(tools); llvm::Value *cmpResult{nullptr}; switch (compareOperator) { diff --git a/compiler/include/symbol_table.h b/compiler/include/symbol_table.h index 8ea4396..8558a20 100644 --- a/compiler/include/symbol_table.h +++ b/compiler/include/symbol_table.h @@ -1,5 +1,5 @@ -#ifndef IMPALA_CPP_STATE_H -#define IMPALA_CPP_STATE_H +#ifndef IMPALA_CPP_SYMBOL_TABLE_H +#define IMPALA_CPP_SYMBOL_TABLE_H #include "engine_types.h" #include "llvm/IR/IRBuilder.h" @@ -48,4 +48,4 @@ struct SymbolTable { }; } // namespace impala -#endif // IMPALA_CPP_STATE_H +#endif // IMPALA_CPP_SYMBOL_TABLE_H diff --git a/compiler/include/toolbox.h b/compiler/include/toolbox.h deleted file mode 100644 index 975b71e..0000000 --- a/compiler/include/toolbox.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef IMPALA_CPP_STATE_H -#define IMPALA_CPP_STATE_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; - } - } - - using TableT = std::unordered_map; - -private: - std::vector scopes{}; -}; - - -struct Toolbox { - Toolbox(llvm::LLVMContext &context, llvm::IRBuilder<> &builder, engine::types::FunctionProtosT &externalMathFunctions) - : context(context), builder(builder), externalMathFunctions(externalMathFunctions) {} - Toolbox(const Toolbox &other) = default; - llvm::IRBuilder<> &builder; - llvm::LLVMContext &context; - engine::types::FunctionProtosT &externalMathFunctions; - SymbolTable symbolTable{}; -}; -} // namespace impala - -#endif // IMPALA_CPP_STATE_H diff --git a/example/cpp/example.cc b/example/cpp/example.cc index 92b3b24..082269c 100644 --- a/example/cpp/example.cc +++ b/example/cpp/example.cc @@ -24,7 +24,7 @@ int main() { impalajit::Compiler compiler("example.conf"); - compiler.compileWithLLVM(); + compiler.compile(); //compiler.compile(); dasm_gen_func example = compiler.getFunction("example"); std::cout << "Result: " << example(3.0, 4.0) << std::endl; diff --git a/impalajit.cc b/impalajit.cc index 6b88f03..f9bf0f5 100644 --- a/impalajit.cc +++ b/impalajit.cc @@ -75,7 +75,7 @@ void impalajit::Compiler::loadFunctionDefinitionsFromInputFiles(std::string _con } } -void impalajit::Compiler::compileWithLLVM() { +void impalajit::Compiler::compile() { auto& jit = impala::engine::Jit::getJit(); auto currentModule = jit.createModule(); std::vector functionSignature; @@ -92,7 +92,7 @@ void impalajit::Compiler::compileWithLLVM() { } } -void impalajit::Compiler::compile(){ +void impalajit::Compiler::compileLegacy(){ for(auto& definition: functionDefinitions) { auto parsedFunctions = driver.parse_string(definition); functionMap.insert(parsedFunctions.begin(), parsedFunctions.end()); diff --git a/include/impalajit.hh b/include/impalajit.hh index 932e2f0..2a1abd2 100644 --- a/include/impalajit.hh +++ b/include/impalajit.hh @@ -47,8 +47,8 @@ public: Compiler(std::vector _functionDefinitions); Compiler(); + void compileLegacy(); void compile(); - void compileWithLLVM(); dasm_gen_func getFunction(std::string functionName); unsigned int getParameterCount(std::string functionName); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f99c7c8..1ad5c43 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 ${TARGET_NAME} ) -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 ${TARGET_NAME} ${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 ${TARGET_NAME} ${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) \ No newline at end of file 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/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/defines.hh b/tests/include/defines.hh deleted file mode 100644 index 4b392ad..0000000 --- a/tests/include/defines.hh +++ /dev/null @@ -1,25 +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_DEFINES_HH -#define IMPALAJIT_DEFINES_HH - -#define CONFIG_FILE_PATH "../../tests/conf/impala.conf" - -#endif //IMPALAJIT_DEFINES_HH 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 - * 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 From 34522be82d87942c911d113011c3e80121f10317 Mon Sep 17 00:00:00 2001 From: ravil Date: Sat, 5 Jun 2021 02:57:47 +0200 Subject: [PATCH 12/29] Added visitors --- .gitignore | 1 + CMakeLists.txt | 2 + compiler/code-gen/code_generator.cc | 10 +- compiler/code-gen/codegen_visitor.cpp | 285 ++++++++++++++++++ compiler/code-gen/include/abstract_visitor.h | 52 ++++ compiler/code-gen/include/codegen_visitor.h | 45 +++ compiler/code-gen/include/pretty_printer.h | 42 +++ compiler/code-gen/pretty_printer.cpp | 195 ++++++++++++ compiler/include/nodes/assignment_nodes.h | 15 +- compiler/include/nodes/boolean_nodes.h | 18 +- compiler/include/nodes/compare_nodes.h | 41 +-- compiler/include/nodes/conditional_nodes.h | 94 +----- compiler/include/nodes/expression_nodes.h | 71 ++--- .../include/nodes/external_function_nodes.h | 37 +-- compiler/include/nodes/node.h | 12 +- compiler/include/nodes/return_nodes.h | 8 +- 16 files changed, 676 insertions(+), 252 deletions(-) create mode 100644 compiler/code-gen/codegen_visitor.cpp create mode 100644 compiler/code-gen/include/abstract_visitor.h create mode 100644 compiler/code-gen/include/codegen_visitor.h create mode 100644 compiler/code-gen/include/pretty_printer.h create mode 100644 compiler/code-gen/pretty_printer.cpp diff --git a/.gitignore b/.gitignore index 583e1b4..0d0dbad 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ minilua build lib/* cmake-build-* +.vscode diff --git a/CMakeLists.txt b/CMakeLists.txt index 4aa135b..e4574b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,8 @@ set(source_files ${source_files} compiler/code-gen/include/calculation_helper.hh compiler/code-gen/code_generator.cc compiler/code-gen/assembly/assembly__sse_4_1.cc + compiler/code-gen/codegen_visitor.cpp + compiler/code-gen/pretty_printer.cpp compiler/engine/engine.cpp compiler/engine/std_math_lib.cpp) diff --git a/compiler/code-gen/code_generator.cc b/compiler/code-gen/code_generator.cc index d579fbc..5778f4b 100644 --- a/compiler/code-gen/code_generator.cc +++ b/compiler/code-gen/code_generator.cc @@ -18,6 +18,8 @@ */ #include "engine.h" +#include "pretty_printer.h" +#include "codegen_visitor.h" #include "llvm/IR/Verifier.h" #include #include @@ -60,12 +62,18 @@ dasm_gen_func CodeGenerator::generateCode(FunctionContext *&functionContext) { } void CodeGenerator::generateLLVMCode(FunctionContext *&functionContext, llvm::Module &module) { + 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(); + auto function = this->genFunctionProto(functionContext, module, tools); - functionContext->root->codegen(tools); + impala::CodegenVisitor codegenVisitor(tools); + functionContext->root->accept(&codegenVisitor); llvm::verifyFunction(*function, &llvm::outs()); impala::engine::Jit::printIRFunction(function); diff --git a/compiler/code-gen/codegen_visitor.cpp b/compiler/code-gen/codegen_visitor.cpp new file mode 100644 index 0000000..42cab08 --- /dev/null +++ b/compiler/code-gen/codegen_visitor.cpp @@ -0,0 +1,285 @@ +#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"); + auto realType = llvm::Type::getDoubleTy(toolbox.context); + 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) { + auto realType = llvm::Type::getDoubleTy(toolbox.context); + 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..fd27696 --- /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; + }; +} + +#endif //IMPALA_CPP_ABSTRACTVISITOR_H diff --git a/compiler/code-gen/include/codegen_visitor.h b/compiler/code-gen/include/codegen_visitor.h new file mode 100644 index 0000000..3db4e15 --- /dev/null +++ b/compiler/code-gen/include/codegen_visitor.h @@ -0,0 +1,45 @@ +#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) : toolbox(tools) {} + 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; +}; +} // 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/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/include/nodes/assignment_nodes.h b/compiler/include/nodes/assignment_nodes.h index bcd6991..e73dd49 100644 --- a/compiler/include/nodes/assignment_nodes.h +++ b/compiler/include/nodes/assignment_nodes.h @@ -29,19 +29,8 @@ class AssignmentNode : public Node { virtual ~AssignmentNode() {} - llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { - assert(nodes.size() == 1 && "AssignmentNode must have one child expr"); - auto expr = nodes[0]->codegen(tools); - - auto address = tools.symbolTable[name]; - if (!address) { - auto realType = llvm::Type::getDoubleTy(tools.context); - address = tools.builder->CreateAlloca(realType); - tools.symbolTable.addSymbol(name, address); - } - std::cout << "AssignmentNode" << std::endl; - tools.builder->CreateStore(expr, address); - return nullptr; + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); } }; #endif // IMPALAJIT_ASSIGNMENT_EXPRESSION_HH diff --git a/compiler/include/nodes/boolean_nodes.h b/compiler/include/nodes/boolean_nodes.h index d9eeb50..8269e68 100644 --- a/compiler/include/nodes/boolean_nodes.h +++ b/compiler/include/nodes/boolean_nodes.h @@ -27,13 +27,8 @@ class BooleanAndNode : public Node { public: BooleanAndNode() : Node(BOOLEAN_AND_JUNCTION) {} - llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { - assert(nodes.size() == 2 && "BooleanAndNode must be a binary op"); - auto lhs = nodes[0]->codegen(tools); - auto rhs = nodes[1]->codegen(tools); - - std::cout << "BooleanAndNode" << std::endl; - return tools.builder->CreateAnd(lhs, rhs); + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); } }; @@ -42,13 +37,8 @@ class BooleanOrNode : public Node { public: BooleanOrNode() : Node(BOOLEAN_OR_JUNCTION) {} - llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { - assert(nodes.size() == 2 && "BooleanOrNode must be a binary op"); - auto lhs = nodes[0]->codegen(tools); - auto rhs = nodes[1]->codegen(tools); - - std::cout << "BooleanOrNode" << std::endl; - return tools.builder->CreateOr(lhs, rhs); + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); } }; diff --git a/compiler/include/nodes/compare_nodes.h b/compiler/include/nodes/compare_nodes.h index 78d1d49..8d62582 100644 --- a/compiler/include/nodes/compare_nodes.h +++ b/compiler/include/nodes/compare_nodes.h @@ -31,45 +31,8 @@ class CompareNode : public Node { nodes.push_back(_left); } - llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { - assert(nodes.size() == 2 && "CompareNode must be a binary op"); - auto lhs = nodes[1]->codegen(tools); - auto rhs = nodes[0]->codegen(tools); - - llvm::Value *cmpResult{nullptr}; - switch (compareOperator) { - case CompareOperatorType::EQ: { - cmpResult = tools.builder->CreateFCmpOEQ(lhs, rhs); - break; - } - case CompareOperatorType::NE: { - cmpResult = tools.builder->CreateFCmpONE(lhs, rhs); - break; - } - case CompareOperatorType::GT: { - cmpResult = tools.builder->CreateFCmpOGT(lhs, rhs); - break; - } - case CompareOperatorType::LT: { - cmpResult = tools.builder->CreateFCmpOLT(lhs, rhs); - break; - } - case CompareOperatorType::GTE: { - cmpResult = tools.builder->CreateFCmpOGE(lhs, rhs); - break; - } - case CompareOperatorType::LTE: { - cmpResult = tools.builder->CreateFCmpOLE(lhs, rhs); - break; - } - default: { - std::string msg = "Unknown comparison operator: " + std::to_string(static_cast(compareOperator)); - throw std::runtime_error(msg); - } - } - - std::cout << "CompareNode" << std::endl; - return cmpResult; + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); } }; diff --git a/compiler/include/nodes/conditional_nodes.h b/compiler/include/nodes/conditional_nodes.h index 314f75b..9fb0dc7 100644 --- a/compiler/include/nodes/conditional_nodes.h +++ b/compiler/include/nodes/conditional_nodes.h @@ -29,29 +29,8 @@ class IfStmtNode : public Node { nodes.push_back(_if_body); } - llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { - assert(nodes.size() == 2 && "IfStmtNode must have two children nodes"); - auto cond = nodes[0]->codegen(tools); - - auto currFunction = tools.builder->GetInsertBlock()->getParent(); - auto thenBlock = llvm::BasicBlock::Create(tools.context); - auto mergeBlock = llvm::BasicBlock::Create(tools.context); - tools.builder->CreateCondBr(cond, thenBlock, mergeBlock); - - currFunction->getBasicBlockList().push_back(thenBlock); - currFunction->getBasicBlockList().push_back(mergeBlock); - - tools.builder->SetInsertPoint(thenBlock); - nodes[1]->codegen(tools); - auto &lastInstr = tools.builder->GetInsertBlock()->back(); - if (!llvm::isa(lastInstr)) { - tools.builder->CreateBr(mergeBlock); - } - - tools.builder->SetInsertPoint(mergeBlock); - - std::cout << "IfStmtNode" << std::endl; - return nullptr; + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); } }; @@ -63,43 +42,8 @@ class IfElseStmtNode : public Node { nodes.push_back(_else_body); } - llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { - assert(nodes.size() == 3 && "IfStmtNode must have three children nodes"); - auto cond = nodes[0]->codegen(tools); - - auto currFunction = tools.builder->GetInsertBlock()->getParent(); - auto thenBlock = llvm::BasicBlock::Create(tools.context); - auto elseBlock = llvm::BasicBlock::Create(tools.context); - auto mergeBlock = llvm::BasicBlock::Create(tools.context); - - currFunction->getBasicBlockList().push_back(thenBlock); - currFunction->getBasicBlockList().push_back(elseBlock); - - tools.builder->CreateCondBr(cond, thenBlock, elseBlock); - - tools.builder->SetInsertPoint(thenBlock); - nodes[1]->codegen(tools); - auto &lastThenBlockInstr = tools.builder->GetInsertBlock()->back(); - bool noReturnInThenBlock = !llvm::isa(lastThenBlockInstr); - if (noReturnInThenBlock) { - tools.builder->CreateBr(mergeBlock); - } - - tools.builder->SetInsertPoint(elseBlock); - nodes[2]->codegen(tools); - auto &lastElseBlockInstr = tools.builder->GetInsertBlock()->back(); - bool noReturnInElseBlock = !llvm::isa(lastElseBlockInstr); - if (noReturnInElseBlock) { - tools.builder->CreateBr(mergeBlock); - } - - if (noReturnInThenBlock || noReturnInElseBlock) { - currFunction->getBasicBlockList().push_back(mergeBlock); - tools.builder->SetInsertPoint(mergeBlock); - } - - std::cout << "IfElseStmtNode" << std::endl; - return nullptr; + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); } }; @@ -109,19 +53,8 @@ class IfBodyNode : public Node { virtual ~IfBodyNode() {} - llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { - tools.symbolTable.addScope(); - for (auto node : nodes) { - node->codegen(tools); - auto &lastInstruction = tools.builder->GetInsertBlock()->back(); - if (llvm::isa(lastInstruction)) { - // a return instruction found. Doesn't make sense to generate the rest of the instructions - break; - } - } - tools.symbolTable.removeScope(); - std::cout << "IfBodyNode" << std::endl; - return nullptr; + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); } }; @@ -131,19 +64,8 @@ class ElseBodyNode : public Node { virtual ~ElseBodyNode() {} - llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { - tools.symbolTable.addScope(); - for (auto node : nodes) { - node->codegen(tools); - auto &lastInstruction = tools.builder->GetInsertBlock()->back(); - if (llvm::isa(lastInstruction)) { - // a return instruction found. Doesn't make sense to generate the rest of the instructions - break; - } - } - tools.symbolTable.removeScope(); - std::cout << "ElseBodyNode" << std::endl; - return nullptr; + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); } }; #endif // IMPALAJIT_COMPLEX_EXPRESSION_H diff --git a/compiler/include/nodes/expression_nodes.h b/compiler/include/nodes/expression_nodes.h index ecee03a..7d67dc8 100644 --- a/compiler/include/nodes/expression_nodes.h +++ b/compiler/include/nodes/expression_nodes.h @@ -27,11 +27,8 @@ class ConstantNode : public Node { double value; explicit ConstantNode(double _value) : Node(CONSTANT), value(_value) {} - llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { - assert(nodes.empty() && "ConstantNode must be a leaf node"); - std::cout << "ConstantNode" << std::endl; - auto realType = llvm::Type::getDoubleTy(tools.context); - return llvm::ConstantFP::get(realType, value); + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); } }; @@ -41,14 +38,8 @@ class VariableNode : public Node { std::string &name; VariableNode(std::string &_name) : Node(VARIABLE), name(_name) {} - llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { - assert(nodes.empty() && "VariableNode must have no children"); - auto address = tools.symbolTable[name]; - if (!address) { - throw std::runtime_error("symbol `" + name + "` have not been defined"); - } - std::cout << "VariableNode" << std::endl; - return tools.builder->CreateLoad(address); + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); } }; @@ -56,11 +47,8 @@ class NegationNode : public Node { public: NegationNode(Node *_node) : Node(NEGATION) { nodes.push_back(_node); } - llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { - assert(nodes.size() == 1 && "NegationNode must be a unary operation"); - auto expr = nodes[0]->codegen(tools); - std::cout << "NegationNode" << std::endl; - return tools.builder->CreateFNeg(expr); + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); } }; @@ -71,13 +59,8 @@ class AdditionNode : public Node { nodes.push_back(_right); } - llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { - assert(nodes.size() == 2 && "AdditionNode must be a binary op"); - auto lhs = nodes[0]->codegen(tools); - auto rhs = nodes[1]->codegen(tools); - - std::cout << "AdditionNode" << std::endl; - return tools.builder->CreateFAdd(lhs, rhs); + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); } }; @@ -88,13 +71,8 @@ class SubtractionNode : public Node { nodes.push_back(_right); } - llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { - assert(nodes.size() == 2 && "SubtractionNode must be a binary op"); - auto lhs = nodes[0]->codegen(tools); - auto rhs = nodes[1]->codegen(tools); - - std::cout << "SubtractionNode" << std::endl; - return tools.builder->CreateFSub(lhs, rhs); + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); } }; @@ -105,13 +83,8 @@ class MultiplicationNode : public Node { nodes.push_back(_right); } - llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { - assert(nodes.size() == 2 && "MultiplicationNode must be a binary op"); - auto lhs = nodes[0]->codegen(tools); - auto rhs = nodes[1]->codegen(tools); - - std::cout << "MultiplicationNode" << std::endl; - return tools.builder->CreateFMul(lhs, rhs); + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); } }; @@ -122,31 +95,21 @@ class DivisionNode : public Node { nodes.push_back(_right); } - llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { - assert(nodes.size() == 2 && "DivisionNode must be a binary op"); - auto lhs = nodes[0]->codegen(tools); - auto rhs = nodes[1]->codegen(tools); - - std::cout << "DivisionNode" << std::endl; - return tools.builder->CreateFDiv(lhs, rhs); + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); } }; class PowerNode : public Node { +// TODO: delete public: PowerNode(Node *_base, Node *_exponent) : Node(POWER) { nodes.push_back(_exponent); nodes.push_back(_base); } - llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { - assert(nodes.size() == 2 && "DivisionNode must be a binary op"); - auto lhs = nodes[0]->codegen(tools); - auto rhs = nodes[1]->codegen(tools); - - std::cout << "PowerNode" << std::endl; - // TODO: return result - return nullptr; + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); } }; diff --git a/compiler/include/nodes/external_function_nodes.h b/compiler/include/nodes/external_function_nodes.h index d1020b7..8c5e5ab 100644 --- a/compiler/include/nodes/external_function_nodes.h +++ b/compiler/include/nodes/external_function_nodes.h @@ -34,47 +34,20 @@ class ExternalFunctionNode : public Node { ExternalFunctionNode(std::string &_name) : name(_name), Node(EXTERNAL_FUNCTION) {} virtual ~ExternalFunctionNode() {} - llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { - std::stringstream errStream; - if (tools.externalMathFunctions.find(name) == tools.externalMathFunctions.end()) { - errStream << "impala: function `" << name << "` doesn't belong to the standard math library"; - throw std::runtime_error(errStream.str()); - } - - auto proto = tools.externalMathFunctions[name]; - if (nodes.size() != proto->arg_size()) { - errStream << "impala: function `" << name << "` takes " << proto->arg_size() << " parameters, " - << "given " << nodes.size(); - throw std::runtime_error(errStream.str()); - } - - std::vector args; - for (auto node : nodes) { - auto arg = node->codegen(tools); - if (arg) { - args.push_back(arg); - } else { - errStream << "impala: found a statement in a list of formal parameters. " - << "Please, check `" << name << "` function call"; - throw std::runtime_error(errStream.str()); - } - } - - std::cout << "ExternalFunctionNode" << std::endl; - return tools.builder->CreateCall(proto, args); + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); } }; class ExternalFunctionParametersNode : public Node { +// TODO: delete public: ExternalFunctionParametersNode() : Node(EXTERNAL_FUNCTION_PARAMETER) {} virtual ~ExternalFunctionParametersNode() {} - llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { - std::cout << "ExternalFunctionParametersNode" << std::endl; - throw std::runtime_error("impala: never been suported by the language"); - return nullptr; + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); } }; diff --git a/compiler/include/nodes/node.h b/compiler/include/nodes/node.h index 3aecaa9..b456dca 100644 --- a/compiler/include/nodes/node.h +++ b/compiler/include/nodes/node.h @@ -21,10 +21,12 @@ #define EXPRESSION_H #include "engine.h" +#include "abstract_visitor.h" #include #include #include + class Node { public: NodeType nodeType; @@ -33,19 +35,15 @@ class Node { Node(NodeType _nodeType) : nodeType(_nodeType) {} virtual ~Node() { nodes.clear(); } - virtual llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) = 0; + virtual void accept(impala::AbstractVisitor* visitor) = 0; }; class RootNode : public Node { public: RootNode() : Node(ROOT) {} - llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { - for (auto statements : nodes) { - statements->codegen(tools); - } - std::cout << "Im root" << std::endl; - return nullptr; + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); } }; diff --git a/compiler/include/nodes/return_nodes.h b/compiler/include/nodes/return_nodes.h index e5d9f65..6430a77 100644 --- a/compiler/include/nodes/return_nodes.h +++ b/compiler/include/nodes/return_nodes.h @@ -26,12 +26,8 @@ class ReturnNode : public Node { public: ReturnNode(Node *_node) : Node(RETURN) { nodes.push_back(_node); } - llvm::Value *codegen(impala::engine::Jit::Toolbox &tools) override { - assert(nodes.size() == 1 && "VariableNode must have one child"); - std::cout << "ReturnNode" << std::endl; - - auto returnValue = nodes[0]->codegen(tools); - return tools.builder->CreateRet(returnValue); + void accept(impala::AbstractVisitor* visitor) override { + visitor->visit(this); } }; #endif // IMPALAJIT_RETURN_NODE_H From 5725c62830b27ffb7ff79ec552826e21a09dcdbe Mon Sep 17 00:00:00 2001 From: ravil Date: Sat, 5 Jun 2021 18:35:09 +0200 Subject: [PATCH 13/29] Added compile options to JIT --- compiler/code-gen/code_generator.cc | 54 ++++++++++++++------- compiler/code-gen/codegen_visitor.cpp | 2 - compiler/code-gen/include/code_generator.hh | 8 +-- compiler/code-gen/include/codegen_visitor.h | 3 +- compiler/driver.cc | 11 +++-- compiler/engine/engine.cpp | 5 +- compiler/engine/engine.h | 2 +- compiler/engine/std_math_lib.cpp | 5 +- compiler/engine/std_math_lib.h | 2 +- compiler/include/driver.h | 8 ++- example/cpp/example.cc | 20 ++++---- impalajit.cc | 6 +-- include/impalajit.hh | 18 +++---- include/impalajit/types.hh | 10 ++++ 14 files changed, 97 insertions(+), 57 deletions(-) diff --git a/compiler/code-gen/code_generator.cc b/compiler/code-gen/code_generator.cc index 5778f4b..21b1e8d 100644 --- a/compiler/code-gen/code_generator.cc +++ b/compiler/code-gen/code_generator.cc @@ -17,9 +17,9 @@ * THE SOFTWARE. */ +#include "codegen_visitor.h" #include "engine.h" #include "pretty_printer.h" -#include "codegen_visitor.h" #include "llvm/IR/Verifier.h" #include #include @@ -61,48 +61,66 @@ dasm_gen_func CodeGenerator::generateCode(FunctionContext *&functionContext) { return assembly.linkAndEncode(); } -void CodeGenerator::generateLLVMCode(FunctionContext *&functionContext, llvm::Module &module) { - impala::PrettyPrinter printer; - functionContext->root->accept(&printer); - std::cout << std::string(80, '+') << std::endl; +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 = this->genFunctionProto(functionContext, module, tools); - impala::CodegenVisitor codegenVisitor(tools); + auto function = this->genFunctionProto(functionContext, module, tools, realType); + impala::CodegenVisitor codegenVisitor(tools, realType); functionContext->root->accept(&codegenVisitor); llvm::verifyFunction(*function, &llvm::outs()); - impala::engine::Jit::printIRFunction(function); - + if (options.printIR) { + impala::engine::Jit::printIRFunction(function); + } // TODO: delete this one (memory de-allocation bug) generateCode(functionContext); } } llvm::Function *CodeGenerator::genFunctionProto(FunctionContext *&functionContext, llvm::Module &currModule, - impala::engine::Jit::Toolbox &tools) { + impala::engine::Jit::Toolbox &tools, llvm::Type *realType) { const auto numParams = functionContext->parameters.size(); - auto typeReal = llvm::Type::getDoubleTy(tools.context); - std::vector paramTypes(numParams, typeReal); - - // TODO: check whether a function proto has already been added + 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()); + } + } - llvm::FunctionType *functionProto = llvm::FunctionType::get(typeReal, paramTypes, false); auto function = llvm::Function::Create(functionProto, llvm::Function::ExternalLinkage, functionContext->name, currModule); - llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(tools.context, "entry", function); + auto entryBlock = llvm::BasicBlock::Create(tools.context, "entry", function); tools.builder->SetInsertPoint(entryBlock); const auto ¶ms = functionContext->parameters; - auto realType = llvm::Type::getDoubleTy(tools.context); for (size_t i = 0; i < params.size(); ++i) { - llvm::Argument *arg = function->getArg(i); + auto arg = function->getArg(i); arg->setName(params[i]); auto argPtr = tools.builder->CreateAlloca(realType); diff --git a/compiler/code-gen/codegen_visitor.cpp b/compiler/code-gen/codegen_visitor.cpp index 42cab08..aba3b39 100644 --- a/compiler/code-gen/codegen_visitor.cpp +++ b/compiler/code-gen/codegen_visitor.cpp @@ -115,7 +115,6 @@ void CodegenVisitor::visit(VariableNode *node) { void CodegenVisitor::visit(ConstantNode *node) { assert(node->nodes.empty() && "ConstantNode must have no children"); - auto realType = llvm::Type::getDoubleTy(toolbox.context); stack.push(llvm::ConstantFP::get(realType, node->value)); } @@ -188,7 +187,6 @@ void CodegenVisitor::visit(AssignmentNode *node) { auto address = toolbox.symbolTable[node->name]; if (!address) { - auto realType = llvm::Type::getDoubleTy(toolbox.context); address = toolbox.builder->CreateAlloca(realType); toolbox.symbolTable.addSymbol(node->name, address); } diff --git a/compiler/code-gen/include/code_generator.hh b/compiler/code-gen/include/code_generator.hh index 818483e..8fb5cb7 100644 --- a/compiler/code-gen/include/code_generator.hh +++ b/compiler/code-gen/include/code_generator.hh @@ -40,8 +40,10 @@ private: Assembly__SSE_4_1 assembly; - llvm::Function *genFunctionProto(FunctionContext *&functionContext, llvm::Module &currModule, - impala::engine::Jit::Toolbox &tools); + llvm::Function *genFunctionProto(FunctionContext *&functionContext, + llvm::Module &currModule, + impala::engine::Jit::Toolbox &tools, + llvm::Type* realType); /** * This functions performs the depth-first search algorithm. @@ -115,6 +117,6 @@ public: */ dasm_gen_func generateCode(FunctionContext *&functionContext); - void generateLLVMCode(FunctionContext *&functionContext, llvm::Module &module); + void generateLLVMCode(FunctionContext *&functionContext, llvm::Module &module, const impalajit::Options& options); }; #endif // IMPALAJIT_CODE_GENERATOR_HH diff --git a/compiler/code-gen/include/codegen_visitor.h b/compiler/code-gen/include/codegen_visitor.h index 3db4e15..c591f8f 100644 --- a/compiler/code-gen/include/codegen_visitor.h +++ b/compiler/code-gen/include/codegen_visitor.h @@ -8,7 +8,7 @@ namespace impala { class CodegenVisitor : public AbstractVisitor { public: - CodegenVisitor(engine::Jit::Toolbox &tools) : toolbox(tools) {} + 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; @@ -39,6 +39,7 @@ class CodegenVisitor : public AbstractVisitor { std::stack stack{}; engine::Jit::Toolbox &toolbox; + llvm::Type* realType{nullptr}; }; } // namespace impala diff --git a/compiler/driver.cc b/compiler/driver.cc index fd0eb95..9ffaf2b 100644 --- a/compiler/driver.cc +++ b/compiler/driver.cc @@ -63,7 +63,9 @@ std::map Driver::parse_string(const std::string &inpu return parse_stream(iss); } -FunctionContext::FunctionSinatureT Driver::generateLLVMFunction(std::istream& in, llvm::Module& module) { +FunctionContext::FunctionSinatureT Driver::generateLLVMFunction(std::istream& in, + llvm::Module& module, + const impalajit::Options& options) { Scanner scanner(&in); scanner.set_debug(false); this->lexer = &scanner; @@ -76,14 +78,15 @@ FunctionContext::FunctionSinatureT Driver::generateLLVMFunction(std::istream& in semanticAnalyzer.performSemanticAnalysis(functionContext); CodeGenerator codeGenerator; - codeGenerator.generateLLVMCode(functionContext, module); + codeGenerator.generateLLVMCode(functionContext, module, options); return std::make_pair(functionContext->name, functionContext->parameters.size()); } FunctionContext::FunctionSinatureT Driver::generateLLVMFunction(const std::string &input, - llvm::Module& module) { + llvm::Module& module, + const impalajit::Options& options) { std::istringstream iss(input); - auto signature = generateLLVMFunction(iss, module); + auto signature = generateLLVMFunction(iss, module, options); return signature; } diff --git a/compiler/engine/engine.cpp b/compiler/engine/engine.cpp index d2bc64f..67a6d90 100644 --- a/compiler/engine/engine.cpp +++ b/compiler/engine/engine.cpp @@ -72,7 +72,7 @@ llvm::JITEvaluatedSymbol Jit::lookup(llvm::StringRef Name) { return *expected; } -std::unique_ptr Jit::createModule() { +std::unique_ptr Jit::createModule(bool isDoublePrecision) { static long long counter{0}; std::string moduleName{"impala_module_" + std::to_string(counter)}; ++counter; @@ -80,8 +80,7 @@ std::unique_ptr Jit::createModule() { auto module = std::make_unique(std::move(moduleName), *context->getContext()); // fill with libmath function definitions - llvm::Type *realType = llvm::Type::getDoubleTy(*(context->getContext())); - externalMathFunctions = StdMathLib::fillModule(module, realType); + externalMathFunctions = StdMathLib::fillModule(module, isDoublePrecision); return module; } diff --git a/compiler/engine/engine.h b/compiler/engine/engine.h index c4e33ce..9abbcb6 100644 --- a/compiler/engine/engine.h +++ b/compiler/engine/engine.h @@ -69,7 +69,7 @@ class Jit { // 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(); + std::unique_ptr createModule(bool isDoublePrecision); types::FunctionProtosT &getExternalMathFunctions() { return externalMathFunctions; } diff --git a/compiler/engine/std_math_lib.cpp b/compiler/engine/std_math_lib.cpp index 2c62128..2427dcf 100644 --- a/compiler/engine/std_math_lib.cpp +++ b/compiler/engine/std_math_lib.cpp @@ -26,7 +26,10 @@ bool StdMathLib::isSupported(const types::FunctionSinatureT &signature) { return supportedSet.find(signature) != supportedSet.end(); } -types::FunctionProtosT StdMathLib::fillModule(std::unique_ptr &module, llvm::Type *realType) { +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(); diff --git a/compiler/engine/std_math_lib.h b/compiler/engine/std_math_lib.h index 7df57d8..6ff02b8 100644 --- a/compiler/engine/std_math_lib.h +++ b/compiler/engine/std_math_lib.h @@ -13,7 +13,7 @@ namespace impala { namespace engine { class StdMathLib { public: - static types::FunctionProtosT fillModule(std::unique_ptr &module, llvm::Type *realType); + static types::FunctionProtosT fillModule(std::unique_ptr &module, bool isDoublePrecision); static bool isSupported(const types::FunctionSinatureT &signature); private: diff --git a/compiler/include/driver.h b/compiler/include/driver.h index 7938975..39738c5 100644 --- a/compiler/include/driver.h +++ b/compiler/include/driver.h @@ -43,9 +43,13 @@ class Driver { std::map parse_string(const std::string &input); - FunctionContext::FunctionSinatureT generateLLVMFunction(std::istream &in, llvm::Module &module); + FunctionContext::FunctionSinatureT generateLLVMFunction(std::istream &in, + llvm::Module &module, + const impalajit::Options& options); - FunctionContext::FunctionSinatureT generateLLVMFunction(const std::string &input, llvm::Module &module); + FunctionContext::FunctionSinatureT generateLLVMFunction(const std::string &input, + llvm::Module &module, + const impalajit::Options& options); void setFunctionContext(FunctionContext *_functionContext); diff --git a/example/cpp/example.cc b/example/cpp/example.cc index 082269c..a27a10b 100644 --- a/example/cpp/example.cc +++ b/example/cpp/example.cc @@ -17,16 +17,18 @@ * THE SOFTWARE. */ - #include #include -int main() -{ - impalajit::Compiler compiler("example.conf"); - compiler.compile(); - //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/impalajit.cc b/impalajit.cc index f9bf0f5..acd943b 100644 --- a/impalajit.cc +++ b/impalajit.cc @@ -75,12 +75,12 @@ void impalajit::Compiler::loadFunctionDefinitionsFromInputFiles(std::string _con } } -void impalajit::Compiler::compile() { +void impalajit::Compiler::compile(Options options) { auto& jit = impala::engine::Jit::getJit(); - auto currentModule = jit.createModule(); + auto currentModule = jit.createModule(options.isDoublePrecision); std::vector functionSignature; for(auto& definition: functionDefinitions) { - functionSignature.emplace_back(driver.generateLLVMFunction(definition, *currentModule)); + functionSignature.emplace_back(driver.generateLLVMFunction(definition, *currentModule, options)); driver.deleteFunctionContext(); } jit.addModule(currentModule); diff --git a/include/impalajit.hh b/include/impalajit.hh index 2a1abd2..dd9f1ee 100644 --- a/include/impalajit.hh +++ b/include/impalajit.hh @@ -34,25 +34,25 @@ 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 compileLegacy(); - 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..bc6833b 100644 --- a/include/impalajit/types.hh +++ b/include/impalajit/types.hh @@ -22,4 +22,14 @@ typedef double (*dasm_gen_func)(...); +namespace impalajit { +struct Options { + Options() : debug(false), printAST(false), printIR(false), isDoublePrecision(true) {} + bool debug; + bool printAST; + bool printIR; + bool isDoublePrecision; +}; +} + #endif //IMPALAJIT_DASM_GEN_FUNCTION_H From aa2cf563e9696c2564b2a4c43ce6d05dace633c8 Mon Sep 17 00:00:00 2001 From: ravil Date: Sat, 5 Jun 2021 19:02:49 +0200 Subject: [PATCH 14/29] Removed legacy code generator --- CMakeLists.txt | 6 +- .../code-gen/assembly/assembly__sse_4_1.cc | 645 ------------------ .../code-gen/assembly/assembly__sse_4_1.dasc | 472 ------------- .../code-gen/assembly/include/assembly.hh | 192 ------ .../assembly/include/assembly__sse_4_1.hh | 154 ----- compiler/code-gen/assembly/include/dasm_arm.h | 456 ------------- .../code-gen/assembly/include/dasm_arm64.h | 518 -------------- .../code-gen/assembly/include/dasm_mips.h | 416 ----------- compiler/code-gen/assembly/include/dasm_ppc.h | 419 ------------ .../code-gen/assembly/include/dasm_proto.h | 83 --- compiler/code-gen/assembly/include/dasm_x86.h | 498 -------------- compiler/code-gen/code_generator.cc | 393 ----------- compiler/code-gen/code_generator.cpp | 92 +++ ...calculation_helper.hh => code_generator.h} | 41 +- compiler/code-gen/include/code_generator.hh | 122 ---- .../code-gen/include/ptr_map_container.hh | 74 -- compiler/driver.cc | 30 +- compiler/include/driver.h | 4 - impalajit.cc | 9 - include/impalajit.hh | 1 - 20 files changed, 119 insertions(+), 4506 deletions(-) delete mode 100644 compiler/code-gen/assembly/assembly__sse_4_1.cc delete mode 100644 compiler/code-gen/assembly/assembly__sse_4_1.dasc delete mode 100644 compiler/code-gen/assembly/include/assembly.hh delete mode 100644 compiler/code-gen/assembly/include/assembly__sse_4_1.hh delete mode 100644 compiler/code-gen/assembly/include/dasm_arm.h delete mode 100644 compiler/code-gen/assembly/include/dasm_arm64.h delete mode 100644 compiler/code-gen/assembly/include/dasm_mips.h delete mode 100644 compiler/code-gen/assembly/include/dasm_ppc.h delete mode 100644 compiler/code-gen/assembly/include/dasm_proto.h delete mode 100644 compiler/code-gen/assembly/include/dasm_x86.h delete mode 100644 compiler/code-gen/code_generator.cc create mode 100644 compiler/code-gen/code_generator.cpp rename compiler/code-gen/include/{calculation_helper.hh => code_generator.h} (57%) delete mode 100644 compiler/code-gen/include/code_generator.hh delete mode 100644 compiler/code-gen/include/ptr_map_container.hh diff --git a/CMakeLists.txt b/CMakeLists.txt index e4574b8..acd628c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,6 @@ set(include_dirs compiler/frontend/include compiler/semantic_analysis/include compiler/code-gen/include - compiler/code-gen/assembly/include compiler/engine) include_directories(${include_dirs}) @@ -54,10 +53,7 @@ set(source_files ${source_files} 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 + compiler/code-gen/code_generator.cpp compiler/code-gen/codegen_visitor.cpp compiler/code-gen/pretty_printer.cpp compiler/engine/engine.cpp 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 171e961..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{nullptr}; - dasm_State** Dst{nullptr}; - void** labels{nullptr}; - 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 21b1e8d..0000000 --- a/compiler/code-gen/code_generator.cc +++ /dev/null @@ -1,393 +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 "codegen_visitor.h" -#include "engine.h" -#include "pretty_printer.h" -#include "llvm/IR/Verifier.h" -#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(); -} - -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 = this->genFunctionProto(functionContext, module, tools, realType); - impala::CodegenVisitor codegenVisitor(tools, realType); - functionContext->root->accept(&codegenVisitor); - - llvm::verifyFunction(*function, &llvm::outs()); - if (options.printIR) { - impala::engine::Jit::printIRFunction(function); - } - // TODO: delete this one (memory de-allocation bug) - generateCode(functionContext); - } -} - -llvm::Function *CodeGenerator::genFunctionProto(FunctionContext *&functionContext, llvm::Module &currModule, - impala::engine::Jit::Toolbox &tools, llvm::Type *realType) { - - 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 function = - llvm::Function::Create(functionProto, llvm::Function::ExternalLinkage, 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; -} - -/** - * @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..1fa3d9e --- /dev/null +++ b/compiler/code-gen/code_generator.cpp @@ -0,0 +1,92 @@ +/** + * 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); + impala::CodegenVisitor codegenVisitor(tools, realType); + functionContext->root->accept(&codegenVisitor); + + 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 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 function = + llvm::Function::Create(functionProto, llvm::Function::ExternalLinkage, 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; +} \ No newline at end of file diff --git a/compiler/code-gen/include/calculation_helper.hh b/compiler/code-gen/include/code_generator.h similarity index 57% rename from compiler/code-gen/include/calculation_helper.hh rename to compiler/code-gen/include/code_generator.h index 67e3295..fcf627c 100644 --- a/compiler/code-gen/include/calculation_helper.hh +++ b/compiler/code-gen/include/code_generator.h @@ -17,22 +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); -/** - * 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 8fb5cb7..0000000 --- a/compiler/code-gen/include/code_generator.hh +++ /dev/null @@ -1,122 +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 "engine.h" -#include "engine_types.h" -#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; - - llvm::Function *genFunctionProto(FunctionContext *&functionContext, - llvm::Module &currModule, - impala::engine::Jit::Toolbox &tools, - llvm::Type* realType); - - /** - * 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); - - void generateLLVMCode(FunctionContext *&functionContext, llvm::Module &module, const impalajit::Options& options); -}; -#endif // IMPALAJIT_CODE_GENERATOR_HH 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/driver.cc b/compiler/driver.cc index 9ffaf2b..7b982a1 100644 --- a/compiler/driver.cc +++ b/compiler/driver.cc @@ -23,7 +23,7 @@ #include #include -#include +#include #include namespace impalajit { @@ -35,34 +35,6 @@ 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(); - - SemanticAnalyzer semanticAnalyzer; - semanticAnalyzer.performSemanticAnalysis(functionContext); - - CodeGenerator codeGenerator; - dasm_gen_func function = codeGenerator.generateCode(functionContext); - - std::map resultMap; - resultMap.insert(std::make_pair(functionContext->name, function)); - - return resultMap; -} - -std::map Driver::parse_string(const std::string &input) -{ - std::istringstream iss(input); - return parse_stream(iss); -} - FunctionContext::FunctionSinatureT Driver::generateLLVMFunction(std::istream& in, llvm::Module& module, const impalajit::Options& options) { diff --git a/compiler/include/driver.h b/compiler/include/driver.h index 39738c5..1beac7a 100644 --- a/compiler/include/driver.h +++ b/compiler/include/driver.h @@ -39,10 +39,6 @@ class Driver { class Scanner *lexer; - std::map parse_stream(std::istream &in); - - std::map parse_string(const std::string &input); - FunctionContext::FunctionSinatureT generateLLVMFunction(std::istream &in, llvm::Module &module, const impalajit::Options& options); diff --git a/impalajit.cc b/impalajit.cc index acd943b..6683080 100644 --- a/impalajit.cc +++ b/impalajit.cc @@ -92,15 +92,6 @@ void impalajit::Compiler::compile(Options options) { } } -void impalajit::Compiler::compileLegacy(){ - for(auto& definition: functionDefinitions) { - auto parsedFunctions = driver.parse_string(definition); - functionMap.insert(parsedFunctions.begin(), parsedFunctions.end()); - parameterCountMap.insert(std::make_pair(parsedFunctions.begin()->first, driver.getParameterCount())); - driver.deleteFunctionContext(); - } -} - dasm_gen_func impalajit::Compiler::getFunction(std::string functionName) { if(functionMap.find(functionName) == functionMap.end()){ throw std::runtime_error("Function \""+functionName+"\" not found"); diff --git a/include/impalajit.hh b/include/impalajit.hh index dd9f1ee..a66e347 100644 --- a/include/impalajit.hh +++ b/include/impalajit.hh @@ -40,7 +40,6 @@ public: Compiler(std::vector _functionDefinitions); Compiler(); - void compileLegacy(); void compile(Options options = Options()); dasm_gen_func getFunction(std::string functionName); unsigned int getParameterCount(std::string functionName); From 1f0a95338f7862bf218df210601e3563aee7fc19 Mon Sep 17 00:00:00 2001 From: ravil Date: Sat, 5 Jun 2021 20:57:39 +0200 Subject: [PATCH 15/29] Added missing header files --- compiler/engine/engine_types.h | 1 + compiler/engine/std_math_lib.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/compiler/engine/engine_types.h b/compiler/engine/engine_types.h index 4f43c28..9093de2 100644 --- a/compiler/engine/engine_types.h +++ b/compiler/engine/engine_types.h @@ -2,6 +2,7 @@ #define IMPALA_CPP_ENGINE_TYPES_H #include "llvm/ExecutionEngine/Orc/Core.h" +#include "llvm/IR/Function.h" #include namespace impala { diff --git a/compiler/engine/std_math_lib.cpp b/compiler/engine/std_math_lib.cpp index 2427dcf..7b9eece 100644 --- a/compiler/engine/std_math_lib.cpp +++ b/compiler/engine/std_math_lib.cpp @@ -1,4 +1,5 @@ #include "std_math_lib.h" +#include "llvm/IR/Module.h" namespace impala { namespace engine { From 94aed5fa60a1385dccb7907a4d4a0f3796277464 Mon Sep 17 00:00:00 2001 From: ravil-mobile Date: Sun, 6 Jun 2021 03:48:59 +0200 Subject: [PATCH 16/29] Added CI (#1) * Added ci.yml as a test workflow --- .github/workflows/ci.yml | 50 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..fa33d27 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,50 @@ +name: CMake + +on: push + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release + +jobs: + build: + # The CMake configure and build commands are platform agnostic and should work equally + # well on Windows or Mac. You can convert this to a matrix build if you need + # cross-platform coverage. + # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix + runs-on: ubuntu-18.04 + + 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 && sudo make && sudo make install + + - name: Install LLVM 10 + run: | + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh 10 + sudo apt-get -y install zlib1g-dev + + - uses: actions/checkout@v2 + + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DTESTS=ON + + - name: Build + # Build your program with the given configuration + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + + - name: Test + working-directory: ${{github.workspace}}/build + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest -C ${{env.BUILD_TYPE}} + From 60dd99fb373472d9be26806182fea5b15e2f3f7a Mon Sep 17 00:00:00 2001 From: ravil-mobile Date: Sun, 6 Jun 2021 14:32:47 +0200 Subject: [PATCH 17/29] Added format.sh for clang-format --- .dev/format.sh | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100755 .dev/format.sh 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 $@ From 7a7f440938723b5cf7e94e6cfb883c8c0e3bf578 Mon Sep 17 00:00:00 2001 From: ravil-mobile Date: Sun, 6 Jun 2021 23:02:23 +0200 Subject: [PATCH 18/29] added formating to the CI workflow (#2) --- .github/workflows/ci.yml | 50 +++++++++++++------ compiler/code-gen/codegen_visitor.cpp | 3 +- compiler/code-gen/include/abstract_visitor.h | 52 ++++++++++---------- compiler/code-gen/include/code_generator.h | 11 ++--- compiler/code-gen/include/codegen_visitor.h | 6 +-- compiler/engine/std_math_lib.cpp | 2 +- 6 files changed, 70 insertions(+), 54 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fa33d27..2355423 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,17 +3,13 @@ name: CMake on: push env: - # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: - build: - # The CMake configure and build commands are platform agnostic and should work equally - # well on Windows or Mac. You can convert this to a matrix build if you need - # cross-platform coverage. - # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix + testing: runs-on: ubuntu-18.04 - + env: + LLVM_VERSION: 10 steps: - name: Setup CMake uses: jwlawson/actions-setup-cmake@v1.9 @@ -22,29 +18,53 @@ jobs: - name: Install GTest run: | - sudo apt-get install libgtest-dev && cd /usr/src/gtest && sudo cmake CMakeLists.txt && sudo make && sudo make install + sudo apt-get install libgtest-dev + cd /usr/src/gtest + sudo cmake CMakeLists.txt + sudo make + sudo make install - - name: Install LLVM 10 + - name: Install LLVM ${{env.LLVM_VERSION}} run: | wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh - sudo ./llvm.sh 10 + sudo ./llvm.sh ${{env.LLVM_VERSION}} sudo apt-get -y install zlib1g-dev - uses: actions/checkout@v2 - name: Configure CMake - # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. - # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DTESTS=ON - name: Build - # Build your program with the given configuration run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} - name: Test working-directory: ${{github.workspace}}/build - # Execute tests defined by the CMake configuration. - # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail run: ctest -C ${{env.BUILD_TYPE}} + 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/compiler/code-gen/codegen_visitor.cpp b/compiler/code-gen/codegen_visitor.cpp index aba3b39..a8711cf 100644 --- a/compiler/code-gen/codegen_visitor.cpp +++ b/compiler/code-gen/codegen_visitor.cpp @@ -8,7 +8,7 @@ #include "return_nodes.h" namespace impala { -void CodegenVisitor::visit(RootNode* node) { +void CodegenVisitor::visit(RootNode *node) { for (auto statements : node->nodes) { statements->accept(this); } @@ -193,7 +193,6 @@ void CodegenVisitor::visit(AssignmentNode *node) { 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); diff --git a/compiler/code-gen/include/abstract_visitor.h b/compiler/code-gen/include/abstract_visitor.h index fd27696..cc38af8 100644 --- a/compiler/code-gen/include/abstract_visitor.h +++ b/compiler/code-gen/include/abstract_visitor.h @@ -23,30 +23,30 @@ 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; - }; -} +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 +#endif // IMPALA_CPP_ABSTRACTVISITOR_H diff --git a/compiler/code-gen/include/code_generator.h b/compiler/code-gen/include/code_generator.h index fcf627c..32afcc2 100644 --- a/compiler/code-gen/include/code_generator.h +++ b/compiler/code-gen/include/code_generator.h @@ -29,19 +29,16 @@ #include #include - class CodeGenerator { private: - - static llvm::Function *genFunctionProto(FunctionContext *&functionContext, - llvm::Module &currModule, - impala::engine::Jit::Toolbox &tools, - llvm::Type* realType); + static llvm::Function *genFunctionProto(FunctionContext *&functionContext, llvm::Module &currModule, + impala::engine::Jit::Toolbox &tools, llvm::Type *realType); public: CodeGenerator() = default; ~CodeGenerator() = default; - static void generateLLVMCode(FunctionContext *&functionContext, llvm::Module &module, const impalajit::Options& options); + static void generateLLVMCode(FunctionContext *&functionContext, llvm::Module &module, + const impalajit::Options &options); }; #endif // IMPALAJIT_CODE_GENERATOR_HH diff --git a/compiler/code-gen/include/codegen_visitor.h b/compiler/code-gen/include/codegen_visitor.h index c591f8f..d5b1888 100644 --- a/compiler/code-gen/include/codegen_visitor.h +++ b/compiler/code-gen/include/codegen_visitor.h @@ -8,7 +8,7 @@ namespace impala { class CodegenVisitor : public AbstractVisitor { public: - CodegenVisitor(engine::Jit::Toolbox &tools, llvm::Type* realType) : toolbox(tools), realType(realType) {} + 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; @@ -31,7 +31,7 @@ class CodegenVisitor : public AbstractVisitor { void visit(ElseBodyNode *node) override; private: - llvm::Value* top() { + llvm::Value *top() { auto topValue = stack.top(); stack.pop(); return topValue; @@ -39,7 +39,7 @@ class CodegenVisitor : public AbstractVisitor { std::stack stack{}; engine::Jit::Toolbox &toolbox; - llvm::Type* realType{nullptr}; + llvm::Type *realType{nullptr}; }; } // namespace impala diff --git a/compiler/engine/std_math_lib.cpp b/compiler/engine/std_math_lib.cpp index 7b9eece..65cfd98 100644 --- a/compiler/engine/std_math_lib.cpp +++ b/compiler/engine/std_math_lib.cpp @@ -29,7 +29,7 @@ bool StdMathLib::isSupported(const types::FunctionSinatureT &signature) { types::FunctionProtosT StdMathLib::fillModule(std::unique_ptr &module, bool isDoublePrecision) { - auto& context = module->getContext(); + auto &context = module->getContext(); llvm::Type *realType = (isDoublePrecision) ? llvm::Type::getDoubleTy(context) : llvm::Type::getFloatTy(context); std::unordered_map functionProtoTable; From c1b0f8db29d8aa474feec1aa288bdea55d47d2b9 Mon Sep 17 00:00:00 2001 From: ravil-mobile Date: Wed, 9 Jun 2021 13:34:18 +0200 Subject: [PATCH 19/29] Ravil/install (#3) * added formating to the CI workflow * Removed pkg-config, added exported targets * added cmake config and version files Co-authored-by: ravil --- .github/workflows/ci.yml | 12 +- CMake/pkg-config.pc.in | 11 - CMakeLists.txt | 161 +++++------ README.md | 6 +- compiler/frontend/scanner.cc | 271 +++++++++--------- share/ImpalaJITConfig.cmake.in | 5 + tests/CMakeLists.txt | 6 +- tests/install_test/CMakeLists.txt | 11 + tests/install_test/example.cc | 34 +++ tests/install_test/example.conf | 1 + tests/install_test/impala_file/example.impala | 3 + 11 files changed, 277 insertions(+), 244 deletions(-) delete mode 100644 CMake/pkg-config.pc.in create mode 100644 share/ImpalaJITConfig.cmake.in create mode 100644 tests/install_test/CMakeLists.txt create mode 100644 tests/install_test/example.cc create mode 100644 tests/install_test/example.conf create mode 100644 tests/install_test/impala_file/example.impala diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2355423..7ad3d2b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: run: | sudo apt-get install libgtest-dev cd /usr/src/gtest - sudo cmake CMakeLists.txt + sudo cmake CMakeLists.txt -Dgtest_disable_pthreads=ON sudo make sudo make install @@ -42,6 +42,16 @@ jobs: - 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 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 acd628c..ecb1a75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,113 +17,95 @@ 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 ) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -O3") +option(SHARED_LIB "Compile the shared library" ON) +option(TESTS "Enable Tests" OFF) -project(ImpalaJIT) +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/std_math_lib.cpp) -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/engine) - -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/code_generator.cpp - compiler/code-gen/codegen_visitor.cpp - compiler/code-gen/pretty_printer.cpp - compiler/engine/engine.cpp - compiler/engine/std_math_lib.cpp) - -##### 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 ) find_package(LLVM 10.0 REQUIRED CONFIG) LLVM_MAP_COMPONENTS_TO_LIBNAMES(LLVM_LIBS core orcjit native) message(STATUS "LLVM: ${LLVM_VERSION}") -if( SHARED_LIB ) - set(TARGET_NAME impalajit) - add_library( ${TARGET_NAME} SHARED ${source_files} ) -endif( SHARED_LIB ) +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) -if( STATIC_LIB ) - set(TARGET_NAME impalajit-static) - add_library( ${TARGET_NAME} STATIC ${source_files} ) - set_target_properties( ${TARGET_NAME} PROPERTIES OUTPUT_NAME impalajit ) -endif( STATIC_LIB ) +# 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 PUBLIC ${LLVM_DEFINITIONS}) -target_link_libraries( ${TARGET_NAME} PUBLIC -rdynamic -lm ${math_library} ${LLVM_LIBS}) -target_include_directories( ${TARGET_NAME} PRIVATE ${LLVM_INCLUDE_DIRS} ) -target_compile_definitions( ${TARGET_NAME} PRIVATE ${LLVM_DEFINITIONS} ) -# Tests if (TESTS) enable_testing() add_subdirectory(tests) endif() +set(IMPALA_CMAKE_FILES lib/impalajit/cmake) +install(TARGETS impalajit DESTINATION lib + EXPORT ImpalaJITTargets + INCLUDES DESTINATION include) +install(EXPORT ImpalaJITTargets DESTINATION ${IMPALA_CMAKE_FILES}) -# install target -install( TARGETS ${TARGET_NAME} DESTINATION 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) + +install(FILES + DESTINATION + lib/cmake) + +include(CMakePackageConfigHelpers) +configure_package_config_file(share/ImpalaJITConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/ImpalaJITConfig.cmake + INSTALL_DESTINATION ${IMPALA_CMAKE_FILES}) + +write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/ImpalaJITConfigVersion.cmake + VERSION 1.0.0 + COMPATIBILITY SameMajorVersion) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ImpalaJITConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/ImpalaJITConfigVersion.cmake + DESTINATION ${IMPALA_CMAKE_FILES}) # uninstall target @@ -131,6 +113,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) @@ -139,5 +122,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..8292a6f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # ImpalaJIT A lightweight JIT compiler for flexible data access in simulation applications +## Depencencies +* LLVM - build +* Z3 - run-time + ## Building ImpalaJIT 1. mkdir build 2. cd build @@ -25,4 +29,4 @@ Flex (Tested with version 2.6.0): https://github.com/westes/flex
* make uninstall ## License -ImpalaJIT is release under the MIT License (see [COPYING](COPYING)) \ No newline at end of file +ImpalaJIT is release under the MIT License (see [COPYING](COPYING)) 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/share/ImpalaJITConfig.cmake.in b/share/ImpalaJITConfig.cmake.in new file mode 100644 index 0000000..d18a293 --- /dev/null +++ b/share/ImpalaJITConfig.cmake.in @@ -0,0 +1,5 @@ +# - Config file for the ImpalaJIT package +# - Using imported targets + +get_filename_component(IMPALAJIT_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +include("${IMPALAJIT_DIR}/ImpalaJITTargets.cmake") diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1ad5c43..6b06dc4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,7 +8,7 @@ add_executable(basic_tests ${CMAKE_CURRENT_SOURCE_DIR}/main.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 ${TARGET_NAME} ${GTEST_LIBRARIES}) +target_link_libraries(basic_tests PRIVATE impalajit ${GTEST_LIBRARIES}) add_executable(advanced_tests ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp @@ -16,9 +16,9 @@ add_executable(advanced_tests ${CMAKE_CURRENT_SOURCE_DIR}/main.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 ${TARGET_NAME} ${GTEST_LIBRARIES}) +target_link_libraries(advanced_tests PRIVATE impalajit ${GTEST_LIBRARIES}) 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) \ No newline at end of file +add_test(NAME advanced_tests COMMAND advanced_tests) diff --git a/tests/install_test/CMakeLists.txt b/tests/install_test/CMakeLists.txt new file mode 100644 index 0000000..6f0f79d --- /dev/null +++ b/tests/install_test/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 2.6) +project(install_test) + +find_package(ImpalaJIT REQUIRED) +message(STATUS "IMPALAJIT_DIR: ${IMPALAJIT_DIR}") + +add_executable(${CMAKE_PROJECT_NAME} ${PROJECT_SOURCE_DIR}/example.cc) +target_link_libraries(${CMAKE_PROJECT_NAME} impalajit) + +file(COPY ${PROJECT_SOURCE_DIR}/example.conf DESTINATION .) +file(COPY ${PROJECT_SOURCE_DIR}/impala_file DESTINATION .) diff --git a/tests/install_test/example.cc b/tests/install_test/example.cc new file mode 100644 index 0000000..a27a10b --- /dev/null +++ b/tests/install_test/example.cc @@ -0,0 +1,34 @@ +/** + * 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 + +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/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); +} From 6fb35ed586860149c6cb803e567536724224f25a Mon Sep 17 00:00:00 2001 From: ravil-mobile Date: Wed, 9 Jun 2021 13:39:33 +0200 Subject: [PATCH 20/29] Update README.md --- README.md | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 8292a6f..4af5b54 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,20 @@ # ImpalaJIT A lightweight JIT compiler for flexible data access in simulation applications -## Depencencies +### Dependencies * LLVM - build * Z3 - run-time -## Building ImpalaJIT +### Building 1. mkdir build 2. cd build -3. cmake ../ -4. make +3. cmake .. -DCMAKE_INSTALL_PREFIX= +4. make -j -## Generating Parser, Scanner and ASM +### 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)
@@ -22,11 +25,5 @@ Flex (Tested with version 2.6.0): https://github.com/westes/flex
* make generate -## Installing ImpalaJIT -* make install - -## Uninstalling ImpalaJIT -* make uninstall - -## License +### License ImpalaJIT is release under the MIT License (see [COPYING](COPYING)) From 90e92aa17bd36044186d19af0d3730b1cef30099 Mon Sep 17 00:00:00 2001 From: ravil-mobile Date: Wed, 9 Jun 2021 13:40:15 +0200 Subject: [PATCH 21/29] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4af5b54..a3e9f34 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A lightweight JIT compiler for flexible data access in simulation applications ### Building 1. mkdir build 2. cd build -3. cmake .. -DCMAKE_INSTALL_PREFIX= +3. cmake .. -DCMAKE_INSTALL_PREFIX=\ 4. make -j ### Installing From a63ca4bab321c54f7542ab167c3b96311216c01b Mon Sep 17 00:00:00 2001 From: ravil-mobile Date: Thu, 10 Jun 2021 22:36:52 +0200 Subject: [PATCH 22/29] Ravil/bug fixes (#4) * Added parallel build. Checks llvm 10 and 11 Co-authored-by: ravil --- .github/workflows/ci.yml | 12 +++++++----- CMakeLists.txt | 9 ++++++++- README.md | 4 ++++ compiler/code-gen/code_generator.cpp | 9 +++++++++ compiler/code-gen/codegen_visitor.cpp | 6 +++--- compiler/code-gen/include/code_generator.h | 2 ++ compiler/semantic_analysis/semantic_analyzer.cc | 12 ------------ tests/CMakeLists.txt | 2 +- tests/impala_files/many_if.impala | 3 ++- 9 files changed, 36 insertions(+), 23 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7ad3d2b..a4e5d51 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,8 +8,10 @@ env: jobs: testing: runs-on: ubuntu-18.04 - env: - LLVM_VERSION: 10 + strategy: + matrix: + llvm_version: [10, 11] + steps: - name: Setup CMake uses: jwlawson/actions-setup-cmake@v1.9 @@ -24,11 +26,11 @@ jobs: sudo make sudo make install - - name: Install LLVM ${{env.LLVM_VERSION}} + - name: Install LLVM ${{ matrix.llvm_version }} run: | wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh - sudo ./llvm.sh ${{env.LLVM_VERSION}} + sudo ./llvm.sh ${{ matrix.llvm_version }} sudo apt-get -y install zlib1g-dev - uses: actions/checkout@v2 @@ -37,7 +39,7 @@ jobs: 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}} + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j2 - name: Test working-directory: ${{github.workspace}}/build diff --git a/CMakeLists.txt b/CMakeLists.txt index ecb1a75..26b0804 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,8 +35,15 @@ set(source_files compiler/frontend/parser.cc compiler/engine/engine.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() -find_package(LLVM 10.0 REQUIRED CONFIG) LLVM_MAP_COMPONENTS_TO_LIBNAMES(LLVM_LIBS core orcjit native) message(STATUS "LLVM: ${LLVM_VERSION}") diff --git a/README.md b/README.md index a3e9f34..a09ddf6 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,10 @@ A lightweight JIT compiler for flexible data access in simulation applications 3. cmake .. -DCMAKE_INSTALL_PREFIX=\ 4. make -j +## Installing ImpalaJIT +* make install + + ### Installing * make install diff --git a/compiler/code-gen/code_generator.cpp b/compiler/code-gen/code_generator.cpp index 1fa3d9e..97ec6a4 100644 --- a/compiler/code-gen/code_generator.cpp +++ b/compiler/code-gen/code_generator.cpp @@ -42,6 +42,7 @@ void CodeGenerator::generateLLVMCode(FunctionContext *&functionContext, llvm::Mo auto function = CodeGenerator::genFunctionProto(functionContext, module, tools, realType); impala::CodegenVisitor codegenVisitor(tools, realType); functionContext->root->accept(&codegenVisitor); + checkLastBasicBlock(function); llvm::verifyFunction(*function, &llvm::outs()); if (options.printIR) { @@ -89,4 +90,12 @@ llvm::Function *CodeGenerator::genFunctionProto(FunctionContext *&functionContex } 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 index a8711cf..43c8b1c 100644 --- a/compiler/code-gen/codegen_visitor.cpp +++ b/compiler/code-gen/codegen_visitor.cpp @@ -209,7 +209,7 @@ void CodegenVisitor::visit(IfStmtNode *node) { toolbox.builder->SetInsertPoint(thenBlock); node->nodes[1]->accept(this); auto &lastInstr = toolbox.builder->GetInsertBlock()->back(); - if (!llvm::isa(lastInstr)) { + if (!llvm::isa(lastInstr)) { toolbox.builder->CreateBr(mergeBlock); } @@ -258,7 +258,7 @@ void CodegenVisitor::visit(IfBodyNode *node) { for (auto child : node->nodes) { child->accept(this); auto &lastInstruction = toolbox.builder->GetInsertBlock()->back(); - if (llvm::isa(lastInstruction)) { + if (llvm::isa(lastInstruction)) { // a return instruction found. Doesn't make sense to generate the rest of the instructions break; } @@ -271,7 +271,7 @@ void CodegenVisitor::visit(ElseBodyNode *node) { for (auto child : node->nodes) { child->accept(this); auto &lastInstruction = toolbox.builder->GetInsertBlock()->back(); - if (llvm::isa(lastInstruction)) { + if (llvm::isa(lastInstruction)) { // a return instruction found. Doesn't make sense to generate the rest of the instructions break; } diff --git a/compiler/code-gen/include/code_generator.h b/compiler/code-gen/include/code_generator.h index 32afcc2..06cb6c4 100644 --- a/compiler/code-gen/include/code_generator.h +++ b/compiler/code-gen/include/code_generator.h @@ -34,6 +34,8 @@ class CodeGenerator { static llvm::Function *genFunctionProto(FunctionContext *&functionContext, llvm::Module &currModule, impala::engine::Jit::Toolbox &tools, llvm::Type *realType); + static void checkLastBasicBlock(llvm::Function *function); + public: CodeGenerator() = default; ~CodeGenerator() = default; diff --git a/compiler/semantic_analysis/semantic_analyzer.cc b/compiler/semantic_analysis/semantic_analyzer.cc index 4910385..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); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6b06dc4..b59d288 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -13,7 +13,7 @@ target_link_libraries(basic_tests PRIVATE impalajit ${GTEST_LIBRARIES}) 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}/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}) 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 From 83d0c211988315f73d8a51a5b9ccaf3152f505a9 Mon Sep 17 00:00:00 2001 From: ravil-mobile Date: Thu, 10 Jun 2021 22:41:18 +0200 Subject: [PATCH 23/29] Update README.md --- README.md | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index a09ddf6..bac2129 100644 --- a/README.md +++ b/README.md @@ -2,21 +2,21 @@ A lightweight JIT compiler for flexible data access in simulation applications ### Dependencies -* LLVM - build -* Z3 - run-time +- LLVM between versions 10.0 and 11.1 - build +- Z3 - run-time ### Building -1. mkdir build -2. cd build -3. cmake .. -DCMAKE_INSTALL_PREFIX=\ -4. make -j - -## Installing ImpalaJIT -* make install - +``` +mkdir build +cd build +cmake .. -DCMAKE_INSTALL_PREFIX= +make -j +``` ### Installing -* make install +``` +make install +``` ### Generating Parser, Scanner and ASM This step is only necessary if you have modified one of the following files:
@@ -27,7 +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 +``` +make generate +``` ### License -ImpalaJIT is release under the MIT License (see [COPYING](COPYING)) +ImpalaJIT is release under the MIT License From d3cd53b3c42ab5dd88b3b4c6c3317adb076ff6a7 Mon Sep 17 00:00:00 2001 From: ravil-mobile Date: Fri, 11 Jun 2021 11:46:48 +0200 Subject: [PATCH 24/29] Ravil/cmake (#5) * Updated CMakeLists.txt * Removed submodule Co-authored-by: ravil --- .gitmodules | 3 --- 3rd_party/LuaJIT | 1 - CMakeLists.txt | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) delete mode 160000 3rd_party/LuaJIT 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/CMakeLists.txt b/CMakeLists.txt index 26b0804..0b2f017 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,7 +71,7 @@ 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 PUBLIC ${LLVM_DEFINITIONS}) +target_compile_definitions(impalajit PRIVATE ${LLVM_DEFINITIONS}) if (TESTS) From 8eb49f7e21c01a14b5b05843552ffb8273aeb6e2 Mon Sep 17 00:00:00 2001 From: ravil-mobile Date: Sat, 12 Jun 2021 12:25:04 +0200 Subject: [PATCH 25/29] Added a linkage option (weak is default b/c compatibility with SeisSol) (#6) --- compiler/code-gen/code_generator.cpp | 10 ++++++---- compiler/code-gen/include/code_generator.h | 3 ++- include/impalajit/types.hh | 3 ++- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/compiler/code-gen/code_generator.cpp b/compiler/code-gen/code_generator.cpp index 97ec6a4..5c30154 100644 --- a/compiler/code-gen/code_generator.cpp +++ b/compiler/code-gen/code_generator.cpp @@ -39,7 +39,7 @@ void CodeGenerator::generateLLVMCode(FunctionContext *&functionContext, llvm::Mo llvm::Type *realType = (options.isDoublePrecision) ? llvm::Type::getDoubleTy(tools.context) : llvm::Type::getFloatTy(tools.context); - auto function = CodeGenerator::genFunctionProto(functionContext, module, tools, realType); + auto function = CodeGenerator::genFunctionProto(functionContext, module, tools, realType, options); impala::CodegenVisitor codegenVisitor(tools, realType); functionContext->root->accept(&codegenVisitor); checkLastBasicBlock(function); @@ -52,7 +52,8 @@ void CodeGenerator::generateLLVMCode(FunctionContext *&functionContext, llvm::Mo } llvm::Function *CodeGenerator::genFunctionProto(FunctionContext *&functionContext, llvm::Module &currModule, - impala::engine::Jit::Toolbox &tools, llvm::Type *realType) { + impala::engine::Jit::Toolbox &tools, llvm::Type *realType, + const impalajit::Options &options) { const auto numParams = functionContext->parameters.size(); std::vector paramTypes(numParams, realType); @@ -73,8 +74,9 @@ llvm::Function *CodeGenerator::genFunctionProto(FunctionContext *&functionContex } } - auto function = - llvm::Function::Create(functionProto, llvm::Function::ExternalLinkage, functionContext->name, currModule); + 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); diff --git a/compiler/code-gen/include/code_generator.h b/compiler/code-gen/include/code_generator.h index 06cb6c4..6a4c6e8 100644 --- a/compiler/code-gen/include/code_generator.h +++ b/compiler/code-gen/include/code_generator.h @@ -32,7 +32,8 @@ class CodeGenerator { private: static llvm::Function *genFunctionProto(FunctionContext *&functionContext, llvm::Module &currModule, - impala::engine::Jit::Toolbox &tools, llvm::Type *realType); + impala::engine::Jit::Toolbox &tools, llvm::Type *realType, + const impalajit::Options &options); static void checkLastBasicBlock(llvm::Function *function); diff --git a/include/impalajit/types.hh b/include/impalajit/types.hh index bc6833b..d284e0b 100644 --- a/include/impalajit/types.hh +++ b/include/impalajit/types.hh @@ -24,11 +24,12 @@ typedef double (*dasm_gen_func)(...); namespace impalajit { struct Options { - Options() : debug(false), printAST(false), printIR(false), isDoublePrecision(true) {} + Options() : debug(false), printAST(false), printIR(false), isDoublePrecision(true), weakLinkage(true) {} bool debug; bool printAST; bool printIR; bool isDoublePrecision; + bool weakLinkage; }; } From c29f3859e2840d736d6b053f58ad07ef9b3d96f3 Mon Sep 17 00:00:00 2001 From: ravil-mobile Date: Mon, 14 Jun 2021 01:20:20 +0200 Subject: [PATCH 26/29] Ravil/opt (#7) * Added an optimizer icompiler/engine/optimizer.h.e. O1 --- CMakeLists.txt | 1 + compiler/engine/engine.cpp | 5 ++++- compiler/engine/engine.h | 17 ++++++++++------- compiler/engine/optimizer.cpp | 20 ++++++++++++++++++++ compiler/engine/optimizer.h | 27 +++++++++++++++++++++++++++ impalajit.cc | 2 +- 6 files changed, 63 insertions(+), 9 deletions(-) create mode 100644 compiler/engine/optimizer.cpp create mode 100644 compiler/engine/optimizer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b2f017..33201c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,7 @@ set(source_files compiler/frontend/parser.cc 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 diff --git a/compiler/engine/engine.cpp b/compiler/engine/engine.cpp index 67a6d90..71b75c6 100644 --- a/compiler/engine/engine.cpp +++ b/compiler/engine/engine.cpp @@ -58,7 +58,10 @@ Jit::Jit() { } } -void Jit::addModule(std::unique_ptr &module) { +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))); } diff --git a/compiler/engine/engine.h b/compiler/engine/engine.h index 9abbcb6..3be8192 100644 --- a/compiler/engine/engine.h +++ b/compiler/engine/engine.h @@ -2,6 +2,7 @@ #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" @@ -24,11 +25,13 @@ * ExecutionSession - provides context for our running JIT’d code (including the string pool, * global mutex, and error reporting facilities) * - * RTDyldObjectLinkingLayer - can be used to add object files to our JIT + * RTDyldObjectLinkingLayer - linker layer * - * IRCompileLayer - can be used to add LLVM Modules to our JIT (builds on the ObjectLayer) + * IRCompileLayer - compiler layer * - * DataLayout and MangleAndInterner - used for symbol mangling + * DataLayout - specifies how data is to be laid out in memory + * + * MangleAndInterner - for symbol mangling * * LLVMContext - llvm core * @@ -36,9 +39,7 @@ * return std::make_unique() - builds a JIT memory manager * for each module that is added * - * ConcurrentIRCompiler - used the JITTargetMachineBuilder to build llvm TargetMachines - * - * JITDylib - A symbol table that supports asynchoronous symbol queries + * JITDylib - a symbol table that supports asynchoronous symbol queries * */ namespace impala { namespace engine { @@ -64,7 +65,7 @@ class Jit { 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); + 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); @@ -81,6 +82,7 @@ class Jit { private: Jit(); + llvm::orc::ExecutionSession ES; std::unique_ptr objectLayer{nullptr}; std::unique_ptr compileLayer{nullptr}; @@ -90,6 +92,7 @@ class Jit { std::unique_ptr mangle{nullptr}; std::unique_ptr context{nullptr}; types::FunctionProtosT externalMathFunctions; + Optimizer optimizer; }; // namespace Jit } // namespace engine } // namespace impala diff --git a/compiler/engine/optimizer.cpp b/compiler/engine/optimizer.cpp new file mode 100644 index 0000000..131525f --- /dev/null +++ b/compiler/engine/optimizer.cpp @@ -0,0 +1,20 @@ +#include "optimizer.h" +#include + +namespace impala { +namespace engine { +Optimizer::Optimizer() { + passBuilder.registerModuleAnalyses(moduleAnalysisManager); + passBuilder.registerCGSCCAnalyses(cGSCCAnalysisManager); + passBuilder.registerFunctionAnalyses(functionAnalysisManager); + passBuilder.registerLoopAnalyses(loopAnalysisManager); + + passBuilder.crossRegisterProxies(loopAnalysisManager, functionAnalysisManager, cGSCCAnalysisManager, + moduleAnalysisManager); + + modulePassManager = passBuilder.buildPerModuleDefaultPipeline(llvm::PassBuilder::OptimizationLevel::O1, false); +} + +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/impalajit.cc b/impalajit.cc index 6683080..67be4b6 100644 --- a/impalajit.cc +++ b/impalajit.cc @@ -83,7 +83,7 @@ void impalajit::Compiler::compile(Options options) { functionSignature.emplace_back(driver.generateLLVMFunction(definition, *currentModule, options)); driver.deleteFunctionContext(); } - jit.addModule(currentModule); + jit.addModule(currentModule, !options.debug); for (auto& signature: functionSignature) { auto function = reinterpret_cast(jit.lookup(signature.first).getAddress()); From d449b7b5fd5601cf4120403e59a77823da9881a0 Mon Sep 17 00:00:00 2001 From: ravil-mobile Date: Mon, 14 Jun 2021 22:09:49 +0200 Subject: [PATCH 27/29] Added selected opt. passes (#8) Co-authored-by: ravil --- compiler/engine/optimizer.cpp | 14 +++++++++++++- example/cpp/CMakeLists.txt | 2 +- impalajit.cc | 2 ++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/compiler/engine/optimizer.cpp b/compiler/engine/optimizer.cpp index 131525f..a2899b9 100644 --- a/compiler/engine/optimizer.cpp +++ b/compiler/engine/optimizer.cpp @@ -1,6 +1,12 @@ #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() { @@ -12,7 +18,13 @@ Optimizer::Optimizer() { passBuilder.crossRegisterProxies(loopAnalysisManager, functionAnalysisManager, cGSCCAnalysisManager, moduleAnalysisManager); - modulePassManager = passBuilder.buildPerModuleDefaultPipeline(llvm::PassBuilder::OptimizationLevel::O1, false); + 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); } diff --git a/example/cpp/CMakeLists.txt b/example/cpp/CMakeLists.txt index 9b83695..c97b3e2 100644 --- a/example/cpp/CMakeLists.txt +++ b/example/cpp/CMakeLists.txt @@ -6,7 +6,7 @@ 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-static) +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/impalajit.cc b/impalajit.cc index 67be4b6..ae97dd3 100644 --- a/impalajit.cc +++ b/impalajit.cc @@ -76,6 +76,8 @@ void impalajit::Compiler::loadFunctionDefinitionsFromInputFiles(std::string _con } 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; From cacc7d15cc86834b7905e8c3a1a2661632fed426 Mon Sep 17 00:00:00 2001 From: ravil-mobile Date: Tue, 15 Jun 2021 15:06:08 +0200 Subject: [PATCH 28/29] Ravil/cmake (#9) * Added cmake impalajit into LLVM namespace Co-authored-by: ravil --- CMakeLists.txt | 5 ++++- tests/install_test/CMakeLists.txt | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 33201c5..d6460f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,7 +84,10 @@ set(IMPALA_CMAKE_FILES lib/impalajit/cmake) install(TARGETS impalajit DESTINATION lib EXPORT ImpalaJITTargets INCLUDES DESTINATION include) -install(EXPORT ImpalaJITTargets DESTINATION ${IMPALA_CMAKE_FILES}) + +install(EXPORT ImpalaJITTargets + NAMESPACE LLVM:: + DESTINATION ${IMPALA_CMAKE_FILES}) install(FILES include/impalajit.hh diff --git a/tests/install_test/CMakeLists.txt b/tests/install_test/CMakeLists.txt index 6f0f79d..dbdae82 100644 --- a/tests/install_test/CMakeLists.txt +++ b/tests/install_test/CMakeLists.txt @@ -5,7 +5,7 @@ find_package(ImpalaJIT REQUIRED) message(STATUS "IMPALAJIT_DIR: ${IMPALAJIT_DIR}") add_executable(${CMAKE_PROJECT_NAME} ${PROJECT_SOURCE_DIR}/example.cc) -target_link_libraries(${CMAKE_PROJECT_NAME} impalajit) +target_link_libraries(${CMAKE_PROJECT_NAME} LLVM::impalajit) file(COPY ${PROJECT_SOURCE_DIR}/example.conf DESTINATION .) file(COPY ${PROJECT_SOURCE_DIR}/impala_file DESTINATION .) From 55786f93229fbfb1577139fc44d595122930796b Mon Sep 17 00:00:00 2001 From: ravil Date: Thu, 17 Jun 2021 17:20:33 +0200 Subject: [PATCH 29/29] Improved CMake based on SeisSol PR --- CMakeLists.txt | 20 ++++++++------------ share/ImpalaJITConfig.cmake.in | 5 +++-- tests/install_test/CMakeLists.txt | 5 ++--- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d6460f3..a58d474 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,13 +80,13 @@ if (TESTS) add_subdirectory(tests) endif() -set(IMPALA_CMAKE_FILES lib/impalajit/cmake) +set(IMPALA_CMAKE_FILES lib/cmake/impalajit-llvm) install(TARGETS impalajit DESTINATION lib - EXPORT ImpalaJITTargets + EXPORT ImpalaJIT-LLVMTargets INCLUDES DESTINATION include) -install(EXPORT ImpalaJITTargets - NAMESPACE LLVM:: +install(EXPORT ImpalaJIT-LLVMTargets + NAMESPACE llvm:: DESTINATION ${IMPALA_CMAKE_FILES}) install(FILES @@ -100,22 +100,18 @@ install(FILES DESTINATION include/impalajit) -install(FILES - DESTINATION - lib/cmake) - include(CMakePackageConfigHelpers) configure_package_config_file(share/ImpalaJITConfig.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/ImpalaJITConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/ImpalaJIT-LLVMConfig.cmake INSTALL_DESTINATION ${IMPALA_CMAKE_FILES}) write_basic_package_version_file( - ${CMAKE_CURRENT_BINARY_DIR}/ImpalaJITConfigVersion.cmake + ${CMAKE_CURRENT_BINARY_DIR}/ImpalaJIT-LLVMConfigVersion.cmake VERSION 1.0.0 COMPATIBILITY SameMajorVersion) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ImpalaJITConfig.cmake - ${CMAKE_CURRENT_BINARY_DIR}/ImpalaJITConfigVersion.cmake +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ImpalaJIT-LLVMConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/ImpalaJIT-LLVMConfigVersion.cmake DESTINATION ${IMPALA_CMAKE_FILES}) diff --git a/share/ImpalaJITConfig.cmake.in b/share/ImpalaJITConfig.cmake.in index d18a293..7b9f9f8 100644 --- a/share/ImpalaJITConfig.cmake.in +++ b/share/ImpalaJITConfig.cmake.in @@ -1,5 +1,6 @@ # - Config file for the ImpalaJIT package # - Using imported targets -get_filename_component(IMPALAJIT_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) -include("${IMPALAJIT_DIR}/ImpalaJITTargets.cmake") +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/install_test/CMakeLists.txt b/tests/install_test/CMakeLists.txt index dbdae82..335c8e2 100644 --- a/tests/install_test/CMakeLists.txt +++ b/tests/install_test/CMakeLists.txt @@ -1,11 +1,10 @@ cmake_minimum_required(VERSION 2.6) project(install_test) -find_package(ImpalaJIT REQUIRED) -message(STATUS "IMPALAJIT_DIR: ${IMPALAJIT_DIR}") +find_package(ImpalaJIT-LLVM REQUIRED) add_executable(${CMAKE_PROJECT_NAME} ${PROJECT_SOURCE_DIR}/example.cc) -target_link_libraries(${CMAKE_PROJECT_NAME} LLVM::impalajit) +target_link_libraries(${CMAKE_PROJECT_NAME} llvm::impalajit) file(COPY ${PROJECT_SOURCE_DIR}/example.conf DESTINATION .) file(COPY ${PROJECT_SOURCE_DIR}/impala_file DESTINATION .)