From 2bea630ba1518cbf0b4482d1d3e0b616b06b932b Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Sun, 4 Jul 2021 23:56:38 +0200 Subject: [PATCH 01/19] Create GeneratorVisitor --- compiler/src/CMakeLists.txt | 4 +- compiler/src/ir/GeneratorVisitor.cpp | 99 ++++++++++++++++++++++++++++ compiler/src/ir/GeneratorVisitor.h | 40 +++++++++++ compiler/src/main.cpp | 4 ++ 4 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 compiler/src/ir/GeneratorVisitor.cpp create mode 100644 compiler/src/ir/GeneratorVisitor.h diff --git a/compiler/src/CMakeLists.txt b/compiler/src/CMakeLists.txt index 1976a7e6f..5ff45eb20 100644 --- a/compiler/src/CMakeLists.txt +++ b/compiler/src/CMakeLists.txt @@ -17,6 +17,8 @@ set(SOURCES analyzer/SymbolTable.h analyzer/SymbolTableEntry.cpp analyzer/SymbolTableEntry.h + ir/GeneratorVisitor.cpp + ir/GeneratorVisitor.h exception/SemanticError.cpp exception/SemanticError.h) @@ -27,4 +29,4 @@ include_directories(${ANTLR_Spice_OUTPUT_DIR}) include_directories(../lib/antlr4/runtime/Cpp/runtime/src) target_link_libraries(${BINARY}_run antlr4_static) -add_library(${BINARY}_lib STATIC ${SOURCES} exception/SemanticError.cpp exception/SemanticError.h analyzer/SymbolTableEntry.cpp analyzer/SymbolTableEntry.h) \ No newline at end of file +add_library(${BINARY}_lib STATIC ${SOURCES}) \ No newline at end of file diff --git a/compiler/src/ir/GeneratorVisitor.cpp b/compiler/src/ir/GeneratorVisitor.cpp new file mode 100644 index 000000000..ef48c519b --- /dev/null +++ b/compiler/src/ir/GeneratorVisitor.cpp @@ -0,0 +1,99 @@ +// Copyright (c) 2021 ChilliBits. All rights reserved. + +#include "GeneratorVisitor.h" + +antlrcpp::Any GeneratorVisitor::visitEntry(SpiceParser::EntryContext *ctx) { + return SpiceBaseVisitor::visitEntry(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitFunctionDef(SpiceParser::FunctionDefContext *ctx) { + return SpiceBaseVisitor::visitFunctionDef(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitProcedureDef(SpiceParser::ProcedureDefContext *ctx) { + return SpiceBaseVisitor::visitProcedureDef(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitForLoop(SpiceParser::ForLoopContext *ctx) { + return SpiceBaseVisitor::visitForLoop(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitWhileLoop(SpiceParser::WhileLoopContext *ctx) { + return SpiceBaseVisitor::visitWhileLoop(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitIfStmt(SpiceParser::IfStmtContext *ctx) { + return SpiceBaseVisitor::visitIfStmt(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitDeclStmt(SpiceParser::DeclStmtContext *ctx) { + return SpiceBaseVisitor::visitDeclStmt(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitFunctionCall(SpiceParser::FunctionCallContext *ctx) { + return SpiceBaseVisitor::visitFunctionCall(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitImportStmt(SpiceParser::ImportStmtContext *ctx) { + return SpiceBaseVisitor::visitImportStmt(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitReturnStmt(SpiceParser::ReturnStmtContext *ctx) { + return SpiceBaseVisitor::visitReturnStmt(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitAssignment(SpiceParser::AssignmentContext *ctx) { + return SpiceBaseVisitor::visitAssignment(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitTernary(SpiceParser::TernaryContext *ctx) { + return SpiceBaseVisitor::visitTernary(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitLogicalOrExpr(SpiceParser::LogicalOrExprContext *ctx) { + return SpiceBaseVisitor::visitLogicalOrExpr(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitLogicalAndExpr(SpiceParser::LogicalAndExprContext *ctx) { + return SpiceBaseVisitor::visitLogicalAndExpr(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitBitwiseOrExpr(SpiceParser::BitwiseOrExprContext *ctx) { + return SpiceBaseVisitor::visitBitwiseOrExpr(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitBitwiseAndExpr(SpiceParser::BitwiseAndExprContext *ctx) { + return SpiceBaseVisitor::visitBitwiseAndExpr(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitEqualityExpr(SpiceParser::EqualityExprContext *ctx) { + return SpiceBaseVisitor::visitEqualityExpr(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitRelationalExpr(SpiceParser::RelationalExprContext *ctx) { + return SpiceBaseVisitor::visitRelationalExpr(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitAdditiveExpr(SpiceParser::AdditiveExprContext *ctx) { + return SpiceBaseVisitor::visitAdditiveExpr(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitMultiplicativeExpr(SpiceParser::MultiplicativeExprContext *ctx) { + return SpiceBaseVisitor::visitMultiplicativeExpr(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitPrefixUnary(SpiceParser::PrefixUnaryContext *ctx) { + return SpiceBaseVisitor::visitPrefixUnary(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitPostfixUnary(SpiceParser::PostfixUnaryContext *ctx) { + return SpiceBaseVisitor::visitPostfixUnary(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitAtomicExpr(SpiceParser::AtomicExprContext *ctx) { + return SpiceBaseVisitor::visitAtomicExpr(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitValue(SpiceParser::ValueContext *ctx) { + return SpiceBaseVisitor::visitValue(ctx); +} diff --git a/compiler/src/ir/GeneratorVisitor.h b/compiler/src/ir/GeneratorVisitor.h new file mode 100644 index 000000000..16d5f269b --- /dev/null +++ b/compiler/src/ir/GeneratorVisitor.h @@ -0,0 +1,40 @@ +// Copyright (c) 2021 ChilliBits. All rights reserved. + +#pragma once + +#include + +class GeneratorVisitor : public SpiceBaseVisitor { +public: + // Public methods + antlrcpp::Any visitEntry(SpiceParser::EntryContext *ctx) override; + antlrcpp::Any visitFunctionDef(SpiceParser::FunctionDefContext *ctx) override; + antlrcpp::Any visitProcedureDef(SpiceParser::ProcedureDefContext *ctx) override; + antlrcpp::Any visitForLoop(SpiceParser::ForLoopContext *ctx) override; + /*antlrcpp::Any visitForeachLoop(SpiceParser::ForeachLoopContext *ctx) override;*/ + antlrcpp::Any visitWhileLoop(SpiceParser::WhileLoopContext *ctx) override; + antlrcpp::Any visitIfStmt(SpiceParser::IfStmtContext *ctx) override; + antlrcpp::Any visitDeclStmt(SpiceParser::DeclStmtContext *ctx) override; + antlrcpp::Any visitFunctionCall(SpiceParser::FunctionCallContext *ctx) override; + antlrcpp::Any visitImportStmt(SpiceParser::ImportStmtContext *ctx) override; + antlrcpp::Any visitReturnStmt(SpiceParser::ReturnStmtContext *ctx) override; + antlrcpp::Any visitAssignment(SpiceParser::AssignmentContext *ctx) override; + antlrcpp::Any visitTernary(SpiceParser::TernaryContext *ctx) override; + antlrcpp::Any visitLogicalOrExpr(SpiceParser::LogicalOrExprContext *ctx) override; + antlrcpp::Any visitLogicalAndExpr(SpiceParser::LogicalAndExprContext *ctx) override; + antlrcpp::Any visitBitwiseOrExpr(SpiceParser::BitwiseOrExprContext *ctx) override; + antlrcpp::Any visitBitwiseAndExpr(SpiceParser::BitwiseAndExprContext *ctx) override; + antlrcpp::Any visitEqualityExpr(SpiceParser::EqualityExprContext *ctx) override; + antlrcpp::Any visitRelationalExpr(SpiceParser::RelationalExprContext *ctx) override; + antlrcpp::Any visitAdditiveExpr(SpiceParser::AdditiveExprContext *ctx) override; + antlrcpp::Any visitMultiplicativeExpr(SpiceParser::MultiplicativeExprContext *ctx) override; + antlrcpp::Any visitPrefixUnary(SpiceParser::PrefixUnaryContext *ctx) override; + antlrcpp::Any visitPostfixUnary(SpiceParser::PostfixUnaryContext *ctx) override; + antlrcpp::Any visitAtomicExpr(SpiceParser::AtomicExprContext *ctx) override; + antlrcpp::Any visitValue(SpiceParser::ValueContext *ctx) override; +private: + // Members + + // Private methods + +}; \ No newline at end of file diff --git a/compiler/src/main.cpp b/compiler/src/main.cpp index 54dbf7d24..c836cd604 100644 --- a/compiler/src/main.cpp +++ b/compiler/src/main.cpp @@ -5,6 +5,7 @@ #include "SpiceLexer.h" #include "SpiceParser.h" #include "analyzer/AnalyzerVisitor.h" +#include "ir/GeneratorVisitor.h" using namespace antlr4; @@ -23,6 +24,9 @@ int main(int argc, char** argv) { antlr4::tree::ParseTree *tree = parser.entry(); SymbolTable* symbolTable = AnalyzerVisitor().visit(tree).as(); + // Execute ir generator + GeneratorVisitor().visit(tree); + // Return with positive result code return 0; } \ No newline at end of file From df32e5660322336ac2ee713f911d6d3c5087087a Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Tue, 6 Jul 2021 20:32:39 +0200 Subject: [PATCH 02/19] Include LLVM into the project --- build.bat | 2 +- compiler/.run/Spice_run.run.xml | 7 +++++++ compiler/src/CMakeLists.txt | 16 +++++++++++++++- compiler/src/ir/GeneratorVisitor.cpp | 7 ++++++- compiler/src/ir/GeneratorVisitor.h | 19 ++++++++++++++++++- 5 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 compiler/.run/Spice_run.run.xml diff --git a/build.bat b/build.bat index 3f8ef58e7..e1f19b5f5 100644 --- a/build.bat +++ b/build.bat @@ -3,7 +3,7 @@ mkdir bin 2> NUL cd bin cmake -DCMAKE_BUILD_TYPE=Release -G "CodeBlocks - MinGW Makefiles" ../compiler -cmake --build . --target Spice_run -- -j 6 +cmake --target Spice_run --build . -- -j 6 move src\Spice_run.exe spicec.exe diff --git a/compiler/.run/Spice_run.run.xml b/compiler/.run/Spice_run.run.xml new file mode 100644 index 000000000..7be03020f --- /dev/null +++ b/compiler/.run/Spice_run.run.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/compiler/src/CMakeLists.txt b/compiler/src/CMakeLists.txt index 5ff45eb20..1f559426f 100644 --- a/compiler/src/CMakeLists.txt +++ b/compiler/src/CMakeLists.txt @@ -1,4 +1,5 @@ set(BINARY ${CMAKE_PROJECT_NAME}) +set(LLVM_DIR C:/Users/i516467/Documents/JustForFunGitHubClones/llvm-project/build/lib/cmake/llvm) LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) @@ -9,6 +10,15 @@ set(ANTLR_EXECUTABLE ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/antlr/antlr-4.9.2-co find_package(ANTLR REQUIRED) antlr_target(Spice ${CMAKE_CURRENT_SOURCE_DIR}/grammar/Spice.g4 VISITOR) +find_package(LLVM REQUIRED CONFIG) + +message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") +message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + +include_directories(${LLVM_INCLUDE_DIRS}) +separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS}) +add_definitions(${LLVM_DEFINITIONS_LIST}) + set(SOURCES main.cpp analyzer/AnalyzerVisitor.cpp @@ -24,9 +34,13 @@ set(SOURCES add_executable(${BINARY}_run ${SOURCES} ${ANTLR_Spice_CXX_OUTPUTS}) +llvm_map_components_to_libnames(LLVM_LIBS core support irreader) + include_directories(${ANTLR4CPP_INCLUDE_DIRS}) include_directories(${ANTLR_Spice_OUTPUT_DIR}) include_directories(../lib/antlr4/runtime/Cpp/runtime/src) target_link_libraries(${BINARY}_run antlr4_static) -add_library(${BINARY}_lib STATIC ${SOURCES}) \ No newline at end of file +target_link_libraries(${BINARY}_run ${LLVM_LIBS}) + +add_library(${BINARY}_lib STATIC ${SOURCES} ${ANTLR_Spice_CXX_OUTPUTS}) \ No newline at end of file diff --git a/compiler/src/ir/GeneratorVisitor.cpp b/compiler/src/ir/GeneratorVisitor.cpp index ef48c519b..7698760c2 100644 --- a/compiler/src/ir/GeneratorVisitor.cpp +++ b/compiler/src/ir/GeneratorVisitor.cpp @@ -95,5 +95,10 @@ antlrcpp::Any GeneratorVisitor::visitAtomicExpr(SpiceParser::AtomicExprContext * } antlrcpp::Any GeneratorVisitor::visitValue(SpiceParser::ValueContext *ctx) { - return SpiceBaseVisitor::visitValue(ctx); + if (ctx->DOUBLE()) + return llvm::ConstantFP::get(context, llvm::APFloat(std::stod(ctx->DOUBLE()->toString()))); + if (ctx->INTEGER()) + return llvm::ConstantInt::get(context, llvm::APInt(32, + std::stoi(ctx->INTEGER()->toString()), false)); + } diff --git a/compiler/src/ir/GeneratorVisitor.h b/compiler/src/ir/GeneratorVisitor.h index 16d5f269b..602a46cc2 100644 --- a/compiler/src/ir/GeneratorVisitor.h +++ b/compiler/src/ir/GeneratorVisitor.h @@ -3,9 +3,23 @@ #pragma once #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include class GeneratorVisitor : public SpiceBaseVisitor { public: + // Constructors + explicit GeneratorVisitor(): builder(context) {}; // Public methods antlrcpp::Any visitEntry(SpiceParser::EntryContext *ctx) override; antlrcpp::Any visitFunctionDef(SpiceParser::FunctionDefContext *ctx) override; @@ -34,7 +48,10 @@ class GeneratorVisitor : public SpiceBaseVisitor { antlrcpp::Any visitValue(SpiceParser::ValueContext *ctx) override; private: // Members - + llvm::LLVMContext context; + llvm::IRBuilder<> builder; + std::unique_ptr module; + std::map namedValues; // Private methods }; \ No newline at end of file From 79cdf217642e797cac96647506f1dd6b25ff1820 Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Wed, 7 Jul 2021 15:32:41 +0200 Subject: [PATCH 03/19] Add first generator visitor method --- build.bat | 4 +- compiler/src/CMakeLists.txt | 24 ++++++++- compiler/src/exception/IRError.cpp | 7 +++ compiler/src/exception/IRError.h | 38 ++++++++++++++ compiler/src/ir/GeneratorVisitor.cpp | 78 ++++++++++++++++++++++++++-- compiler/src/ir/GeneratorVisitor.h | 27 +++++++--- compiler/src/main.cpp | 3 +- media/test-code.spice | 2 +- 8 files changed, 166 insertions(+), 17 deletions(-) create mode 100644 compiler/src/exception/IRError.cpp create mode 100644 compiler/src/exception/IRError.h diff --git a/build.bat b/build.bat index e1f19b5f5..57387fc4a 100644 --- a/build.bat +++ b/build.bat @@ -2,8 +2,8 @@ mkdir bin 2> NUL cd bin -cmake -DCMAKE_BUILD_TYPE=Release -G "CodeBlocks - MinGW Makefiles" ../compiler -cmake --target Spice_run --build . -- -j 6 +cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -G "CodeBlocks - MinGW Makefiles" ../compiler +cmake --build . --target Spice_run -- -j 6 move src\Spice_run.exe spicec.exe diff --git a/compiler/src/CMakeLists.txt b/compiler/src/CMakeLists.txt index 1f559426f..e9dc0001b 100644 --- a/compiler/src/CMakeLists.txt +++ b/compiler/src/CMakeLists.txt @@ -30,11 +30,31 @@ set(SOURCES ir/GeneratorVisitor.cpp ir/GeneratorVisitor.h exception/SemanticError.cpp - exception/SemanticError.h) + exception/SemanticError.h + exception/IRError.cpp + exception/IRError.h) add_executable(${BINARY}_run ${SOURCES} ${ANTLR_Spice_CXX_OUTPUTS}) -llvm_map_components_to_libnames(LLVM_LIBS core support irreader) +llvm_map_components_to_libnames(LLVM_LIBS aarch64asmparser aarch64codegen aarch64desc aarch64disassembler + aarch64info aarch64utils aggressiveinstcombine amdgpuasmparser amdgpucodegen amdgpudesc amdgpudisassembler + amdgpuinfo amdgpuutils analysis armasmparser armcodegen armdesc armdisassembler arminfo armutils asmparser + asmprinter avrasmparser avrcodegen avrdesc avrdisassembler avrinfo binaryformat bitreader bitstreamreader + bitwriter bpfasmparser bpfcodegen bpfdesc bpfdisassembler bpfinfo cfguard codegen core coroutines coverage + debuginfocodeview debuginfodwarf debuginfogsym debuginfomsf debuginfopdb demangle dlltooldriver dwarflinker + executionengine extensions filecheck frontendopenacc frontendopenmp fuzzmutate globalisel hexagonasmparser + hexagoncodegen hexagondesc hexagondisassembler hexagoninfo instcombine instrumentation interfacestub + interpreter ipo irreader lanaiasmparser lanaicodegen lanaidesc lanaidisassembler lanaiinfo libdriver lineeditor + linker lto mc mca mcdisassembler mcparser mipsasmparser mipscodegen mipsdesc mipsdisassembler mipsinfo + mirparser msp430asmparser msp430codegen msp430desc msp430disassembler msp430info native nativecodegen + nvptxcodegen nvptxdesc nvptxinfo objcarcopts object objectyaml option orcshared orctargetprocess passes + powerpcasmparser powerpccodegen powerpcdesc powerpcdisassembler powerpcinfo profiledata remarks riscvasmparser + riscvcodegen riscvdesc riscvdisassembler riscvinfo runtimedyld scalaropts selectiondag sparcasmparser + sparccodegen sparcdesc sparcdisassembler sparcinfo support symbolize systemzasmparser systemzcodegen + systemzdesc systemzdisassembler systemzinfo tablegen target textapi transformutils vectorize + webassemblyasmparser webassemblycodegen webassemblydesc webassemblydisassembler webassemblyinfo + webassemblyutils windowsmanifest x86asmparser x86codegen x86desc x86disassembler x86info xcorecodegen xcoredesc + xcoredisassembler xcoreinfo xray) include_directories(${ANTLR4CPP_INCLUDE_DIRS}) include_directories(${ANTLR_Spice_OUTPUT_DIR}) diff --git a/compiler/src/exception/IRError.cpp b/compiler/src/exception/IRError.cpp new file mode 100644 index 000000000..5674424e1 --- /dev/null +++ b/compiler/src/exception/IRError.cpp @@ -0,0 +1,7 @@ +// Copyright (c) 2021 ChilliBits. All rights reserved. + +#include "IRError.h" + +const char *IRError::what() const noexcept { + return errorMessage.c_str(); +} diff --git a/compiler/src/exception/IRError.h b/compiler/src/exception/IRError.h new file mode 100644 index 000000000..6f3067af3 --- /dev/null +++ b/compiler/src/exception/IRError.h @@ -0,0 +1,38 @@ +// Copyright (c) 2021 ChilliBits. All rights reserved. + +#pragma once + +#include +#include + +enum IRErrorType { + TARGET_NOT_AVAILABLE, + CANT_OPEN_OUTPUT_FILE, + WRONG_TYPE, +}; + +class IRError : public std::exception { +public: + // Constructors + explicit IRError(IRErrorType type, const std::string& message) { + std::string messagePrefix; + switch (type) { + case TARGET_NOT_AVAILABLE: + messagePrefix = "Selected target not available"; + break; + case CANT_OPEN_OUTPUT_FILE: + messagePrefix = "Could not open output file"; + break; + case WRONG_TYPE: + messagePrefix = "Wrong type of output file"; + break; + } + errorMessage = messagePrefix + ": " + message; + } + + // Public methods + const char * what() const noexcept override; +private: + // Members + std::string errorMessage {}; +}; \ No newline at end of file diff --git a/compiler/src/ir/GeneratorVisitor.cpp b/compiler/src/ir/GeneratorVisitor.cpp index 7698760c2..3355f8958 100644 --- a/compiler/src/ir/GeneratorVisitor.cpp +++ b/compiler/src/ir/GeneratorVisitor.cpp @@ -2,8 +2,49 @@ #include "GeneratorVisitor.h" +GeneratorVisitor::GeneratorVisitor() { + // Initialize LLVM + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargets(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmParsers(); + llvm::InitializeAllAsmPrinters(); + + // Configure output target + // ToDo: Make target customizable by setting an cli arg or similar + auto targetTriple = llvm::sys::getDefaultTargetTriple(); + module->setTargetTriple(targetTriple); + + // Search after selected target + std::string error; + auto target = llvm::TargetRegistry::lookupTarget(targetTriple, error); + if (!target) throw IRError(TARGET_NOT_AVAILABLE, "Selected target was not found: " + error); + + auto cpu = "generic"; + auto features = ""; + + llvm::TargetOptions opt; + auto rm = llvm::Optional(); + auto targetMachine = target->createTargetMachine(targetTriple, cpu, features, opt, rm); + + module->setDataLayout(targetMachine->createDataLayout()); + + std::string filename = "output.o"; + std::error_code errorCode; + llvm::raw_fd_ostream dest(filename, errorCode, llvm::sys::fs::OF_None); + if (errorCode) throw IRError(CANT_OPEN_OUTPUT_FILE, "File '" + filename + "' could not be opened"); + + llvm::legacy::PassManager pass; + auto FileType = llvm::CGFT_ObjectFile; + if (targetMachine->addPassesToEmitFile(pass, dest, nullptr, FileType)) + throw IRError(WRONG_TYPE, "Target machine can't emit a file of this type"); + + pass.run(*module); + dest.flush(); +} + antlrcpp::Any GeneratorVisitor::visitEntry(SpiceParser::EntryContext *ctx) { - return SpiceBaseVisitor::visitEntry(ctx); + return getIRString(); } antlrcpp::Any GeneratorVisitor::visitFunctionDef(SpiceParser::FunctionDefContext *ctx) { @@ -96,9 +137,36 @@ antlrcpp::Any GeneratorVisitor::visitAtomicExpr(SpiceParser::AtomicExprContext * antlrcpp::Any GeneratorVisitor::visitValue(SpiceParser::ValueContext *ctx) { if (ctx->DOUBLE()) - return llvm::ConstantFP::get(context, llvm::APFloat(std::stod(ctx->DOUBLE()->toString()))); - if (ctx->INTEGER()) - return llvm::ConstantInt::get(context, llvm::APInt(32, - std::stoi(ctx->INTEGER()->toString()), false)); + return llvm::ConstantFP::get(*context, llvm::APFloat(std::stod(ctx->DOUBLE()->toString()))); + if (ctx->INTEGER()) + return llvm::ConstantInt::getSigned(llvm::Type::getInt32Ty(*context), + std::stoi(ctx->INTEGER()->toString())); + if (ctx->STRING()) { + std::string value = ctx->STRING()->toString(); + auto charType = llvm::IntegerType::get(*context, 8); + std::vector chars(value.size()); + for(unsigned int i = 0; i < value.size(); i++) + chars[i] = llvm::ConstantInt::get(charType, value[i]); + return llvm::ConstantArray::get(llvm::ArrayType::get(charType, chars.size()), chars); + } + + if (ctx->TRUE() || ctx->FALSE()) + return llvm::ConstantInt::getSigned((llvm::Type::getInt1Ty(*context)), ctx->TRUE() ? 1 : 0); + + if (ctx->IDENTIFIER()) { + llvm::Value* var = namedValues[ctx->IDENTIFIER()->toString()]; + if (!var) throw std::runtime_error("Internal compiler error - Variable not found in code generation step"); + return builder->CreateLoad(llvm::Type::getDoubleTy(*context), var, + ctx->IDENTIFIER()->toString().c_str()); + } + + return nullptr; +} + +std::string GeneratorVisitor::getIRString() { + std::string output; + llvm::raw_string_ostream oss(output); + module->print(oss, nullptr); + return oss.str(); } diff --git a/compiler/src/ir/GeneratorVisitor.h b/compiler/src/ir/GeneratorVisitor.h index 602a46cc2..f680dbc8c 100644 --- a/compiler/src/ir/GeneratorVisitor.h +++ b/compiler/src/ir/GeneratorVisitor.h @@ -3,23 +3,37 @@ #pragma once #include +#include + #include -#include +#include #include #include #include #include #include +#include #include #include +#include #include #include #include +#include +#include +#include +#include +#include +#include +#include + +#include class GeneratorVisitor : public SpiceBaseVisitor { public: // Constructors - explicit GeneratorVisitor(): builder(context) {}; + GeneratorVisitor(); + // Public methods antlrcpp::Any visitEntry(SpiceParser::EntryContext *ctx) override; antlrcpp::Any visitFunctionDef(SpiceParser::FunctionDefContext *ctx) override; @@ -48,10 +62,11 @@ class GeneratorVisitor : public SpiceBaseVisitor { antlrcpp::Any visitValue(SpiceParser::ValueContext *ctx) override; private: // Members - llvm::LLVMContext context; - llvm::IRBuilder<> builder; - std::unique_ptr module; + std::unique_ptr context = std::make_unique(); + std::unique_ptr> builder = std::make_unique>(*context); + std::unique_ptr module = std::make_unique("Module", *context); std::map namedValues; - // Private methods + // Private methods + std::string getIRString(); }; \ No newline at end of file diff --git a/compiler/src/main.cpp b/compiler/src/main.cpp index c836cd604..194493e66 100644 --- a/compiler/src/main.cpp +++ b/compiler/src/main.cpp @@ -22,7 +22,8 @@ int main(int argc, char** argv) { // Execute syntactical analysis antlr4::tree::ParseTree *tree = parser.entry(); - SymbolTable* symbolTable = AnalyzerVisitor().visit(tree).as(); + AnalyzerVisitor().visit(tree); + //SymbolTable* symbolTable = AnalyzerVisitor().visit(tree).as(); // Execute ir generator GeneratorVisitor().visit(tree); diff --git a/media/test-code.spice b/media/test-code.spice index da86d1b9f..6d482fe23 100644 --- a/media/test-code.spice +++ b/media/test-code.spice @@ -27,5 +27,5 @@ p testProcedure(string stringParam, bool boolParam = false) { double result = testString == "" || testBool ? 5.0 : 1.4; if result == 5.0 { result = 3.0; } int result1 = testFunction(3.0); - testProcedure("test", false, 123); + testProcedure("test", false); } \ No newline at end of file From f5501eff3b053fcfbf79735b39badeededf62cdb Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Wed, 7 Jul 2021 23:24:34 +0200 Subject: [PATCH 04/19] Limit the number of imported LLVM libs --- README.md | 6 +++++- compiler/src/CMakeLists.txt | 34 ++++++++++++++++------------------ 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 9217e03aa..d731017c2 100644 --- a/README.md +++ b/README.md @@ -30,4 +30,8 @@ The Spice grammar can be found [here](./compiler/src/grammar/Spice.g4) as a ANTL - Something like `"Test" * 3` is valid and will evaluate to `"TestTestTest"` - Alternatively to the return statement in a function, you can also assign variable `result` with a value, which was automatically declared by the function header - Unary minus has to be applied without a space between (e.g.: `-3.4`) and binary minus has to be applied with a space beween (e.g.: `n - 5`) -- Default values of function/procedure parameters are possible e.g.: `f test(int param = 2) {}` \ No newline at end of file +- Default values of function/procedure parameters are possible e.g.: `f test(int param = 2) {}` + +## CMake instructions for building +`cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS_RELEASE="-O2" -G "CodeBlocks - MinGW Makefiles" ../llvm` +`cmake --build .` \ No newline at end of file diff --git a/compiler/src/CMakeLists.txt b/compiler/src/CMakeLists.txt index e9dc0001b..84879f4a7 100644 --- a/compiler/src/CMakeLists.txt +++ b/compiler/src/CMakeLists.txt @@ -1,5 +1,5 @@ set(BINARY ${CMAKE_PROJECT_NAME}) -set(LLVM_DIR C:/Users/i516467/Documents/JustForFunGitHubClones/llvm-project/build/lib/cmake/llvm) +set(LLVM_DIR C:/Users/i516467/Documents/JustForFunGitHubClones/llvm-project/build-release/lib/cmake/llvm) LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) @@ -37,24 +37,22 @@ set(SOURCES add_executable(${BINARY}_run ${SOURCES} ${ANTLR_Spice_CXX_OUTPUTS}) llvm_map_components_to_libnames(LLVM_LIBS aarch64asmparser aarch64codegen aarch64desc aarch64disassembler - aarch64info aarch64utils aggressiveinstcombine amdgpuasmparser amdgpucodegen amdgpudesc amdgpudisassembler - amdgpuinfo amdgpuutils analysis armasmparser armcodegen armdesc armdisassembler arminfo armutils asmparser - asmprinter avrasmparser avrcodegen avrdesc avrdisassembler avrinfo binaryformat bitreader bitstreamreader - bitwriter bpfasmparser bpfcodegen bpfdesc bpfdisassembler bpfinfo cfguard codegen core coroutines coverage - debuginfocodeview debuginfodwarf debuginfogsym debuginfomsf debuginfopdb demangle dlltooldriver dwarflinker - executionengine extensions filecheck frontendopenacc frontendopenmp fuzzmutate globalisel hexagonasmparser - hexagoncodegen hexagondesc hexagondisassembler hexagoninfo instcombine instrumentation interfacestub - interpreter ipo irreader lanaiasmparser lanaicodegen lanaidesc lanaidisassembler lanaiinfo libdriver lineeditor - linker lto mc mca mcdisassembler mcparser mipsasmparser mipscodegen mipsdesc mipsdisassembler mipsinfo - mirparser msp430asmparser msp430codegen msp430desc msp430disassembler msp430info native nativecodegen - nvptxcodegen nvptxdesc nvptxinfo objcarcopts object objectyaml option orcshared orctargetprocess passes - powerpcasmparser powerpccodegen powerpcdesc powerpcdisassembler powerpcinfo profiledata remarks riscvasmparser - riscvcodegen riscvdesc riscvdisassembler riscvinfo runtimedyld scalaropts selectiondag sparcasmparser - sparccodegen sparcdesc sparcdisassembler sparcinfo support symbolize systemzasmparser systemzcodegen - systemzdesc systemzdisassembler systemzinfo tablegen target textapi transformutils vectorize + aarch64info aarch64utils amdgpuasmparser amdgpucodegen amdgpudesc amdgpudisassembler + amdgpuinfo amdgpuutils armasmparser armcodegen armdesc armdisassembler arminfo armutils asmparser + asmprinter avrasmparser avrcodegen avrdesc avrdisassembler avrinfo + bpfasmparser bpfcodegen bpfdesc bpfdisassembler bpfinfo codegen core + hexagonasmparser hexagoncodegen hexagondesc hexagondisassembler hexagoninfo + irreader lanaiasmparser lanaicodegen lanaidesc lanaidisassembler lanaiinfo + mipsasmparser mipscodegen mipsdesc mipsdisassembler mipsinfo + mirparser msp430asmparser msp430codegen msp430desc msp430disassembler msp430info + nvptxcodegen nvptxdesc nvptxinfo + powerpcasmparser powerpccodegen powerpcdesc powerpcdisassembler powerpcinfo riscvasmparser + riscvcodegen riscvdesc riscvdisassembler riscvinfo sparcasmparser + sparccodegen sparcdesc sparcdisassembler sparcinfo support systemzasmparser systemzcodegen + systemzdesc systemzdisassembler systemzinfo webassemblyasmparser webassemblycodegen webassemblydesc webassemblydisassembler webassemblyinfo - webassemblyutils windowsmanifest x86asmparser x86codegen x86desc x86disassembler x86info xcorecodegen xcoredesc - xcoredisassembler xcoreinfo xray) + webassemblyutils x86asmparser x86codegen x86desc x86disassembler x86info xcorecodegen xcoredesc + xcoredisassembler xcoreinfo) include_directories(${ANTLR4CPP_INCLUDE_DIRS}) include_directories(${ANTLR_Spice_OUTPUT_DIR}) From ecbd21885b35e84d6f8d48a49cf1653f4658dbfa Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Fri, 9 Jul 2021 21:50:33 +0200 Subject: [PATCH 05/19] Separate init and emit steps --- compiler/src/ir/GeneratorVisitor.cpp | 20 ++++++++++++++++---- compiler/src/ir/GeneratorVisitor.h | 5 ++--- compiler/src/main.cpp | 6 ++++-- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/compiler/src/ir/GeneratorVisitor.cpp b/compiler/src/ir/GeneratorVisitor.cpp index 3355f8958..f5681327a 100644 --- a/compiler/src/ir/GeneratorVisitor.cpp +++ b/compiler/src/ir/GeneratorVisitor.cpp @@ -2,14 +2,16 @@ #include "GeneratorVisitor.h" -GeneratorVisitor::GeneratorVisitor() { +void GeneratorVisitor::init() { // Initialize LLVM llvm::InitializeAllTargetInfos(); llvm::InitializeAllTargets(); llvm::InitializeAllTargetMCs(); llvm::InitializeAllAsmParsers(); llvm::InitializeAllAsmPrinters(); +} +void GeneratorVisitor::emit() { // Configure output target // ToDo: Make target customizable by setting an cli arg or similar auto targetTriple = llvm::sys::getDefaultTargetTriple(); @@ -29,6 +31,7 @@ GeneratorVisitor::GeneratorVisitor() { module->setDataLayout(targetMachine->createDataLayout()); + // Open file output stream std::string filename = "output.o"; std::error_code errorCode; llvm::raw_fd_ostream dest(filename, errorCode, llvm::sys::fs::OF_None); @@ -39,6 +42,7 @@ GeneratorVisitor::GeneratorVisitor() { if (targetMachine->addPassesToEmitFile(pass, dest, nullptr, FileType)) throw IRError(WRONG_TYPE, "Target machine can't emit a file of this type"); + // Emit object file pass.run(*module); dest.flush(); } @@ -136,12 +140,16 @@ antlrcpp::Any GeneratorVisitor::visitAtomicExpr(SpiceParser::AtomicExprContext * } antlrcpp::Any GeneratorVisitor::visitValue(SpiceParser::ValueContext *ctx) { + // Value is a double constant if (ctx->DOUBLE()) return llvm::ConstantFP::get(*context, llvm::APFloat(std::stod(ctx->DOUBLE()->toString()))); + // Value is an integer constant if (ctx->INTEGER()) return llvm::ConstantInt::getSigned(llvm::Type::getInt32Ty(*context), std::stoi(ctx->INTEGER()->toString())); + + // Value is a string constant if (ctx->STRING()) { std::string value = ctx->STRING()->toString(); auto charType = llvm::IntegerType::get(*context, 8); @@ -151,16 +159,20 @@ antlrcpp::Any GeneratorVisitor::visitValue(SpiceParser::ValueContext *ctx) { return llvm::ConstantArray::get(llvm::ArrayType::get(charType, chars.size()), chars); } + // Value is a boolean constant if (ctx->TRUE() || ctx->FALSE()) return llvm::ConstantInt::getSigned((llvm::Type::getInt1Ty(*context)), ctx->TRUE() ? 1 : 0); + // Value is an identifier if (ctx->IDENTIFIER()) { llvm::Value* var = namedValues[ctx->IDENTIFIER()->toString()]; if (!var) throw std::runtime_error("Internal compiler error - Variable not found in code generation step"); - return builder->CreateLoad(llvm::Type::getDoubleTy(*context), var, - ctx->IDENTIFIER()->toString().c_str()); + return var; } + // Value is a function call + + return nullptr; } @@ -169,4 +181,4 @@ std::string GeneratorVisitor::getIRString() { llvm::raw_string_ostream oss(output); module->print(oss, nullptr); return oss.str(); -} +} \ No newline at end of file diff --git a/compiler/src/ir/GeneratorVisitor.h b/compiler/src/ir/GeneratorVisitor.h index f680dbc8c..4df277a97 100644 --- a/compiler/src/ir/GeneratorVisitor.h +++ b/compiler/src/ir/GeneratorVisitor.h @@ -31,10 +31,9 @@ class GeneratorVisitor : public SpiceBaseVisitor { public: - // Constructors - GeneratorVisitor(); - // Public methods + void init(); + void emit(); antlrcpp::Any visitEntry(SpiceParser::EntryContext *ctx) override; antlrcpp::Any visitFunctionDef(SpiceParser::FunctionDefContext *ctx) override; antlrcpp::Any visitProcedureDef(SpiceParser::ProcedureDefContext *ctx) override; diff --git a/compiler/src/main.cpp b/compiler/src/main.cpp index 194493e66..1ca2d8a46 100644 --- a/compiler/src/main.cpp +++ b/compiler/src/main.cpp @@ -23,10 +23,12 @@ int main(int argc, char** argv) { // Execute syntactical analysis antlr4::tree::ParseTree *tree = parser.entry(); AnalyzerVisitor().visit(tree); - //SymbolTable* symbolTable = AnalyzerVisitor().visit(tree).as(); // Execute ir generator - GeneratorVisitor().visit(tree); + GeneratorVisitor generator = GeneratorVisitor(); + generator.init(); + generator.visit(tree); + generator.emit(); // Return with positive result code return 0; From 578fb56775d1b373ed0a96504f5d2e777b64ee9c Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Sat, 10 Jul 2021 00:17:47 +0200 Subject: [PATCH 06/19] Add generator methods for additive, multiplicative and unary operators --- compiler/src/ir/GeneratorVisitor.cpp | 84 ++++++++++++++++++++++++++-- compiler/src/ir/GeneratorVisitor.h | 2 + compiler/src/main.cpp | 14 +++-- 3 files changed, 88 insertions(+), 12 deletions(-) diff --git a/compiler/src/ir/GeneratorVisitor.cpp b/compiler/src/ir/GeneratorVisitor.cpp index f5681327a..b7e9acdc8 100644 --- a/compiler/src/ir/GeneratorVisitor.cpp +++ b/compiler/src/ir/GeneratorVisitor.cpp @@ -11,6 +11,34 @@ void GeneratorVisitor::init() { llvm::InitializeAllAsmPrinters(); } +void GeneratorVisitor::optimize() { + /*// Register optimization passes + std::unique_ptr functionPassManager = + llvm::make_unique(module.get()); + + // Promote allocas to registers. + functionPassManager->add(llvm::createPromoteMemoryToRegisterPass()); + // Do simple "peephole" optimizations + functionPassManager->add(llvm::createInstructionCombiningPass()); + // Reassociate expressions. + functionPassManager->add(llvm::createReassociatePass()); + // Eliminate Common SubExpressions. + functionPassManager->add(llvm::createGVNPass()); + // Simplify the control flow graph (deleting unreachable blocks etc). + functionPassManager->add(llvm::createCFGSimplificationPass()); + + functionPassManager->doInitialization(); + + for (auto &function : functions) { + llvm::Function *llvmFun = + module->getFunction(llvm::StringRef(function->functionName)); + functionPassManager->run(*llvmFun); + } + + llvm::Function *llvmMainFun = module->getFunction(llvm::StringRef("main")); + functionPassManager->run(*llvmMainFun);*/ +} + void GeneratorVisitor::emit() { // Configure output target // ToDo: Make target customizable by setting an cli arg or similar @@ -47,6 +75,10 @@ void GeneratorVisitor::emit() { dest.flush(); } +void GeneratorVisitor::dumpIR() { + module->print(llvm::outs(), nullptr); +} + antlrcpp::Any GeneratorVisitor::visitEntry(SpiceParser::EntryContext *ctx) { return getIRString(); } @@ -120,23 +152,63 @@ antlrcpp::Any GeneratorVisitor::visitRelationalExpr(SpiceParser::RelationalExprC } antlrcpp::Any GeneratorVisitor::visitAdditiveExpr(SpiceParser::AdditiveExprContext *ctx) { - return SpiceBaseVisitor::visitAdditiveExpr(ctx); + if (ctx->multiplicativeExpr().size() > 1) { + auto lhs = visit(ctx->multiplicativeExpr()[0]).as(); + for (int i = 1; i < ctx->multiplicativeExpr().size(); i++) { + auto rhs = visit(ctx->multiplicativeExpr()[i]).as(); + if (ctx->PLUS()[i-1]) + lhs = builder->CreateAdd(lhs, rhs, "add"); + else + lhs = builder->CreateSub(lhs, rhs, "sub"); + } + } + return visit(ctx->multiplicativeExpr()[0]); } antlrcpp::Any GeneratorVisitor::visitMultiplicativeExpr(SpiceParser::MultiplicativeExprContext *ctx) { - return SpiceBaseVisitor::visitMultiplicativeExpr(ctx); + if (ctx->prefixUnary().size() > 1) { + auto lhs = visit(ctx->prefixUnary()[0]).as(); + for (int i = 1; i < ctx->prefixUnary().size(); i++) { + auto rhs = visit(ctx->prefixUnary()[i]).as(); + if (ctx->MUL()[i-1]) + lhs = builder->CreateMul(lhs, rhs, "mul"); + else + lhs = builder->CreateSDiv(lhs, rhs, "div"); + } + return lhs; + } + return visit(ctx->prefixUnary()[0]); } antlrcpp::Any GeneratorVisitor::visitPrefixUnary(SpiceParser::PrefixUnaryContext *ctx) { - return SpiceBaseVisitor::visitPrefixUnary(ctx); + auto value = visit(ctx->postfixUnary()).as(); + + // Prefix unary is: PLUS_PLUS postfixUnary + if (ctx->PLUS_PLUS()) return builder->CreateAdd(value, builder->getInt32(1), "++ prefix"); + + // Prefix unary is: MINUS_MINUS postfixUnary + if (ctx->MINUS_MINUS()) return builder->CreateSub(value, builder->getInt32(1), "-- prefix"); + + // Prefix unary is: NOT postfixUnary + return builder->CreateNot(value, "not"); } antlrcpp::Any GeneratorVisitor::visitPostfixUnary(SpiceParser::PostfixUnaryContext *ctx) { - return SpiceBaseVisitor::visitPostfixUnary(ctx); + auto value = visit(ctx->atomicExpr()).as(); + + // Postfix unary is: PLUS_PLUS atomicExpr + if (ctx->PLUS_PLUS()) return builder->CreateAdd(value, builder->getInt32(1), "++ postfix"); + + // Postfix unary is: MINUS_MINUS atomicExpr + return builder->CreateSub(value, builder->getInt32(1), "-- postfix"); } antlrcpp::Any GeneratorVisitor::visitAtomicExpr(SpiceParser::AtomicExprContext *ctx) { - return SpiceBaseVisitor::visitAtomicExpr(ctx); + // Atomic expr is: LPAREN value RPAREN + if (ctx->LPAREN()) return visit(ctx->assignment()); + + // Atomic expr is: value + return visit(ctx->value()); } antlrcpp::Any GeneratorVisitor::visitValue(SpiceParser::ValueContext *ctx) { @@ -181,4 +253,4 @@ std::string GeneratorVisitor::getIRString() { llvm::raw_string_ostream oss(output); module->print(oss, nullptr); return oss.str(); -} \ No newline at end of file +} diff --git a/compiler/src/ir/GeneratorVisitor.h b/compiler/src/ir/GeneratorVisitor.h index 4df277a97..668dc4c23 100644 --- a/compiler/src/ir/GeneratorVisitor.h +++ b/compiler/src/ir/GeneratorVisitor.h @@ -33,7 +33,9 @@ class GeneratorVisitor : public SpiceBaseVisitor { public: // Public methods void init(); + void optimize(); void emit(); + void dumpIR(); antlrcpp::Any visitEntry(SpiceParser::EntryContext *ctx) override; antlrcpp::Any visitFunctionDef(SpiceParser::FunctionDefContext *ctx) override; antlrcpp::Any visitProcedureDef(SpiceParser::ProcedureDefContext *ctx) override; diff --git a/compiler/src/main.cpp b/compiler/src/main.cpp index 1ca2d8a46..6722aa2b8 100644 --- a/compiler/src/main.cpp +++ b/compiler/src/main.cpp @@ -18,17 +18,19 @@ int main(int argc, char** argv) { // Parse input to AST SpiceLexer lexer(&input); antlr4::CommonTokenStream tokens((antlr4::TokenSource*) &lexer); - SpiceParser parser(&tokens); + SpiceParser parser(&tokens); // Check for syntax errors // Execute syntactical analysis antlr4::tree::ParseTree *tree = parser.entry(); - AnalyzerVisitor().visit(tree); + AnalyzerVisitor().visit(tree); // Check for semantic errors - // Execute ir generator + // Execute generator GeneratorVisitor generator = GeneratorVisitor(); - generator.init(); - generator.visit(tree); - generator.emit(); + generator.init(); // Initialize code generation + generator.visit(tree); // Generate IR code + generator.dumpIR(); + generator.optimize(); // Optimize IR code + generator.emit(); // Emit object file for specified platform // Return with positive result code return 0; From 06c36357890ea99bbc0bd600d4f3abd85dd39867 Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Sat, 10 Jul 2021 00:37:13 +0200 Subject: [PATCH 07/19] Add generator methods for relational, bitwise and logical operators --- compiler/src/ir/GeneratorVisitor.cpp | 66 +++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 6 deletions(-) diff --git a/compiler/src/ir/GeneratorVisitor.cpp b/compiler/src/ir/GeneratorVisitor.cpp index b7e9acdc8..2c3d65a97 100644 --- a/compiler/src/ir/GeneratorVisitor.cpp +++ b/compiler/src/ir/GeneratorVisitor.cpp @@ -128,27 +128,81 @@ antlrcpp::Any GeneratorVisitor::visitTernary(SpiceParser::TernaryContext *ctx) { } antlrcpp::Any GeneratorVisitor::visitLogicalOrExpr(SpiceParser::LogicalOrExprContext *ctx) { - return SpiceBaseVisitor::visitLogicalOrExpr(ctx); + if (ctx->logicalAndExpr().size() > 1) { + auto lhs = visit(ctx->logicalAndExpr()[0]).as(); + for (int i = 1; i < ctx->logicalAndExpr().size(); i++) { + auto rhs = visit(ctx->logicalAndExpr()[i]).as(); + lhs = builder->CreateLogicalOr(lhs, rhs, "logical or"); + } + } + return visit(ctx->logicalAndExpr()[0]); } antlrcpp::Any GeneratorVisitor::visitLogicalAndExpr(SpiceParser::LogicalAndExprContext *ctx) { - return SpiceBaseVisitor::visitLogicalAndExpr(ctx); + if (ctx->bitwiseOrExpr().size() > 1) { + auto lhs = visit(ctx->bitwiseOrExpr()[0]).as(); + for (int i = 1; i < ctx->bitwiseOrExpr().size(); i++) { + auto rhs = visit(ctx->bitwiseOrExpr()[i]).as(); + lhs = builder->CreateLogicalAnd(lhs, rhs, "logical and"); + } + } + return visit(ctx->bitwiseOrExpr()[0]); } antlrcpp::Any GeneratorVisitor::visitBitwiseOrExpr(SpiceParser::BitwiseOrExprContext *ctx) { - return SpiceBaseVisitor::visitBitwiseOrExpr(ctx); + if (ctx->bitwiseAndExpr().size() > 1) { + auto lhs = visit(ctx->bitwiseAndExpr()[0]).as(); + for (int i = 1; i < ctx->bitwiseAndExpr().size(); i++) { + auto rhs = visit(ctx->bitwiseAndExpr()[i]).as(); + lhs = builder->CreateOr(lhs, rhs, "bitwise or"); + } + } + return visit(ctx->bitwiseAndExpr()[0]); } antlrcpp::Any GeneratorVisitor::visitBitwiseAndExpr(SpiceParser::BitwiseAndExprContext *ctx) { - return SpiceBaseVisitor::visitBitwiseAndExpr(ctx); + if (ctx->equalityExpr().size() > 1) { + auto lhs = visit(ctx->equalityExpr()[0]).as(); + for (int i = 1; i < ctx->equalityExpr().size(); i++) { + auto rhs = visit(ctx->equalityExpr()[i]).as(); + lhs = builder->CreateAnd(lhs, rhs, "bitwise and"); + } + } + return visit(ctx->equalityExpr()[0]); } antlrcpp::Any GeneratorVisitor::visitEqualityExpr(SpiceParser::EqualityExprContext *ctx) { - return SpiceBaseVisitor::visitEqualityExpr(ctx); + if (ctx->children.size() > 1) { + auto lhs = visit(ctx->relationalExpr()[0]).as(); + auto rhs = visit(ctx->relationalExpr()[1]).as(); + + // Equality expr is: relationalExpr EQUAL relationalExpr + if (ctx->EQUAL()) return builder->CreateICmpEQ(lhs, rhs, "equal"); + + // Equality expr is: relationalExpr NOT_EQUAL relationalExpr + return builder->CreateICmpNE(lhs, rhs, "not equal"); + } + return visit(ctx->relationalExpr()[0]); } antlrcpp::Any GeneratorVisitor::visitRelationalExpr(SpiceParser::RelationalExprContext *ctx) { - return SpiceBaseVisitor::visitRelationalExpr(ctx); + if (ctx->children.size() > 1) { + auto lhs = visit(ctx->additiveExpr()[0]).as(); + auto rhs = visit(ctx->additiveExpr()[1]).as(); + + // Relational expr is: additiveExpr LESS additiveExpr + if (ctx->LESS()) return builder->CreateICmpSLT(lhs, rhs, "less than"); + + // Relational expr is: additiveExpr GREATER additiveExpr + if (ctx->GREATER()) return builder->CreateICmpSGT(lhs, rhs, "greater than"); + + // Relational expr is: additiveExpr LESS_EQUAL additiveExpr + if (ctx->LESS_EQUAL()) return builder->CreateICmpSLE(lhs, rhs, "less equal"); + + // Relational expr is: additiveExpr GREATER_EQUAL additiveExpr + return builder->CreateICmpSGE(lhs, rhs, "greater equal"); + } + return visit(ctx->additiveExpr()[0]); } antlrcpp::Any GeneratorVisitor::visitAdditiveExpr(SpiceParser::AdditiveExprContext *ctx) { From 99811bdd8a567de1e2cb3461c41482b8e7bca12e Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Sat, 10 Jul 2021 01:18:19 +0200 Subject: [PATCH 08/19] Add generator methods for for and while loops --- compiler/src/ir/GeneratorVisitor.cpp | 68 ++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/compiler/src/ir/GeneratorVisitor.cpp b/compiler/src/ir/GeneratorVisitor.cpp index 2c3d65a97..9ec4b2508 100644 --- a/compiler/src/ir/GeneratorVisitor.cpp +++ b/compiler/src/ir/GeneratorVisitor.cpp @@ -92,11 +92,73 @@ antlrcpp::Any GeneratorVisitor::visitProcedureDef(SpiceParser::ProcedureDefConte } antlrcpp::Any GeneratorVisitor::visitForLoop(SpiceParser::ForLoopContext *ctx) { - return SpiceBaseVisitor::visitForLoop(ctx); + auto parentFct = builder->GetInsertBlock()->getParent(); + + // Create blocks + auto bLoop = llvm::BasicBlock::Create(*context, "loop"); + auto bLoopPre = llvm::BasicBlock::Create(*context, "loop pre"); + auto bLoopPost = llvm::BasicBlock::Create(*context, "loop post"); + auto bLoopEnd = llvm::BasicBlock::Create(*context, "loop end"); + + // Fill loop pre block + parentFct->getBasicBlockList().push_back(bLoopPre); + builder->SetInsertPoint(bLoopPre); + visit(ctx->assignment()[0]); + // Check if entering the loop is necessary + auto conditionValue = visit(ctx->assignment()[1]).as(); + builder->CreateCondBr(conditionValue, bLoop, bLoopEnd); + + // Fill loop block + parentFct->getBasicBlockList().push_back(bLoop); + builder->SetInsertPoint(bLoop); + // Generate IR for nested statements + for (auto &stmt : ctx->stmtLst()->stmt())visit(stmt); + // Check if condition is now false + conditionValue = visit(ctx->assignment()[1]).as(); + builder->CreateCondBr(conditionValue, bLoopPost, bLoopEnd); + + // Fill loop post block + parentFct->getBasicBlockList().push_back(bLoopPost); + builder->SetInsertPoint(bLoopPost); + visit(ctx->assignment()[2]); + builder->CreateBr(bLoop); + + // Fil loop end block + parentFct->getBasicBlockList().push_back(bLoopEnd); + builder->SetInsertPoint(bLoopEnd); + + // Return true as result for the loop + return llvm::ConstantInt::get((llvm::Type::getInt1Ty(*context)), 1); } antlrcpp::Any GeneratorVisitor::visitWhileLoop(SpiceParser::WhileLoopContext *ctx) { - return SpiceBaseVisitor::visitWhileLoop(ctx); + auto conditionValue = visit(ctx->assignment()).as(); + auto parentFct = builder->GetInsertBlock()->getParent(); + + // Create blocks + auto bLoop = llvm::BasicBlock::Create(*context, "loop"); + auto bLoopEnd = llvm::BasicBlock::Create(*context, "loop end"); + + // Check if entering the loop is necessary + builder->CreateCondBr(conditionValue, bLoop, bLoopEnd); + + // Fill loop block + parentFct->getBasicBlockList().push_back(bLoop); + builder->SetInsertPoint(bLoop); + // Generate IR for nested statements + for (auto &stmt : ctx->stmtLst()->stmt())visit(stmt); + // Visit condition again + conditionValue = visit(ctx->assignment()).as(); + // Check if condition is now false + bLoop = builder->GetInsertBlock(); + builder->CreateCondBr(conditionValue, bLoop, bLoopEnd); + + // Fill loop end block + parentFct->getBasicBlockList().push_back(bLoopEnd); + builder->SetInsertPoint(bLoopEnd); + + // Return true as result for the loop + return llvm::ConstantInt::get((llvm::Type::getInt1Ty(*context)), 1); } antlrcpp::Any GeneratorVisitor::visitIfStmt(SpiceParser::IfStmtContext *ctx) { @@ -287,7 +349,7 @@ antlrcpp::Any GeneratorVisitor::visitValue(SpiceParser::ValueContext *ctx) { // Value is a boolean constant if (ctx->TRUE() || ctx->FALSE()) - return llvm::ConstantInt::getSigned((llvm::Type::getInt1Ty(*context)), ctx->TRUE() ? 1 : 0); + return llvm::ConstantInt::get((llvm::Type::getInt1Ty(*context)), ctx->TRUE() ? 1 : 0); // Value is an identifier if (ctx->IDENTIFIER()) { From 9d75a50ba6d1612cbdf36d3967a9a9d3b8554ee1 Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Sun, 11 Jul 2021 21:36:41 +0200 Subject: [PATCH 09/19] Add printf statement to grammar --- README.md | 1 + compiler/.run/Spice_run.run.xml | 2 +- compiler/src/analyzer/AnalyzerVisitor.cpp | 27 +++++ compiler/src/analyzer/AnalyzerVisitor.h | 2 + compiler/src/grammar/Spice.g4 | 8 +- compiler/src/ir/GeneratorVisitor.cpp | 141 +++++++++++++++++++++- compiler/src/ir/GeneratorVisitor.h | 2 + media/fibonacci.spice | 3 +- media/test.spice | 6 + 9 files changed, 182 insertions(+), 10 deletions(-) create mode 100644 media/test.spice diff --git a/README.md b/README.md index d731017c2..0a0dc6f80 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ The Spice grammar can be found [here](./compiler/src/grammar/Spice.g4) as a ANTL - [x] Additive operators are only applied to some type combinations - [x] Multiplicative operators are only applied to some type combinations - [x] Prefix/postfix unary operators are only applied to integers +- [ ] Program contains main function ## Special language features - Something like `"Test" * 3` is valid and will evaluate to `"TestTestTest"` diff --git a/compiler/.run/Spice_run.run.xml b/compiler/.run/Spice_run.run.xml index 7be03020f..9f13f8e79 100644 --- a/compiler/.run/Spice_run.run.xml +++ b/compiler/.run/Spice_run.run.xml @@ -1,5 +1,5 @@ - + diff --git a/compiler/src/analyzer/AnalyzerVisitor.cpp b/compiler/src/analyzer/AnalyzerVisitor.cpp index c3485a5a1..4bd3c0e48 100644 --- a/compiler/src/analyzer/AnalyzerVisitor.cpp +++ b/compiler/src/analyzer/AnalyzerVisitor.cpp @@ -15,6 +15,29 @@ antlrcpp::Any AnalyzerVisitor::visitEntry(SpiceParser::EntryContext *ctx) { return currentScope; } +antlrcpp::Any AnalyzerVisitor::visitMainFunctionDef(SpiceParser::MainFunctionDefContext *ctx) { + // Insert function name into the root symbol table + currentScope->insert("main", TYPE_FUNCTION, INITIALIZED, true, false); + // Create a new scope + std::string scopeId = "f:main"; + currentScope = currentScope->createChildBlock(scopeId); + // Declare variable for the return value + SymbolType returnType = TYPE_INT; + currentScope->insert(RETURN_VARIABLE_NAME, returnType, DECLARED, false, false); + // Visit parameters + parameterMode = true; + if (ctx->paramLstDef()) visit(ctx->paramLstDef()); + parameterMode = false; + // Visit statements in new scope + visit(ctx->stmtLst()); + // Check if return variable is now initialized + if (currentScope->lookup(RETURN_VARIABLE_NAME)->getState() == DECLARED) + throw SemanticError(FUNCTION_WITHOUT_RETURN_STMT, "Function without return statement"); + // Return to old scope + currentScope = currentScope->getParent(); + return returnType; +} + antlrcpp::Any AnalyzerVisitor::visitFunctionDef(SpiceParser::FunctionDefContext *ctx) { // Insert function name into the root symbol table std::string functionName = ctx->IDENTIFIER()->toString(); @@ -180,6 +203,10 @@ antlrcpp::Any AnalyzerVisitor::visitReturnStmt(SpiceParser::ReturnStmtContext *c return returnType; } +antlrcpp::Any AnalyzerVisitor::visitPrintfStmt(SpiceParser::PrintfStmtContext *ctx) { + return SpiceBaseVisitor::visitPrintfStmt(ctx); +} + antlrcpp::Any AnalyzerVisitor::visitAssignment(SpiceParser::AssignmentContext *ctx) { // Check if there is an assign operator applied if (ctx->children.size() > 1) { diff --git a/compiler/src/analyzer/AnalyzerVisitor.h b/compiler/src/analyzer/AnalyzerVisitor.h index 1e39146ec..446a9843d 100644 --- a/compiler/src/analyzer/AnalyzerVisitor.h +++ b/compiler/src/analyzer/AnalyzerVisitor.h @@ -13,6 +13,7 @@ class AnalyzerVisitor : public SpiceBaseVisitor { public: // Public methods antlrcpp::Any visitEntry(SpiceParser::EntryContext *ctx) override; + antlrcpp::Any visitMainFunctionDef(SpiceParser::MainFunctionDefContext *ctx) override; antlrcpp::Any visitFunctionDef(SpiceParser::FunctionDefContext *ctx) override; antlrcpp::Any visitProcedureDef(SpiceParser::ProcedureDefContext *ctx) override; antlrcpp::Any visitForLoop(SpiceParser::ForLoopContext *ctx) override; @@ -23,6 +24,7 @@ class AnalyzerVisitor : public SpiceBaseVisitor { antlrcpp::Any visitFunctionCall(SpiceParser::FunctionCallContext *ctx) override; antlrcpp::Any visitImportStmt(SpiceParser::ImportStmtContext *ctx) override; antlrcpp::Any visitReturnStmt(SpiceParser::ReturnStmtContext *ctx) override; + antlrcpp::Any visitPrintfStmt(SpiceParser::PrintfStmtContext *ctx) override; antlrcpp::Any visitAssignment(SpiceParser::AssignmentContext *ctx) override; antlrcpp::Any visitTernary(SpiceParser::TernaryContext *ctx) override; antlrcpp::Any visitLogicalOrExpr(SpiceParser::LogicalOrExprContext *ctx) override; diff --git a/compiler/src/grammar/Spice.g4 b/compiler/src/grammar/Spice.g4 index 5c1000bb0..67aaa4147 100644 --- a/compiler/src/grammar/Spice.g4 +++ b/compiler/src/grammar/Spice.g4 @@ -1,6 +1,7 @@ grammar Spice; -entry: (stmt | functionDef | procedureDef)*; +entry: (stmt | mainFunctionDef | functionDef | procedureDef)*; +mainFunctionDef: F LESS TYPE_INT GREATER MAIN LPAREN paramLstDef? RPAREN LBRACE stmtLst RBRACE; functionDef: F LESS dataType GREATER IDENTIFIER LPAREN paramLstDef? RPAREN LBRACE stmtLst RBRACE; procedureDef: P IDENTIFIER LPAREN paramLstDef? RPAREN LBRACE stmtLst RBRACE; forLoop: FOR assignment SEMICOLON assignment SEMICOLON assignment LBRACE stmtLst RBRACE; @@ -11,11 +12,12 @@ ifStmt: IF assignment LBRACE stmtLst RBRACE; stmtLst: (stmt | forLoop | /*foreachLoop |*/ whileLoop | ifStmt)*; paramLstDef: (declStmt | assignment) (COMMA (declStmt | assignment))*; paramLstCall: assignment (COMMA assignment)*; -stmt: (declStmt | assignment | functionCall | assignment | importStmt | returnStmt) SEMICOLON; +stmt: (declStmt | assignment | functionCall | assignment | importStmt | returnStmt | printfStmt) SEMICOLON; declStmt: CONST? dataType IDENTIFIER; functionCall: IDENTIFIER LPAREN paramLstCall? RPAREN; importStmt: IMPORT STRING; returnStmt: RETURN assignment; +printfStmt: PRINTF LPAREN STRING (COMMA assignment)* RPAREN; assignment: ((declStmt | IDENTIFIER) (ASSIGN_OP | PLUS_EQUAL | MINUS_EQUAL | MUL_EQUAL | DIV_EQUAL))? ternary; ternary: logicalOrExpr (QUESTION_MARK logicalOrExpr ':' logicalOrExpr)?; @@ -47,6 +49,8 @@ WHILE: 'while'; CONST: 'const'; IMPORT: 'import'; RETURN: 'return'; +MAIN: 'main'; +PRINTF: 'printf'; TRUE: 'true'; FALSE: 'false'; STRING: '"' (~["\\\r\n] | '\\' (. | EOF))* '"'; diff --git a/compiler/src/ir/GeneratorVisitor.cpp b/compiler/src/ir/GeneratorVisitor.cpp index 9ec4b2508..73045d94a 100644 --- a/compiler/src/ir/GeneratorVisitor.cpp +++ b/compiler/src/ir/GeneratorVisitor.cpp @@ -80,14 +80,102 @@ void GeneratorVisitor::dumpIR() { } antlrcpp::Any GeneratorVisitor::visitEntry(SpiceParser::EntryContext *ctx) { - return getIRString(); + return SpiceBaseVisitor::visitEntry(ctx); +} + +antlrcpp::Any GeneratorVisitor::visitMainFunctionDef(SpiceParser::MainFunctionDefContext *ctx) { + // Build function itself + auto mainType = llvm::FunctionType::get(llvm::IntegerType::getInt32Ty(*context), + std::vector(), false); + auto main = llvm::Function::Create(mainType, llvm::Function::ExternalLinkage, "main", module.get()); + auto mainBasicBlock = llvm::BasicBlock::Create(*context, "entry", main); + builder->SetInsertPoint(mainBasicBlock); + namedValues.clear(); + + // Generate IR for function body + //for (auto &stmt : ctx->stmtLst()->stmt()) visit(stmt); + + // Build return value + llvm::APInt retVal(32, 0, true); + builder->CreateRet(llvm::ConstantInt::get(*context, retVal)); + llvm::verifyFunction(*main); + + // Return true as result for the function definition + return llvm::ConstantInt::get(llvm::Type::getInt1Ty(*context), 1); + //return SpiceBaseVisitor::visitMainFunctionDef(ctx); } antlrcpp::Any GeneratorVisitor::visitFunctionDef(SpiceParser::FunctionDefContext *ctx) { + /*std::string functionName = ctx->IDENTIFIER()->toString(); + // Create function itself + auto function = module->getFunction(llvm::StringRef(functionName)); + + // Create entry block + auto bEntry = llvm::BasicBlock::Create(*context, "entry"); + function->getBasicBlockList().push_back(bEntry); + builder->SetInsertPoint(bEntry); + + // Store function params + namedValues.clear(); + for (auto& param : function->args()) { + auto paramNo = param.getArgNo(); + std::string paramName = ctx->paramLstDef()->assignment()[paramNo]->IDENTIFIER()->toString(); + llvm::Type *paramType = function->getFunctionType()->getParamType(paramNo); + namedValues[paramName] = builder->CreateAlloca(paramType, nullptr, paramName); + builder->CreateStore(¶m, namedValues[paramName]); + } + + // Generate IR for function body + llvm::Value* returnValue; + for (auto &stmt : ctx->stmtLst()->stmt()) { + if (stmt->returnStmt()) { + returnValue = visit(stmt).as(); + } else { + visit(stmt); + } + } + + // Create return value + builder->CreateRet(returnValue); + + // Verify function + llvm::verifyFunction(*function); + + // Return true as result for the function definition + return llvm::ConstantInt::get((llvm::Type::getInt1Ty(*context)), 1);*/ return SpiceBaseVisitor::visitFunctionDef(ctx); } antlrcpp::Any GeneratorVisitor::visitProcedureDef(SpiceParser::ProcedureDefContext *ctx) { + /*// Create procedure itself + auto procedure = module->getFunction(llvm::StringRef(ctx->IDENTIFIER()->toString())); + + // Create entry block + auto bEntry = llvm::BasicBlock::Create(*context, "entry"); + procedure->getBasicBlockList().push_back(bEntry); + builder->SetInsertPoint(bEntry); + + // Store procedure params + namedValues.clear(); + for (auto& param : procedure->args()) { + auto paramNo = param.getArgNo(); + std::string paramName = ctx->paramLstDef()->assignment()[paramNo]->IDENTIFIER()->toString(); + llvm::Type *paramType = procedure->getFunctionType()->getParamType(paramNo); + namedValues[paramName] = builder->CreateAlloca(paramType, nullptr, paramName); + builder->CreateStore(¶m, namedValues[paramName]); + } + + // Generate IR for procedure body + for (auto &stmt : ctx->stmtLst()->stmt()) visit(stmt); + + // Create return + builder->CreateRetVoid(); + + // Verify procedure + llvm::verifyFunction(*procedure); + + // Return true as result for the function definition + return llvm::ConstantInt::get((llvm::Type::getInt1Ty(*context)), 1);*/ return SpiceBaseVisitor::visitProcedureDef(ctx); } @@ -112,7 +200,7 @@ antlrcpp::Any GeneratorVisitor::visitForLoop(SpiceParser::ForLoopContext *ctx) { parentFct->getBasicBlockList().push_back(bLoop); builder->SetInsertPoint(bLoop); // Generate IR for nested statements - for (auto &stmt : ctx->stmtLst()->stmt())visit(stmt); + for (auto &stmt : ctx->stmtLst()->stmt()) visit(stmt); // Check if condition is now false conditionValue = visit(ctx->assignment()[1]).as(); builder->CreateCondBr(conditionValue, bLoopPost, bLoopEnd); @@ -162,7 +250,29 @@ antlrcpp::Any GeneratorVisitor::visitWhileLoop(SpiceParser::WhileLoopContext *ct } antlrcpp::Any GeneratorVisitor::visitIfStmt(SpiceParser::IfStmtContext *ctx) { - return SpiceBaseVisitor::visitIfStmt(ctx); + auto conditionValue = visit(ctx->assignment()).as(); + auto parentFct = builder->GetInsertBlock()->getParent(); + + // Create blocks + auto bThen = llvm::BasicBlock::Create(*context, "then"); + auto bExit = llvm::BasicBlock::Create(*context, "exit"); + + // Check if if condition is fulfilled + builder->CreateCondBr(conditionValue, bThen, bExit); + + // Fill then block + parentFct->getBasicBlockList().push_back(bThen); + builder->SetInsertPoint(bThen); + // Generate IR for nested statements + for (auto &stmt : ctx->stmtLst()->stmt()) visit(stmt); + builder->CreateBr(bExit); + + // Fill exit block + parentFct->getBasicBlockList().push_back(bExit); + builder->SetInsertPoint(bExit); + + // Return conditional value as result for the if stmt + return conditionValue; } antlrcpp::Any GeneratorVisitor::visitDeclStmt(SpiceParser::DeclStmtContext *ctx) { @@ -181,6 +291,17 @@ antlrcpp::Any GeneratorVisitor::visitReturnStmt(SpiceParser::ReturnStmtContext * return SpiceBaseVisitor::visitReturnStmt(ctx); } +antlrcpp::Any GeneratorVisitor::visitPrintfStmt(SpiceParser::PrintfStmtContext *ctx) { + auto printf = module->getFunction("printf"); + std::vector printfArgs; + printfArgs.push_back(builder->CreateGlobalStringPtr(ctx->STRING()->toString())); + for (auto &arg : ctx->assignment()) { + auto argVal = visit(arg).as(); + printfArgs.push_back(argVal); + } + return builder->CreateCall(printf, printfArgs); +} + antlrcpp::Any GeneratorVisitor::visitAssignment(SpiceParser::AssignmentContext *ctx) { return SpiceBaseVisitor::visitAssignment(ctx); } @@ -359,9 +480,17 @@ antlrcpp::Any GeneratorVisitor::visitValue(SpiceParser::ValueContext *ctx) { } // Value is a function call - - - return nullptr; + auto calleeFun = module->getFunction(llvm::StringRef(ctx->functionCall()->IDENTIFIER()->toString())); + auto calleeFunTy = calleeFun->getFunctionType(); + std::vector argValues; + auto params = ctx->functionCall()->paramLstCall()->assignment(); + for (int i = 0; i < params.size(); i++) { + auto argVal = visit(params[i]).as(); + llvm::Type *paramTy = calleeFunTy->getParamType(i); + llvm::Value *bitCastArgVal = builder->CreateBitCast(argVal, paramTy); + argValues.push_back(bitCastArgVal); + } + return builder->CreateCall(calleeFun, argValues); } std::string GeneratorVisitor::getIRString() { diff --git a/compiler/src/ir/GeneratorVisitor.h b/compiler/src/ir/GeneratorVisitor.h index 668dc4c23..569bbb25e 100644 --- a/compiler/src/ir/GeneratorVisitor.h +++ b/compiler/src/ir/GeneratorVisitor.h @@ -37,6 +37,7 @@ class GeneratorVisitor : public SpiceBaseVisitor { void emit(); void dumpIR(); antlrcpp::Any visitEntry(SpiceParser::EntryContext *ctx) override; + antlrcpp::Any visitMainFunctionDef(SpiceParser::MainFunctionDefContext *ctx) override; antlrcpp::Any visitFunctionDef(SpiceParser::FunctionDefContext *ctx) override; antlrcpp::Any visitProcedureDef(SpiceParser::ProcedureDefContext *ctx) override; antlrcpp::Any visitForLoop(SpiceParser::ForLoopContext *ctx) override; @@ -47,6 +48,7 @@ class GeneratorVisitor : public SpiceBaseVisitor { antlrcpp::Any visitFunctionCall(SpiceParser::FunctionCallContext *ctx) override; antlrcpp::Any visitImportStmt(SpiceParser::ImportStmtContext *ctx) override; antlrcpp::Any visitReturnStmt(SpiceParser::ReturnStmtContext *ctx) override; + antlrcpp::Any visitPrintfStmt(SpiceParser::PrintfStmtContext *ctx) override; antlrcpp::Any visitAssignment(SpiceParser::AssignmentContext *ctx) override; antlrcpp::Any visitTernary(SpiceParser::TernaryContext *ctx) override; antlrcpp::Any visitLogicalOrExpr(SpiceParser::LogicalOrExprContext *ctx) override; diff --git a/media/fibonacci.spice b/media/fibonacci.spice index 72ff7456e..2268b7b83 100644 --- a/media/fibonacci.spice +++ b/media/fibonacci.spice @@ -6,6 +6,7 @@ f fibo(int n) { } f main() { - fibo(5); + int result = fibo(5); + printf("%d", result); return 0; } \ No newline at end of file diff --git a/media/test.spice b/media/test.spice new file mode 100644 index 000000000..e61317b19 --- /dev/null +++ b/media/test.spice @@ -0,0 +1,6 @@ +f main() { + if (1 == 1) { + printf("Test: %s", "Value"); + } + return 0; +} \ No newline at end of file From 015031d62fa96698baa7f8b20a67875026f0f780 Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Mon, 12 Jul 2021 21:51:34 +0200 Subject: [PATCH 10/19] First working print stmt --- compiler/src/ir/GeneratorVisitor.cpp | 126 +++++++++++++++++++++++---- compiler/src/ir/GeneratorVisitor.h | 2 + media/test.spice | 8 +- 3 files changed, 117 insertions(+), 19 deletions(-) diff --git a/compiler/src/ir/GeneratorVisitor.cpp b/compiler/src/ir/GeneratorVisitor.cpp index 73045d94a..cbd535dbc 100644 --- a/compiler/src/ir/GeneratorVisitor.cpp +++ b/compiler/src/ir/GeneratorVisitor.cpp @@ -80,6 +80,9 @@ void GeneratorVisitor::dumpIR() { } antlrcpp::Any GeneratorVisitor::visitEntry(SpiceParser::EntryContext *ctx) { + // Generate code for external functions + initializeExternalFunctions(); + return SpiceBaseVisitor::visitEntry(ctx); } @@ -93,7 +96,7 @@ antlrcpp::Any GeneratorVisitor::visitMainFunctionDef(SpiceParser::MainFunctionDe namedValues.clear(); // Generate IR for function body - //for (auto &stmt : ctx->stmtLst()->stmt()) visit(stmt); + for (auto &stmt : ctx->stmtLst()->stmt()) visit(stmt); // Build return value llvm::APInt retVal(32, 0, true); @@ -255,21 +258,21 @@ antlrcpp::Any GeneratorVisitor::visitIfStmt(SpiceParser::IfStmtContext *ctx) { // Create blocks auto bThen = llvm::BasicBlock::Create(*context, "then"); - auto bExit = llvm::BasicBlock::Create(*context, "exit"); + auto bEnd = llvm::BasicBlock::Create(*context, "end"); // Check if if condition is fulfilled - builder->CreateCondBr(conditionValue, bThen, bExit); + builder->CreateCondBr(conditionValue, bThen, bEnd); // Fill then block parentFct->getBasicBlockList().push_back(bThen); builder->SetInsertPoint(bThen); // Generate IR for nested statements for (auto &stmt : ctx->stmtLst()->stmt()) visit(stmt); - builder->CreateBr(bExit); + builder->CreateBr(bEnd); - // Fill exit block - parentFct->getBasicBlockList().push_back(bExit); - builder->SetInsertPoint(bExit); + // Fill end block + parentFct->getBasicBlockList().push_back(bEnd); + builder->SetInsertPoint(bEnd); // Return conditional value as result for the if stmt return conditionValue; @@ -280,7 +283,16 @@ antlrcpp::Any GeneratorVisitor::visitDeclStmt(SpiceParser::DeclStmtContext *ctx) } antlrcpp::Any GeneratorVisitor::visitFunctionCall(SpiceParser::FunctionCallContext *ctx) { - return SpiceBaseVisitor::visitFunctionCall(ctx); + llvm::Function *calleeFun = module->getFunction(llvm::StringRef(ctx->IDENTIFIER()->toString())); + llvm::FunctionType *calleeFunTy = calleeFun->getFunctionType(); + std::vector argValues; + for (int i = 0; i < ctx->paramLstCall()->assignment().size(); i++) { + auto argVal = visit(ctx->paramLstCall()->assignment()[i]).as(); + auto paramTy = calleeFunTy->getParamType(i); + auto bitCastArgVal = builder->CreateBitCast(argVal, paramTy); + argValues.push_back(bitCastArgVal); + } + return builder->CreateCall(calleeFun, argValues); } antlrcpp::Any GeneratorVisitor::visitImportStmt(SpiceParser::ImportStmtContext *ctx) { @@ -297,17 +309,69 @@ antlrcpp::Any GeneratorVisitor::visitPrintfStmt(SpiceParser::PrintfStmtContext * printfArgs.push_back(builder->CreateGlobalStringPtr(ctx->STRING()->toString())); for (auto &arg : ctx->assignment()) { auto argVal = visit(arg).as(); + if (argVal == nullptr) throw std::runtime_error("Printf has null arg"); printfArgs.push_back(argVal); } return builder->CreateCall(printf, printfArgs); } antlrcpp::Any GeneratorVisitor::visitAssignment(SpiceParser::AssignmentContext *ctx) { - return SpiceBaseVisitor::visitAssignment(ctx); + if (ctx->declStmt() || ctx->IDENTIFIER()) { + // Get value of left and right side + auto rhs = visit(ctx->ternary()).as(); + auto lhs = visit(ctx->IDENTIFIER()).as(); + // Store right side on the left one + builder->CreateStore(rhs, lhs); + // Return value of the right side + return rhs; + } + return visit(ctx->ternary()); + //return SpiceBaseVisitor::visitAssignment(ctx); } antlrcpp::Any GeneratorVisitor::visitTernary(SpiceParser::TernaryContext *ctx) { - return SpiceBaseVisitor::visitTernary(ctx); + if (ctx->logicalOrExpr().size() > 1) { + auto conditionValue = visit(ctx->logicalOrExpr()[0]).as(); + auto parentFct = builder->GetInsertBlock()->getParent(); + + // Create blocks + auto bThen = llvm::BasicBlock::Create(*context, "then"); + auto bElse = llvm::BasicBlock::Create(*context, "else"); + auto bEnd = llvm::BasicBlock::Create(*context, "end"); + + // Conditional jump to respective block + builder->CreateCondBr(conditionValue, bThen, bElse); + + // Fill then block + parentFct->getBasicBlockList().push_back(bThen); + builder->SetInsertPoint(bThen); + auto thenValue = visit(ctx->logicalOrExpr()[1]).as(); + builder->CreateBr(bEnd); + + // Fill else block + parentFct->getBasicBlockList().push_back(bElse); + builder->SetInsertPoint(bElse); + auto elseValue = visit(ctx->logicalOrExpr()[2]).as(); + builder->CreateBr(bEnd); + + // Fill end block + parentFct->getBasicBlockList().push_back(bEnd); + builder->SetInsertPoint(bEnd); + // if either is void or their types don't match (which indicates one of them + // returned the null value for void, then don't construct a phi node) + if (thenValue->getType() == llvm::Type::getVoidTy(*context) || + elseValue->getType() == llvm::Type::getVoidTy(*context) || + thenValue->getType() != elseValue->getType()) { + return llvm::Constant::getNullValue(llvm::Type::getInt32Ty(*context)); + } + // Setup phi value + auto phi = builder->CreatePHI(thenValue->getType(), 2, "phi"); + phi->addIncoming(thenValue, bThen); + phi->addIncoming(elseValue, bElse); + return phi; + } + return visit(ctx->logicalOrExpr()[0]); + //return SpiceBaseVisitor::visitTernary(ctx); } antlrcpp::Any GeneratorVisitor::visitLogicalOrExpr(SpiceParser::LogicalOrExprContext *ctx) { @@ -317,6 +381,7 @@ antlrcpp::Any GeneratorVisitor::visitLogicalOrExpr(SpiceParser::LogicalOrExprCon auto rhs = visit(ctx->logicalAndExpr()[i]).as(); lhs = builder->CreateLogicalOr(lhs, rhs, "logical or"); } + return lhs; } return visit(ctx->logicalAndExpr()[0]); } @@ -328,6 +393,7 @@ antlrcpp::Any GeneratorVisitor::visitLogicalAndExpr(SpiceParser::LogicalAndExprC auto rhs = visit(ctx->bitwiseOrExpr()[i]).as(); lhs = builder->CreateLogicalAnd(lhs, rhs, "logical and"); } + return lhs; } return visit(ctx->bitwiseOrExpr()[0]); } @@ -339,6 +405,7 @@ antlrcpp::Any GeneratorVisitor::visitBitwiseOrExpr(SpiceParser::BitwiseOrExprCon auto rhs = visit(ctx->bitwiseAndExpr()[i]).as(); lhs = builder->CreateOr(lhs, rhs, "bitwise or"); } + return lhs; } return visit(ctx->bitwiseAndExpr()[0]); } @@ -350,6 +417,7 @@ antlrcpp::Any GeneratorVisitor::visitBitwiseAndExpr(SpiceParser::BitwiseAndExprC auto rhs = visit(ctx->equalityExpr()[i]).as(); lhs = builder->CreateAnd(lhs, rhs, "bitwise and"); } + return lhs; } return visit(ctx->equalityExpr()[0]); } @@ -398,6 +466,7 @@ antlrcpp::Any GeneratorVisitor::visitAdditiveExpr(SpiceParser::AdditiveExprConte else lhs = builder->CreateSub(lhs, rhs, "sub"); } + return lhs; } return visit(ctx->multiplicativeExpr()[0]); } @@ -418,26 +487,35 @@ antlrcpp::Any GeneratorVisitor::visitMultiplicativeExpr(SpiceParser::Multiplicat } antlrcpp::Any GeneratorVisitor::visitPrefixUnary(SpiceParser::PrefixUnaryContext *ctx) { - auto value = visit(ctx->postfixUnary()).as(); + auto value = visit(ctx->postfixUnary()); // Prefix unary is: PLUS_PLUS postfixUnary - if (ctx->PLUS_PLUS()) return builder->CreateAdd(value, builder->getInt32(1), "++ prefix"); + if (ctx->PLUS_PLUS()) + return builder->CreateAdd(value.as(), builder->getInt32(1), "++ prefix"); // Prefix unary is: MINUS_MINUS postfixUnary - if (ctx->MINUS_MINUS()) return builder->CreateSub(value, builder->getInt32(1), "-- prefix"); + if (ctx->MINUS_MINUS()) + return builder->CreateSub(value.as(), builder->getInt32(1), "-- prefix"); // Prefix unary is: NOT postfixUnary - return builder->CreateNot(value, "not"); + if (ctx->NOT()) + return builder->CreateNot(value.as(), "not"); + + return value; } antlrcpp::Any GeneratorVisitor::visitPostfixUnary(SpiceParser::PostfixUnaryContext *ctx) { - auto value = visit(ctx->atomicExpr()).as(); + auto value = visit(ctx->atomicExpr()); // Postfix unary is: PLUS_PLUS atomicExpr - if (ctx->PLUS_PLUS()) return builder->CreateAdd(value, builder->getInt32(1), "++ postfix"); + if (ctx->PLUS_PLUS()) + return builder->CreateAdd(value.as(), builder->getInt32(1), "++ postfix"); // Postfix unary is: MINUS_MINUS atomicExpr - return builder->CreateSub(value, builder->getInt32(1), "-- postfix"); + if (ctx->MINUS_MINUS()) + return builder->CreateSub(value.as(), builder->getInt32(1), "-- postfix"); + + return value; } antlrcpp::Any GeneratorVisitor::visitAtomicExpr(SpiceParser::AtomicExprContext *ctx) { @@ -493,9 +571,23 @@ antlrcpp::Any GeneratorVisitor::visitValue(SpiceParser::ValueContext *ctx) { return builder->CreateCall(calleeFun, argValues); } +antlrcpp::Any GeneratorVisitor::visitDataType(SpiceParser::DataTypeContext *ctx) { + if (ctx->TYPE_DOUBLE()) return llvm::Type::getDoubleTy(*context); + + if (ctx->TYPE_INT()) return llvm::Type::getInt32Ty(*context); + + if (ctx->TYPE_BOOL()) return llvm::Type::getInt1Ty(*context); +} + std::string GeneratorVisitor::getIRString() { std::string output; llvm::raw_string_ostream oss(output); module->print(oss, nullptr); return oss.str(); } + +void GeneratorVisitor::initializeExternalFunctions() { + module->getOrInsertFunction("printf", llvm::FunctionType::get( + llvm::IntegerType::getInt32Ty(*context), + llvm::Type::getInt8Ty(*context)->getPointerTo(), true)); +} diff --git a/compiler/src/ir/GeneratorVisitor.h b/compiler/src/ir/GeneratorVisitor.h index 569bbb25e..0eba46cb0 100644 --- a/compiler/src/ir/GeneratorVisitor.h +++ b/compiler/src/ir/GeneratorVisitor.h @@ -63,6 +63,7 @@ class GeneratorVisitor : public SpiceBaseVisitor { antlrcpp::Any visitPostfixUnary(SpiceParser::PostfixUnaryContext *ctx) override; antlrcpp::Any visitAtomicExpr(SpiceParser::AtomicExprContext *ctx) override; antlrcpp::Any visitValue(SpiceParser::ValueContext *ctx) override; + antlrcpp::Any visitDataType(SpiceParser::DataTypeContext *ctx) override; private: // Members std::unique_ptr context = std::make_unique(); @@ -72,4 +73,5 @@ class GeneratorVisitor : public SpiceBaseVisitor { // Private methods std::string getIRString(); + void initializeExternalFunctions(); }; \ No newline at end of file diff --git a/media/test.spice b/media/test.spice index e61317b19..b922d02d0 100644 --- a/media/test.spice +++ b/media/test.spice @@ -1,6 +1,10 @@ f main() { - if (1 == 1) { - printf("Test: %s", "Value"); + /*if (true) { + return 1; } + while (true) { + return 2; + }*/ + printf("Test"); return 0; } \ No newline at end of file From 2d955faafc2016afc614655275fa7bd3340308bb Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Tue, 13 Jul 2021 14:21:24 +0200 Subject: [PATCH 11/19] If, while, return stmt working --- compiler/src/ir/GeneratorVisitor.cpp | 91 +++++++++++++--------------- media/test.spice | 18 ++++-- 2 files changed, 55 insertions(+), 54 deletions(-) diff --git a/compiler/src/ir/GeneratorVisitor.cpp b/compiler/src/ir/GeneratorVisitor.cpp index cbd535dbc..d4992fcbe 100644 --- a/compiler/src/ir/GeneratorVisitor.cpp +++ b/compiler/src/ir/GeneratorVisitor.cpp @@ -96,16 +96,13 @@ antlrcpp::Any GeneratorVisitor::visitMainFunctionDef(SpiceParser::MainFunctionDe namedValues.clear(); // Generate IR for function body - for (auto &stmt : ctx->stmtLst()->stmt()) visit(stmt); + visit(ctx->stmtLst()); - // Build return value - llvm::APInt retVal(32, 0, true); - builder->CreateRet(llvm::ConstantInt::get(*context, retVal)); + // Verify function llvm::verifyFunction(*main); // Return true as result for the function definition return llvm::ConstantInt::get(llvm::Type::getInt1Ty(*context), 1); - //return SpiceBaseVisitor::visitMainFunctionDef(ctx); } antlrcpp::Any GeneratorVisitor::visitFunctionDef(SpiceParser::FunctionDefContext *ctx) { @@ -129,17 +126,7 @@ antlrcpp::Any GeneratorVisitor::visitFunctionDef(SpiceParser::FunctionDefContext } // Generate IR for function body - llvm::Value* returnValue; - for (auto &stmt : ctx->stmtLst()->stmt()) { - if (stmt->returnStmt()) { - returnValue = visit(stmt).as(); - } else { - visit(stmt); - } - } - - // Create return value - builder->CreateRet(returnValue); + visit(ctx->stmtLst()); // Verify function llvm::verifyFunction(*function); @@ -169,7 +156,7 @@ antlrcpp::Any GeneratorVisitor::visitProcedureDef(SpiceParser::ProcedureDefConte } // Generate IR for procedure body - for (auto &stmt : ctx->stmtLst()->stmt()) visit(stmt); + visit(ctx->stmtLst()); // Create return builder->CreateRetVoid(); @@ -187,9 +174,9 @@ antlrcpp::Any GeneratorVisitor::visitForLoop(SpiceParser::ForLoopContext *ctx) { // Create blocks auto bLoop = llvm::BasicBlock::Create(*context, "loop"); - auto bLoopPre = llvm::BasicBlock::Create(*context, "loop pre"); - auto bLoopPost = llvm::BasicBlock::Create(*context, "loop post"); - auto bLoopEnd = llvm::BasicBlock::Create(*context, "loop end"); + auto bLoopPre = llvm::BasicBlock::Create(*context, "loop_pre"); + auto bLoopPost = llvm::BasicBlock::Create(*context, "loop_post"); + auto bLoopEnd = llvm::BasicBlock::Create(*context, "loop_end"); // Fill loop pre block parentFct->getBasicBlockList().push_back(bLoopPre); @@ -203,7 +190,7 @@ antlrcpp::Any GeneratorVisitor::visitForLoop(SpiceParser::ForLoopContext *ctx) { parentFct->getBasicBlockList().push_back(bLoop); builder->SetInsertPoint(bLoop); // Generate IR for nested statements - for (auto &stmt : ctx->stmtLst()->stmt()) visit(stmt); + visit(ctx->stmtLst()); // Check if condition is now false conditionValue = visit(ctx->assignment()[1]).as(); builder->CreateCondBr(conditionValue, bLoopPost, bLoopEnd); @@ -219,7 +206,7 @@ antlrcpp::Any GeneratorVisitor::visitForLoop(SpiceParser::ForLoopContext *ctx) { builder->SetInsertPoint(bLoopEnd); // Return true as result for the loop - return llvm::ConstantInt::get((llvm::Type::getInt1Ty(*context)), 1); + return llvm::ConstantInt::get(llvm::Type::getInt1Ty(*context), 1); } antlrcpp::Any GeneratorVisitor::visitWhileLoop(SpiceParser::WhileLoopContext *ctx) { @@ -228,7 +215,7 @@ antlrcpp::Any GeneratorVisitor::visitWhileLoop(SpiceParser::WhileLoopContext *ct // Create blocks auto bLoop = llvm::BasicBlock::Create(*context, "loop"); - auto bLoopEnd = llvm::BasicBlock::Create(*context, "loop end"); + auto bLoopEnd = llvm::BasicBlock::Create(*context, "loop_end"); // Check if entering the loop is necessary builder->CreateCondBr(conditionValue, bLoop, bLoopEnd); @@ -237,7 +224,7 @@ antlrcpp::Any GeneratorVisitor::visitWhileLoop(SpiceParser::WhileLoopContext *ct parentFct->getBasicBlockList().push_back(bLoop); builder->SetInsertPoint(bLoop); // Generate IR for nested statements - for (auto &stmt : ctx->stmtLst()->stmt())visit(stmt); + visit(ctx->stmtLst()); // Visit condition again conditionValue = visit(ctx->assignment()).as(); // Check if condition is now false @@ -249,7 +236,7 @@ antlrcpp::Any GeneratorVisitor::visitWhileLoop(SpiceParser::WhileLoopContext *ct builder->SetInsertPoint(bLoopEnd); // Return true as result for the loop - return llvm::ConstantInt::get((llvm::Type::getInt1Ty(*context)), 1); + return llvm::ConstantInt::get(llvm::Type::getInt1Ty(*context), 1); } antlrcpp::Any GeneratorVisitor::visitIfStmt(SpiceParser::IfStmtContext *ctx) { @@ -267,7 +254,7 @@ antlrcpp::Any GeneratorVisitor::visitIfStmt(SpiceParser::IfStmtContext *ctx) { parentFct->getBasicBlockList().push_back(bThen); builder->SetInsertPoint(bThen); // Generate IR for nested statements - for (auto &stmt : ctx->stmtLst()->stmt()) visit(stmt); + visit(ctx->stmtLst()); builder->CreateBr(bEnd); // Fill end block @@ -283,14 +270,14 @@ antlrcpp::Any GeneratorVisitor::visitDeclStmt(SpiceParser::DeclStmtContext *ctx) } antlrcpp::Any GeneratorVisitor::visitFunctionCall(SpiceParser::FunctionCallContext *ctx) { - llvm::Function *calleeFun = module->getFunction(llvm::StringRef(ctx->IDENTIFIER()->toString())); - llvm::FunctionType *calleeFunTy = calleeFun->getFunctionType(); - std::vector argValues; + llvm::Function* calleeFun = module->getFunction(llvm::StringRef(ctx->IDENTIFIER()->toString())); + llvm::FunctionType* calleeFunTy = calleeFun->getFunctionType(); + std::vector argValues; for (int i = 0; i < ctx->paramLstCall()->assignment().size(); i++) { - auto argVal = visit(ctx->paramLstCall()->assignment()[i]).as(); + auto argValue = visit(ctx->paramLstCall()->assignment()[i]).as(); auto paramTy = calleeFunTy->getParamType(i); - auto bitCastArgVal = builder->CreateBitCast(argVal, paramTy); - argValues.push_back(bitCastArgVal); + auto bitCastArgValue = builder->CreateBitCast(argValue, paramTy); + argValues.push_back(bitCastArgValue); } return builder->CreateCall(calleeFun, argValues); } @@ -300,13 +287,18 @@ antlrcpp::Any GeneratorVisitor::visitImportStmt(SpiceParser::ImportStmtContext * } antlrcpp::Any GeneratorVisitor::visitReturnStmt(SpiceParser::ReturnStmtContext *ctx) { - return SpiceBaseVisitor::visitReturnStmt(ctx); + auto returnValue = visit(ctx->assignment()).as(); + // Build return value + builder->CreateRet(returnValue); + return returnValue; } antlrcpp::Any GeneratorVisitor::visitPrintfStmt(SpiceParser::PrintfStmtContext *ctx) { auto printf = module->getFunction("printf"); std::vector printfArgs; - printfArgs.push_back(builder->CreateGlobalStringPtr(ctx->STRING()->toString())); + auto stringTemplate = ctx->STRING()->toString(); + stringTemplate = stringTemplate.erase(stringTemplate.size() -1).erase(0, 1); + printfArgs.push_back(builder->CreateGlobalStringPtr(stringTemplate)); for (auto &arg : ctx->assignment()) { auto argVal = visit(arg).as(); if (argVal == nullptr) throw std::runtime_error("Printf has null arg"); @@ -326,7 +318,6 @@ antlrcpp::Any GeneratorVisitor::visitAssignment(SpiceParser::AssignmentContext * return rhs; } return visit(ctx->ternary()); - //return SpiceBaseVisitor::visitAssignment(ctx); } antlrcpp::Any GeneratorVisitor::visitTernary(SpiceParser::TernaryContext *ctx) { @@ -520,7 +511,7 @@ antlrcpp::Any GeneratorVisitor::visitPostfixUnary(SpiceParser::PostfixUnaryConte antlrcpp::Any GeneratorVisitor::visitAtomicExpr(SpiceParser::AtomicExprContext *ctx) { // Atomic expr is: LPAREN value RPAREN - if (ctx->LPAREN()) return visit(ctx->assignment()); + if (ctx->LPAREN()) return visit(ctx->assignment()).as(); // Atomic expr is: value return visit(ctx->value()); @@ -528,27 +519,29 @@ antlrcpp::Any GeneratorVisitor::visitAtomicExpr(SpiceParser::AtomicExprContext * antlrcpp::Any GeneratorVisitor::visitValue(SpiceParser::ValueContext *ctx) { // Value is a double constant - if (ctx->DOUBLE()) - return llvm::ConstantFP::get(*context, llvm::APFloat(std::stod(ctx->DOUBLE()->toString()))); + if (ctx->DOUBLE()) { + auto value = std::stod(ctx->DOUBLE()->toString()); + return (llvm::Value*) llvm::ConstantFP::get(*context, llvm::APFloat(value)); + } // Value is an integer constant - if (ctx->INTEGER()) - return llvm::ConstantInt::getSigned(llvm::Type::getInt32Ty(*context), - std::stoi(ctx->INTEGER()->toString())); + if (ctx->INTEGER()) { + auto value = std::stoi(ctx->INTEGER()->toString()); + return (llvm::Value*) llvm::ConstantInt::getSigned(llvm::Type::getInt32Ty(*context), value); + } // Value is a string constant if (ctx->STRING()) { std::string value = ctx->STRING()->toString(); auto charType = llvm::IntegerType::get(*context, 8); - std::vector chars(value.size()); - for(unsigned int i = 0; i < value.size(); i++) - chars[i] = llvm::ConstantInt::get(charType, value[i]); - return llvm::ConstantArray::get(llvm::ArrayType::get(charType, chars.size()), chars); + std::vector chars(value.size()); + for(unsigned int i = 0; i < value.size(); i++) chars[i] = llvm::ConstantInt::get(charType, value[i]); + return (llvm::Value*) llvm::ConstantArray::get(llvm::ArrayType::get(charType, chars.size()), chars); } // Value is a boolean constant if (ctx->TRUE() || ctx->FALSE()) - return llvm::ConstantInt::get((llvm::Type::getInt1Ty(*context)), ctx->TRUE() ? 1 : 0); + return (llvm::Value*) llvm::ConstantInt::getSigned(llvm::Type::getInt1Ty(*context), ctx->TRUE() ? 1 : 0); // Value is an identifier if (ctx->IDENTIFIER()) { @@ -564,11 +557,11 @@ antlrcpp::Any GeneratorVisitor::visitValue(SpiceParser::ValueContext *ctx) { auto params = ctx->functionCall()->paramLstCall()->assignment(); for (int i = 0; i < params.size(); i++) { auto argVal = visit(params[i]).as(); - llvm::Type *paramTy = calleeFunTy->getParamType(i); - llvm::Value *bitCastArgVal = builder->CreateBitCast(argVal, paramTy); + llvm::Type* paramTy = calleeFunTy->getParamType(i); + llvm::Value* bitCastArgVal = builder->CreateBitCast(argVal, paramTy); argValues.push_back(bitCastArgVal); } - return builder->CreateCall(calleeFun, argValues); + return (llvm::Value*) builder->CreateCall(calleeFun, argValues); } antlrcpp::Any GeneratorVisitor::visitDataType(SpiceParser::DataTypeContext *ctx) { diff --git a/media/test.spice b/media/test.spice index b922d02d0..135ffd08e 100644 --- a/media/test.spice +++ b/media/test.spice @@ -1,10 +1,18 @@ f main() { - /*if (true) { - return 1; + if false { + printf("If content!"); } - while (true) { - return 2; + while true { + printf("While content!"); + } + /*int i = 0; + while i < 5 { + i++; + }*/ + /*for int i = 0; i < 3; i++ { + printf("For content!"); }*/ - printf("Test"); + printf("Hello World!"); + printf("Dies ist ein Test: %d, %d", 1, 5); return 0; } \ No newline at end of file From 0ee3b94b9edbf769bafeef424482ecb21e0d3a3f Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Tue, 13 Jul 2021 23:03:33 +0200 Subject: [PATCH 12/19] Fix post- and prefix unary operators --- README.md | 1 + compiler/src/ir/GeneratorVisitor.cpp | 103 +++++++++++++++++++-------- compiler/src/ir/GeneratorVisitor.h | 2 +- media/test.spice | 24 +++---- 4 files changed, 85 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 0a0dc6f80..d201b203a 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ The Spice grammar can be found [here](./compiler/src/grammar/Spice.g4) as a ANTL - [x] Multiplicative operators are only applied to some type combinations - [x] Prefix/postfix unary operators are only applied to integers - [ ] Program contains main function +- [ ] `++` and `--` are only applied on identifiers ## Special language features - Something like `"Test" * 3` is valid and will evaluate to `"TestTestTest"` diff --git a/compiler/src/ir/GeneratorVisitor.cpp b/compiler/src/ir/GeneratorVisitor.cpp index d4992fcbe..5a9b14388 100644 --- a/compiler/src/ir/GeneratorVisitor.cpp +++ b/compiler/src/ir/GeneratorVisitor.cpp @@ -91,7 +91,7 @@ antlrcpp::Any GeneratorVisitor::visitMainFunctionDef(SpiceParser::MainFunctionDe auto mainType = llvm::FunctionType::get(llvm::IntegerType::getInt32Ty(*context), std::vector(), false); auto main = llvm::Function::Create(mainType, llvm::Function::ExternalLinkage, "main", module.get()); - auto mainBasicBlock = llvm::BasicBlock::Create(*context, "entry", main); + auto mainBasicBlock = llvm::BasicBlock::Create(*context, "main_entry", main); builder->SetInsertPoint(mainBasicBlock); namedValues.clear(); @@ -173,10 +173,10 @@ antlrcpp::Any GeneratorVisitor::visitForLoop(SpiceParser::ForLoopContext *ctx) { auto parentFct = builder->GetInsertBlock()->getParent(); // Create blocks - auto bLoop = llvm::BasicBlock::Create(*context, "loop"); - auto bLoopPre = llvm::BasicBlock::Create(*context, "loop_pre"); - auto bLoopPost = llvm::BasicBlock::Create(*context, "loop_post"); - auto bLoopEnd = llvm::BasicBlock::Create(*context, "loop_end"); + auto bLoop = llvm::BasicBlock::Create(*context, "for"); + auto bLoopPre = llvm::BasicBlock::Create(*context, "for_pre"); + auto bLoopPost = llvm::BasicBlock::Create(*context, "for_post"); + auto bLoopEnd = llvm::BasicBlock::Create(*context, "for_end"); // Fill loop pre block parentFct->getBasicBlockList().push_back(bLoopPre); @@ -214,8 +214,8 @@ antlrcpp::Any GeneratorVisitor::visitWhileLoop(SpiceParser::WhileLoopContext *ct auto parentFct = builder->GetInsertBlock()->getParent(); // Create blocks - auto bLoop = llvm::BasicBlock::Create(*context, "loop"); - auto bLoopEnd = llvm::BasicBlock::Create(*context, "loop_end"); + auto bLoop = llvm::BasicBlock::Create(*context, "while"); + auto bLoopEnd = llvm::BasicBlock::Create(*context, "while_end"); // Check if entering the loop is necessary builder->CreateCondBr(conditionValue, bLoop, bLoopEnd); @@ -266,7 +266,15 @@ antlrcpp::Any GeneratorVisitor::visitIfStmt(SpiceParser::IfStmtContext *ctx) { } antlrcpp::Any GeneratorVisitor::visitDeclStmt(SpiceParser::DeclStmtContext *ctx) { - return SpiceBaseVisitor::visitDeclStmt(ctx); + std::string varName = ctx->IDENTIFIER()->toString(); + + llvm::Type* varType = visit(ctx->dataType()).as(); + + llvm::Function* parentFunction = builder->GetInsertBlock()->getParent(); + llvm::IRBuilder<> tmpBuilder(&parentFunction->getEntryBlock(), parentFunction->getEntryBlock().begin()); + llvm::AllocaInst* var = tmpBuilder.CreateAlloca(varType, nullptr, varName); + namedValues[varName] = var; + return varName; } antlrcpp::Any GeneratorVisitor::visitFunctionCall(SpiceParser::FunctionCallContext *ctx) { @@ -309,9 +317,12 @@ antlrcpp::Any GeneratorVisitor::visitPrintfStmt(SpiceParser::PrintfStmtContext * antlrcpp::Any GeneratorVisitor::visitAssignment(SpiceParser::AssignmentContext *ctx) { if (ctx->declStmt() || ctx->IDENTIFIER()) { + std::string varName = ctx->declStmt() ? visit(ctx->declStmt()).as() : ctx->IDENTIFIER()->toString(); + // Get value of left and right side auto rhs = visit(ctx->ternary()).as(); - auto lhs = visit(ctx->IDENTIFIER()).as(); + auto lhs = namedValues[varName]; + if (!lhs) throw std::runtime_error("Internal compiler error - Variable not found in code generation step"); // Store right side on the left one builder->CreateStore(rhs, lhs); // Return value of the right side @@ -370,7 +381,7 @@ antlrcpp::Any GeneratorVisitor::visitLogicalOrExpr(SpiceParser::LogicalOrExprCon auto lhs = visit(ctx->logicalAndExpr()[0]).as(); for (int i = 1; i < ctx->logicalAndExpr().size(); i++) { auto rhs = visit(ctx->logicalAndExpr()[i]).as(); - lhs = builder->CreateLogicalOr(lhs, rhs, "logical or"); + lhs = builder->CreateLogicalOr(lhs, rhs, "lg_or"); } return lhs; } @@ -382,7 +393,7 @@ antlrcpp::Any GeneratorVisitor::visitLogicalAndExpr(SpiceParser::LogicalAndExprC auto lhs = visit(ctx->bitwiseOrExpr()[0]).as(); for (int i = 1; i < ctx->bitwiseOrExpr().size(); i++) { auto rhs = visit(ctx->bitwiseOrExpr()[i]).as(); - lhs = builder->CreateLogicalAnd(lhs, rhs, "logical and"); + lhs = builder->CreateLogicalAnd(lhs, rhs, "lg_and"); } return lhs; } @@ -394,7 +405,7 @@ antlrcpp::Any GeneratorVisitor::visitBitwiseOrExpr(SpiceParser::BitwiseOrExprCon auto lhs = visit(ctx->bitwiseAndExpr()[0]).as(); for (int i = 1; i < ctx->bitwiseAndExpr().size(); i++) { auto rhs = visit(ctx->bitwiseAndExpr()[i]).as(); - lhs = builder->CreateOr(lhs, rhs, "bitwise or"); + lhs = builder->CreateOr(lhs, rhs, "bw_or"); } return lhs; } @@ -406,7 +417,7 @@ antlrcpp::Any GeneratorVisitor::visitBitwiseAndExpr(SpiceParser::BitwiseAndExprC auto lhs = visit(ctx->equalityExpr()[0]).as(); for (int i = 1; i < ctx->equalityExpr().size(); i++) { auto rhs = visit(ctx->equalityExpr()[i]).as(); - lhs = builder->CreateAnd(lhs, rhs, "bitwise and"); + lhs = builder->CreateAnd(lhs, rhs, "bw_and"); } return lhs; } @@ -419,10 +430,10 @@ antlrcpp::Any GeneratorVisitor::visitEqualityExpr(SpiceParser::EqualityExprConte auto rhs = visit(ctx->relationalExpr()[1]).as(); // Equality expr is: relationalExpr EQUAL relationalExpr - if (ctx->EQUAL()) return builder->CreateICmpEQ(lhs, rhs, "equal"); + if (ctx->EQUAL()) return builder->CreateICmpEQ(lhs, rhs, "eq"); // Equality expr is: relationalExpr NOT_EQUAL relationalExpr - return builder->CreateICmpNE(lhs, rhs, "not equal"); + return builder->CreateICmpNE(lhs, rhs, "ne"); } return visit(ctx->relationalExpr()[0]); } @@ -433,16 +444,16 @@ antlrcpp::Any GeneratorVisitor::visitRelationalExpr(SpiceParser::RelationalExprC auto rhs = visit(ctx->additiveExpr()[1]).as(); // Relational expr is: additiveExpr LESS additiveExpr - if (ctx->LESS()) return builder->CreateICmpSLT(lhs, rhs, "less than"); + if (ctx->LESS()) return builder->CreateICmpSLT(lhs, rhs, "lt"); // Relational expr is: additiveExpr GREATER additiveExpr - if (ctx->GREATER()) return builder->CreateICmpSGT(lhs, rhs, "greater than"); + if (ctx->GREATER()) return builder->CreateICmpSGT(lhs, rhs, "gt"); // Relational expr is: additiveExpr LESS_EQUAL additiveExpr - if (ctx->LESS_EQUAL()) return builder->CreateICmpSLE(lhs, rhs, "less equal"); + if (ctx->LESS_EQUAL()) return builder->CreateICmpSLE(lhs, rhs, "le"); // Relational expr is: additiveExpr GREATER_EQUAL additiveExpr - return builder->CreateICmpSGE(lhs, rhs, "greater equal"); + return builder->CreateICmpSGE(lhs, rhs, "ge"); } return visit(ctx->additiveExpr()[0]); } @@ -481,12 +492,22 @@ antlrcpp::Any GeneratorVisitor::visitPrefixUnary(SpiceParser::PrefixUnaryContext auto value = visit(ctx->postfixUnary()); // Prefix unary is: PLUS_PLUS postfixUnary - if (ctx->PLUS_PLUS()) - return builder->CreateAdd(value.as(), builder->getInt32(1), "++ prefix"); + if (ctx->PLUS_PLUS()) { + auto llvmValue = value.as(); + auto rhs = builder->CreateAdd(llvmValue, builder->getInt32(1), "pre_pp"); + auto lhs = namedValues[ctx->postfixUnary()->atomicExpr()->value()->IDENTIFIER()->toString()]; + builder->CreateStore(rhs, lhs); + return lhs; + } // Prefix unary is: MINUS_MINUS postfixUnary - if (ctx->MINUS_MINUS()) - return builder->CreateSub(value.as(), builder->getInt32(1), "-- prefix"); + if (ctx->MINUS_MINUS()) { + auto llvmValue = value.as(); + auto rhs = builder->CreateSub(llvmValue, builder->getInt32(1), "pre_mm"); + auto lhs = namedValues[ctx->postfixUnary()->atomicExpr()->value()->IDENTIFIER()->toString()]; + builder->CreateStore(rhs, lhs); + return lhs; + } // Prefix unary is: NOT postfixUnary if (ctx->NOT()) @@ -499,12 +520,22 @@ antlrcpp::Any GeneratorVisitor::visitPostfixUnary(SpiceParser::PostfixUnaryConte auto value = visit(ctx->atomicExpr()); // Postfix unary is: PLUS_PLUS atomicExpr - if (ctx->PLUS_PLUS()) - return builder->CreateAdd(value.as(), builder->getInt32(1), "++ postfix"); + if (ctx->PLUS_PLUS()) { + auto llvmValue = value.as(); + auto rhs = builder->CreateAdd(llvmValue, builder->getInt32(1), "post_pp"); + auto lhs = namedValues[ctx->atomicExpr()->value()->IDENTIFIER()->toString()]; + builder->CreateStore(rhs, lhs); + return rhs; + } // Postfix unary is: MINUS_MINUS atomicExpr - if (ctx->MINUS_MINUS()) - return builder->CreateSub(value.as(), builder->getInt32(1), "-- postfix"); + if (ctx->MINUS_MINUS()) { + auto llvmValue = value.as(); + auto rhs = builder->CreateSub(llvmValue, builder->getInt32(1), "post_mm"); + auto lhs = namedValues[ctx->atomicExpr()->value()->IDENTIFIER()->toString()]; + builder->CreateStore(rhs, lhs); + return rhs; + } return value; } @@ -547,7 +578,7 @@ antlrcpp::Any GeneratorVisitor::visitValue(SpiceParser::ValueContext *ctx) { if (ctx->IDENTIFIER()) { llvm::Value* var = namedValues[ctx->IDENTIFIER()->toString()]; if (!var) throw std::runtime_error("Internal compiler error - Variable not found in code generation step"); - return var; + return (llvm::Value*) builder->CreateLoad(var->getType()->getPointerElementType(), var); } // Value is a function call @@ -565,11 +596,21 @@ antlrcpp::Any GeneratorVisitor::visitValue(SpiceParser::ValueContext *ctx) { } antlrcpp::Any GeneratorVisitor::visitDataType(SpiceParser::DataTypeContext *ctx) { - if (ctx->TYPE_DOUBLE()) return llvm::Type::getDoubleTy(*context); + // Data type is double + if (ctx->TYPE_DOUBLE()) return (llvm::Type*) llvm::Type::getDoubleTy(*context); + + // Data type is int + if (ctx->TYPE_INT()) return (llvm::Type*) llvm::Type::getInt32Ty(*context); + + // Data type is string + if (ctx->TYPE_STRING()) return (llvm::Type*) llvm::Type::getInt8Ty(*context)->getPointerTo(); - if (ctx->TYPE_INT()) return llvm::Type::getInt32Ty(*context); + // Data type is bool + if (ctx->TYPE_BOOL()) return (llvm::Type*) llvm::Type::getInt1Ty(*context); - if (ctx->TYPE_BOOL()) return llvm::Type::getInt1Ty(*context); + // Data type is dyn + // ToDo: Add support for dyn + return (llvm::Type*) nullptr; } std::string GeneratorVisitor::getIRString() { diff --git a/compiler/src/ir/GeneratorVisitor.h b/compiler/src/ir/GeneratorVisitor.h index 0eba46cb0..c625348cb 100644 --- a/compiler/src/ir/GeneratorVisitor.h +++ b/compiler/src/ir/GeneratorVisitor.h @@ -69,7 +69,7 @@ class GeneratorVisitor : public SpiceBaseVisitor { std::unique_ptr context = std::make_unique(); std::unique_ptr> builder = std::make_unique>(*context); std::unique_ptr module = std::make_unique("Module", *context); - std::map namedValues; + std::map namedValues; // Private methods std::string getIRString(); diff --git a/media/test.spice b/media/test.spice index 135ffd08e..5c75eb7ec 100644 --- a/media/test.spice +++ b/media/test.spice @@ -1,18 +1,16 @@ f main() { - if false { - printf("If content!"); - } - while true { - printf("While content!"); - } - /*int i = 0; + int i = 1; + + if !false { printf("If was true"); } + while i < 5 { + printf("While 1 round: %d", i); i++; - }*/ - /*for int i = 0; i < 3; i++ { - printf("For content!"); - }*/ - printf("Hello World!"); - printf("Dies ist ein Test: %d, %d", 1, 5); + } + + while i < 3 { + printf("While 2 round: %d", i); + i++; + } return 0; } \ No newline at end of file From 332fab5da44162a70e352034269649053fd06240 Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Wed, 14 Jul 2021 11:10:11 +0200 Subject: [PATCH 13/19] Fix for loop --- compiler/src/ir/GeneratorVisitor.cpp | 5 +---- media/test.spice | 15 +++------------ 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/compiler/src/ir/GeneratorVisitor.cpp b/compiler/src/ir/GeneratorVisitor.cpp index 5a9b14388..7a768936b 100644 --- a/compiler/src/ir/GeneratorVisitor.cpp +++ b/compiler/src/ir/GeneratorVisitor.cpp @@ -174,13 +174,10 @@ antlrcpp::Any GeneratorVisitor::visitForLoop(SpiceParser::ForLoopContext *ctx) { // Create blocks auto bLoop = llvm::BasicBlock::Create(*context, "for"); - auto bLoopPre = llvm::BasicBlock::Create(*context, "for_pre"); auto bLoopPost = llvm::BasicBlock::Create(*context, "for_post"); auto bLoopEnd = llvm::BasicBlock::Create(*context, "for_end"); - // Fill loop pre block - parentFct->getBasicBlockList().push_back(bLoopPre); - builder->SetInsertPoint(bLoopPre); + // Execute pre-loop stmts visit(ctx->assignment()[0]); // Check if entering the loop is necessary auto conditionValue = visit(ctx->assignment()[1]).as(); diff --git a/media/test.spice b/media/test.spice index 5c75eb7ec..d9717c367 100644 --- a/media/test.spice +++ b/media/test.spice @@ -1,16 +1,7 @@ f main() { - int i = 1; - - if !false { printf("If was true"); } - - while i < 5 { - printf("While 1 round: %d", i); - i++; - } - - while i < 3 { - printf("While 2 round: %d", i); - i++; + int j; + for j = 0; j < 5; j++ { + printf("For round: %d", j); } return 0; } \ No newline at end of file From 45b396f5c31b7d2c2700e5b3a2dd8165890f8c12 Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Wed, 14 Jul 2021 13:11:37 +0200 Subject: [PATCH 14/19] Fix function def & call --- compiler/src/analyzer/AnalyzerVisitor.cpp | 20 +++++---- compiler/src/ir/GeneratorVisitor.cpp | 53 +++++++++++++---------- media/test.spice | 12 +++-- 3 files changed, 49 insertions(+), 36 deletions(-) diff --git a/compiler/src/analyzer/AnalyzerVisitor.cpp b/compiler/src/analyzer/AnalyzerVisitor.cpp index 4bd3c0e48..e73d3d2f2 100644 --- a/compiler/src/analyzer/AnalyzerVisitor.cpp +++ b/compiler/src/analyzer/AnalyzerVisitor.cpp @@ -169,15 +169,17 @@ antlrcpp::Any AnalyzerVisitor::visitFunctionCall(SpiceParser::FunctionCallContex SymbolTable* symbolTable = rootTable->getChild(scopeId); std::vector paramNames = symbolTable->getParamNames(); // Check if types match for parameter list - for (int i = 0; i < ctx->paramLstCall()->assignment().size(); i++) { - SymbolType type = visit(ctx->paramLstCall()->assignment()[i]).as(); - SymbolTableEntry* param = symbolTable->lookup(paramNames[i]); - if (!param) - throw SemanticError(REFERENCED_UNDEFINED_VARIABLE, - "Parameter '" + paramNames[i] + "' was not found in declaration"); - if (type != param->getType()) - throw SemanticError(PARAMETER_TYPES_DO_NOT_MATCH, - "Type of parameter '" + paramNames[i] + "' does not match the declaration"); + if (ctx->paramLstCall()) { + for (int i = 0; i < ctx->paramLstCall()->assignment().size(); i++) { + SymbolType type = visit(ctx->paramLstCall()->assignment()[i]).as(); + SymbolTableEntry* param = symbolTable->lookup(paramNames[i]); + if (!param) + throw SemanticError(REFERENCED_UNDEFINED_VARIABLE, + "Parameter '" + paramNames[i] + "' was not found in declaration"); + if (type != param->getType()) + throw SemanticError(PARAMETER_TYPES_DO_NOT_MATCH, + "Type of parameter '" + paramNames[i] + "' does not match the declaration"); + } } return symbolTable->lookup(RETURN_VARIABLE_NAME)->getType(); } diff --git a/compiler/src/ir/GeneratorVisitor.cpp b/compiler/src/ir/GeneratorVisitor.cpp index 7a768936b..27a96bc85 100644 --- a/compiler/src/ir/GeneratorVisitor.cpp +++ b/compiler/src/ir/GeneratorVisitor.cpp @@ -89,38 +89,41 @@ antlrcpp::Any GeneratorVisitor::visitEntry(SpiceParser::EntryContext *ctx) { antlrcpp::Any GeneratorVisitor::visitMainFunctionDef(SpiceParser::MainFunctionDefContext *ctx) { // Build function itself auto mainType = llvm::FunctionType::get(llvm::IntegerType::getInt32Ty(*context), - std::vector(), false); - auto main = llvm::Function::Create(mainType, llvm::Function::ExternalLinkage, "main", module.get()); - auto mainBasicBlock = llvm::BasicBlock::Create(*context, "main_entry", main); - builder->SetInsertPoint(mainBasicBlock); + std::vector(), false); + auto fct = llvm::Function::Create(mainType, llvm::Function::ExternalLinkage, "main", module.get()); + auto bMain = llvm::BasicBlock::Create(*context, "main_entry", fct); + builder->SetInsertPoint(bMain); namedValues.clear(); // Generate IR for function body visit(ctx->stmtLst()); // Verify function - llvm::verifyFunction(*main); + llvm::verifyFunction(*fct); // Return true as result for the function definition return llvm::ConstantInt::get(llvm::Type::getInt1Ty(*context), 1); } antlrcpp::Any GeneratorVisitor::visitFunctionDef(SpiceParser::FunctionDefContext *ctx) { - /*std::string functionName = ctx->IDENTIFIER()->toString(); + std::string functionName = ctx->IDENTIFIER()->toString(); // Create function itself - auto function = module->getFunction(llvm::StringRef(functionName)); + auto returnType = visit(ctx->dataType()).as(); + auto fctType = llvm::FunctionType::get(returnType, std::vector(), false); + auto fct = llvm::Function::Create(fctType, llvm::Function::ExternalLinkage, functionName, module.get()); + //auto function = module->getFunction(llvm::StringRef(functionName)); // Create entry block auto bEntry = llvm::BasicBlock::Create(*context, "entry"); - function->getBasicBlockList().push_back(bEntry); + fct->getBasicBlockList().push_back(bEntry); builder->SetInsertPoint(bEntry); // Store function params namedValues.clear(); - for (auto& param : function->args()) { + for (auto& param : fct->args()) { auto paramNo = param.getArgNo(); std::string paramName = ctx->paramLstDef()->assignment()[paramNo]->IDENTIFIER()->toString(); - llvm::Type *paramType = function->getFunctionType()->getParamType(paramNo); + llvm::Type *paramType = fct->getFunctionType()->getParamType(paramNo); namedValues[paramName] = builder->CreateAlloca(paramType, nullptr, paramName); builder->CreateStore(¶m, namedValues[paramName]); } @@ -129,11 +132,10 @@ antlrcpp::Any GeneratorVisitor::visitFunctionDef(SpiceParser::FunctionDefContext visit(ctx->stmtLst()); // Verify function - llvm::verifyFunction(*function); + llvm::verifyFunction(*fct); // Return true as result for the function definition - return llvm::ConstantInt::get((llvm::Type::getInt1Ty(*context)), 1);*/ - return SpiceBaseVisitor::visitFunctionDef(ctx); + return llvm::ConstantInt::get((llvm::Type::getInt1Ty(*context)), 1); } antlrcpp::Any GeneratorVisitor::visitProcedureDef(SpiceParser::ProcedureDefContext *ctx) { @@ -275,16 +277,17 @@ antlrcpp::Any GeneratorVisitor::visitDeclStmt(SpiceParser::DeclStmtContext *ctx) } antlrcpp::Any GeneratorVisitor::visitFunctionCall(SpiceParser::FunctionCallContext *ctx) { - llvm::Function* calleeFun = module->getFunction(llvm::StringRef(ctx->IDENTIFIER()->toString())); - llvm::FunctionType* calleeFunTy = calleeFun->getFunctionType(); + auto fctName = ctx->IDENTIFIER()->toString(); + auto fct = module->getFunction(fctName); + auto fctType = fct->getFunctionType(); std::vector argValues; for (int i = 0; i < ctx->paramLstCall()->assignment().size(); i++) { auto argValue = visit(ctx->paramLstCall()->assignment()[i]).as(); - auto paramTy = calleeFunTy->getParamType(i); - auto bitCastArgValue = builder->CreateBitCast(argValue, paramTy); + auto argType = fctType->getParamType(i); + auto bitCastArgValue = builder->CreateBitCast(argValue, argType); argValues.push_back(bitCastArgValue); } - return builder->CreateCall(calleeFun, argValues); + return builder->CreateCall(fct, argValues); } antlrcpp::Any GeneratorVisitor::visitImportStmt(SpiceParser::ImportStmtContext *ctx) { @@ -582,12 +585,14 @@ antlrcpp::Any GeneratorVisitor::visitValue(SpiceParser::ValueContext *ctx) { auto calleeFun = module->getFunction(llvm::StringRef(ctx->functionCall()->IDENTIFIER()->toString())); auto calleeFunTy = calleeFun->getFunctionType(); std::vector argValues; - auto params = ctx->functionCall()->paramLstCall()->assignment(); - for (int i = 0; i < params.size(); i++) { - auto argVal = visit(params[i]).as(); - llvm::Type* paramTy = calleeFunTy->getParamType(i); - llvm::Value* bitCastArgVal = builder->CreateBitCast(argVal, paramTy); - argValues.push_back(bitCastArgVal); + if (ctx->functionCall()->paramLstCall()) { + auto params = ctx->functionCall()->paramLstCall()->assignment(); + for (int i = 0; i < params.size(); i++) { + auto argVal = visit(params[i]).as(); + llvm::Type* paramTy = calleeFunTy->getParamType(i); + llvm::Value* bitCastArgVal = builder->CreateBitCast(argVal, paramTy); + argValues.push_back(bitCastArgVal); + } } return (llvm::Value*) builder->CreateCall(calleeFun, argValues); } diff --git a/media/test.spice b/media/test.spice index d9717c367..4538c4f63 100644 --- a/media/test.spice +++ b/media/test.spice @@ -1,7 +1,13 @@ +f testFunc() { + printf("Hello from testFunc!\n"); + return 1; +} + f main() { - int j; - for j = 0; j < 5; j++ { - printf("For round: %d", j); + for int j = 0; j < 5; j++ { + printf("For round: %d \n", j); } + int testFuncResult = testFunc(); + printf("Result of testFunc: %d \n", testFuncResult); return 0; } \ No newline at end of file From 22ce128d9a1a2486f8bd91c85d248428b8b61b85 Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Wed, 14 Jul 2021 14:37:32 +0200 Subject: [PATCH 15/19] Fix procedure def & ternary op --- compiler/src/ir/GeneratorVisitor.cpp | 32 +++++++++++++++------------- media/fibonacci.spice | 6 ++---- media/test.spice | 6 ++++++ 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/compiler/src/ir/GeneratorVisitor.cpp b/compiler/src/ir/GeneratorVisitor.cpp index 27a96bc85..77c0839c0 100644 --- a/compiler/src/ir/GeneratorVisitor.cpp +++ b/compiler/src/ir/GeneratorVisitor.cpp @@ -111,7 +111,6 @@ antlrcpp::Any GeneratorVisitor::visitFunctionDef(SpiceParser::FunctionDefContext auto returnType = visit(ctx->dataType()).as(); auto fctType = llvm::FunctionType::get(returnType, std::vector(), false); auto fct = llvm::Function::Create(fctType, llvm::Function::ExternalLinkage, functionName, module.get()); - //auto function = module->getFunction(llvm::StringRef(functionName)); // Create entry block auto bEntry = llvm::BasicBlock::Create(*context, "entry"); @@ -139,20 +138,23 @@ antlrcpp::Any GeneratorVisitor::visitFunctionDef(SpiceParser::FunctionDefContext } antlrcpp::Any GeneratorVisitor::visitProcedureDef(SpiceParser::ProcedureDefContext *ctx) { - /*// Create procedure itself - auto procedure = module->getFunction(llvm::StringRef(ctx->IDENTIFIER()->toString())); + auto procedureName = ctx->IDENTIFIER()->toString(); + // Create procedure itself + auto procType = llvm::FunctionType::get(llvm::Type::getVoidTy(*context), + std::vector(), false); + auto proc = llvm::Function::Create(procType, llvm::Function::ExternalLinkage, procedureName, module.get()); // Create entry block auto bEntry = llvm::BasicBlock::Create(*context, "entry"); - procedure->getBasicBlockList().push_back(bEntry); + proc->getBasicBlockList().push_back(bEntry); builder->SetInsertPoint(bEntry); // Store procedure params namedValues.clear(); - for (auto& param : procedure->args()) { + for (auto& param : proc->args()) { auto paramNo = param.getArgNo(); std::string paramName = ctx->paramLstDef()->assignment()[paramNo]->IDENTIFIER()->toString(); - llvm::Type *paramType = procedure->getFunctionType()->getParamType(paramNo); + llvm::Type *paramType = proc->getFunctionType()->getParamType(paramNo); namedValues[paramName] = builder->CreateAlloca(paramType, nullptr, paramName); builder->CreateStore(¶m, namedValues[paramName]); } @@ -164,11 +166,10 @@ antlrcpp::Any GeneratorVisitor::visitProcedureDef(SpiceParser::ProcedureDefConte builder->CreateRetVoid(); // Verify procedure - llvm::verifyFunction(*procedure); + llvm::verifyFunction(*proc); // Return true as result for the function definition - return llvm::ConstantInt::get((llvm::Type::getInt1Ty(*context)), 1);*/ - return SpiceBaseVisitor::visitProcedureDef(ctx); + return llvm::ConstantInt::get(llvm::Type::getInt1Ty(*context), 1); } antlrcpp::Any GeneratorVisitor::visitForLoop(SpiceParser::ForLoopContext *ctx) { @@ -370,10 +371,9 @@ antlrcpp::Any GeneratorVisitor::visitTernary(SpiceParser::TernaryContext *ctx) { auto phi = builder->CreatePHI(thenValue->getType(), 2, "phi"); phi->addIncoming(thenValue, bThen); phi->addIncoming(elseValue, bElse); - return phi; + return (llvm::Value*) phi; } return visit(ctx->logicalOrExpr()[0]); - //return SpiceBaseVisitor::visitTernary(ctx); } antlrcpp::Any GeneratorVisitor::visitLogicalOrExpr(SpiceParser::LogicalOrExprContext *ctx) { @@ -381,7 +381,7 @@ antlrcpp::Any GeneratorVisitor::visitLogicalOrExpr(SpiceParser::LogicalOrExprCon auto lhs = visit(ctx->logicalAndExpr()[0]).as(); for (int i = 1; i < ctx->logicalAndExpr().size(); i++) { auto rhs = visit(ctx->logicalAndExpr()[i]).as(); - lhs = builder->CreateLogicalOr(lhs, rhs, "lg_or"); + lhs = builder->CreateLogicalOr(lhs, rhs, "log_or"); } return lhs; } @@ -393,7 +393,7 @@ antlrcpp::Any GeneratorVisitor::visitLogicalAndExpr(SpiceParser::LogicalAndExprC auto lhs = visit(ctx->bitwiseOrExpr()[0]).as(); for (int i = 1; i < ctx->bitwiseOrExpr().size(); i++) { auto rhs = visit(ctx->bitwiseOrExpr()[i]).as(); - lhs = builder->CreateLogicalAnd(lhs, rhs, "lg_and"); + lhs = builder->CreateLogicalAnd(lhs, rhs, "log_and"); } return lhs; } @@ -576,8 +576,10 @@ antlrcpp::Any GeneratorVisitor::visitValue(SpiceParser::ValueContext *ctx) { // Value is an identifier if (ctx->IDENTIFIER()) { - llvm::Value* var = namedValues[ctx->IDENTIFIER()->toString()]; - if (!var) throw std::runtime_error("Internal compiler error - Variable not found in code generation step"); + auto variableName = ctx->IDENTIFIER()->toString(); + llvm::Value* var = namedValues[variableName]; + if (!var) throw std::runtime_error("Internal compiler error - Variable '" + variableName + + "' not found in code generation step"); return (llvm::Value*) builder->CreateLoad(var->getType()->getPointerElementType(), var); } diff --git a/media/fibonacci.spice b/media/fibonacci.spice index 2268b7b83..46a862da1 100644 --- a/media/fibonacci.spice +++ b/media/fibonacci.spice @@ -1,12 +1,10 @@ f fibo(int n) { - if n <=1 { - return n; - } + if n <=1 { return n; } return fibo(n - 1) + fibo(n - 2); } f main() { - int result = fibo(5); + result = fibo(5); printf("%d", result); return 0; } \ No newline at end of file diff --git a/media/test.spice b/media/test.spice index 4538c4f63..8c0665b02 100644 --- a/media/test.spice +++ b/media/test.spice @@ -3,11 +3,17 @@ f testFunc() { return 1; } +p testProcedure() { + double result = true || false ? 5.1 : 4.12; + printf("Computation result: %d", result); +} + f main() { for int j = 0; j < 5; j++ { printf("For round: %d \n", j); } int testFuncResult = testFunc(); printf("Result of testFunc: %d \n", testFuncResult); + testProcedure(); return 0; } \ No newline at end of file From 56b05c8dbdb3a7021318817c3ec8117fb5da556f Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Wed, 14 Jul 2021 14:51:16 +0200 Subject: [PATCH 16/19] Add LLVM setup step to CI workflow --- .github/workflows/ci.yml | 20 ++++++++++++++++++++ compiler/src/CMakeLists.txt | 2 +- compiler/src/ir/GeneratorVisitor.cpp | 4 ---- compiler/src/ir/GeneratorVisitor.h | 1 - media/test.spice | 21 +++++---------------- 5 files changed, 26 insertions(+), 22 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1230ce300..1446fc721 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,26 @@ jobs: - name: Checkout uses: actions/checkout@v2 + - name: Cache LLVM and Clang + id: cache-llvm + uses: actions/cache@v2 + with: + path: ../llvm + key: llvm-12-0-1 + + - name: Setup LLVM + if: steps.cache-llvm.outputs.cache-hit != 'true' + run: | + mkdir -p ../llvm + cd ../llvm + curl -fsSL https://github.com/llvm/llvm-project/archive/refs/tags/llvmorg-12.0.1.tar.gz -o llvm.tar.gz + tar -zxf llvm.tar.gz + mkdir ./llvm-project-llvmorg-12.0.1/build + cd ./llvm-project-llvmorg-12.0.1/build + cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS_RELEASE="-O2" -G "Unix Makefiles" ../llvm + cmake --build . + export LLVM_DIR=/home/runner/work/spice/llvm/llvm-project-llvmorg-12.0.1/build/lib/cmake/llvm + - name: Download Libs run: | mkdir -p ./compiler/lib diff --git a/compiler/src/CMakeLists.txt b/compiler/src/CMakeLists.txt index 84879f4a7..1e53542e5 100644 --- a/compiler/src/CMakeLists.txt +++ b/compiler/src/CMakeLists.txt @@ -1,5 +1,5 @@ set(BINARY ${CMAKE_PROJECT_NAME}) -set(LLVM_DIR C:/Users/i516467/Documents/JustForFunGitHubClones/llvm-project/build-release/lib/cmake/llvm) +set(LLVM_DIR $ENV{LLVM_DIR}) LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) diff --git a/compiler/src/ir/GeneratorVisitor.cpp b/compiler/src/ir/GeneratorVisitor.cpp index 77c0839c0..fdc6144d1 100644 --- a/compiler/src/ir/GeneratorVisitor.cpp +++ b/compiler/src/ir/GeneratorVisitor.cpp @@ -291,10 +291,6 @@ antlrcpp::Any GeneratorVisitor::visitFunctionCall(SpiceParser::FunctionCallConte return builder->CreateCall(fct, argValues); } -antlrcpp::Any GeneratorVisitor::visitImportStmt(SpiceParser::ImportStmtContext *ctx) { - return SpiceBaseVisitor::visitImportStmt(ctx); -} - antlrcpp::Any GeneratorVisitor::visitReturnStmt(SpiceParser::ReturnStmtContext *ctx) { auto returnValue = visit(ctx->assignment()).as(); // Build return value diff --git a/compiler/src/ir/GeneratorVisitor.h b/compiler/src/ir/GeneratorVisitor.h index c625348cb..6080035ac 100644 --- a/compiler/src/ir/GeneratorVisitor.h +++ b/compiler/src/ir/GeneratorVisitor.h @@ -46,7 +46,6 @@ class GeneratorVisitor : public SpiceBaseVisitor { antlrcpp::Any visitIfStmt(SpiceParser::IfStmtContext *ctx) override; antlrcpp::Any visitDeclStmt(SpiceParser::DeclStmtContext *ctx) override; antlrcpp::Any visitFunctionCall(SpiceParser::FunctionCallContext *ctx) override; - antlrcpp::Any visitImportStmt(SpiceParser::ImportStmtContext *ctx) override; antlrcpp::Any visitReturnStmt(SpiceParser::ReturnStmtContext *ctx) override; antlrcpp::Any visitPrintfStmt(SpiceParser::PrintfStmtContext *ctx) override; antlrcpp::Any visitAssignment(SpiceParser::AssignmentContext *ctx) override; diff --git a/media/test.spice b/media/test.spice index 8c0665b02..ef04810ec 100644 --- a/media/test.spice +++ b/media/test.spice @@ -1,19 +1,8 @@ -f testFunc() { - printf("Hello from testFunc!\n"); - return 1; -} - -p testProcedure() { - double result = true || false ? 5.1 : 4.12; - printf("Computation result: %d", result); -} - f main() { - for int j = 0; j < 5; j++ { - printf("For round: %d \n", j); - } - int testFuncResult = testFunc(); - printf("Result of testFunc: %d \n", testFuncResult); - testProcedure(); + int operand1 = 6; + int operand2 = 5; + int res = operand1 | operand2; + printf("Computation result is: %d", res); + return 0; } \ No newline at end of file From 2b35f8736b7ae74be5fdb0d0cad99ae54a6bc2c4 Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Thu, 15 Jul 2021 09:32:33 +0200 Subject: [PATCH 17/19] Fix CI workflow --- .github/workflows/ci.yml | 27 +++++++++---------- compiler/src/CMakeLists.txt | 4 +-- .../{ir => generator}/GeneratorVisitor.cpp | 0 .../src/{ir => generator}/GeneratorVisitor.h | 0 compiler/src/main.cpp | 2 +- 5 files changed, 16 insertions(+), 17 deletions(-) rename compiler/src/{ir => generator}/GeneratorVisitor.cpp (100%) rename compiler/src/{ir => generator}/GeneratorVisitor.h (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1446fc721..7c39e890a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: - name: Checkout uses: actions/checkout@v2 - - name: Cache LLVM and Clang + - name: Cache LLVM id: cache-llvm uses: actions/cache@v2 with: @@ -25,15 +25,12 @@ jobs: - name: Setup LLVM if: steps.cache-llvm.outputs.cache-hit != 'true' run: | - mkdir -p ../llvm - cd ../llvm - curl -fsSL https://github.com/llvm/llvm-project/archive/refs/tags/llvmorg-12.0.1.tar.gz -o llvm.tar.gz - tar -zxf llvm.tar.gz - mkdir ./llvm-project-llvmorg-12.0.1/build - cd ./llvm-project-llvmorg-12.0.1/build + cd .. + git clone https://github.com/llvm/llvm-project llvm + mkdir ./llvm/build + cd ./llvm/build cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS_RELEASE="-O2" -G "Unix Makefiles" ../llvm cmake --build . - export LLVM_DIR=/home/runner/work/spice/llvm/llvm-project-llvmorg-12.0.1/build/lib/cmake/llvm - name: Download Libs run: | @@ -42,9 +39,11 @@ jobs: git clone https://github.com/google/googletest.git git clone https://github.com/antlr/antlr4.git - - name: Build - run: | - mkdir bin - cd bin - cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" -DWITH_TESTS=ON ../compiler - cmake --build . --target Spice_run -- -j 6 \ No newline at end of file + #- name: Build + # env: + # LLVM_DIR: /home/runner/work/spice/llvm/build/lib/cmake/llvm + # run: | + # mkdir bin + # cd bin + # cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" -DWITH_TESTS=ON ../compiler + # cmake --build . --target Spice_run -- -j 6 \ No newline at end of file diff --git a/compiler/src/CMakeLists.txt b/compiler/src/CMakeLists.txt index 1e53542e5..7111fe465 100644 --- a/compiler/src/CMakeLists.txt +++ b/compiler/src/CMakeLists.txt @@ -27,8 +27,8 @@ set(SOURCES analyzer/SymbolTable.h analyzer/SymbolTableEntry.cpp analyzer/SymbolTableEntry.h - ir/GeneratorVisitor.cpp - ir/GeneratorVisitor.h + generator/GeneratorVisitor.cpp + generator/GeneratorVisitor.h exception/SemanticError.cpp exception/SemanticError.h exception/IRError.cpp diff --git a/compiler/src/ir/GeneratorVisitor.cpp b/compiler/src/generator/GeneratorVisitor.cpp similarity index 100% rename from compiler/src/ir/GeneratorVisitor.cpp rename to compiler/src/generator/GeneratorVisitor.cpp diff --git a/compiler/src/ir/GeneratorVisitor.h b/compiler/src/generator/GeneratorVisitor.h similarity index 100% rename from compiler/src/ir/GeneratorVisitor.h rename to compiler/src/generator/GeneratorVisitor.h diff --git a/compiler/src/main.cpp b/compiler/src/main.cpp index 6722aa2b8..6fb2363d9 100644 --- a/compiler/src/main.cpp +++ b/compiler/src/main.cpp @@ -5,7 +5,7 @@ #include "SpiceLexer.h" #include "SpiceParser.h" #include "analyzer/AnalyzerVisitor.h" -#include "ir/GeneratorVisitor.h" +#include "generator/GeneratorVisitor.h" using namespace antlr4; From 7f576e11f7e1fbfe8006c5096a487357918952df Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Thu, 15 Jul 2021 15:39:51 +0200 Subject: [PATCH 18/19] Fix CI workflow --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7c39e890a..319d075ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: id: cache-llvm uses: actions/cache@v2 with: - path: ../llvm + path: /home/runner/work/spice/llvm key: llvm-12-0-1 - name: Setup LLVM From c7f7e990a202bcc5439176b6f2ed52132e4d4f82 Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Thu, 15 Jul 2021 22:29:50 +0200 Subject: [PATCH 19/19] Fix CI workflow --- .github/workflows/ci.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 319d075ac..b7dfc51ed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,11 +39,11 @@ jobs: git clone https://github.com/google/googletest.git git clone https://github.com/antlr/antlr4.git - #- name: Build - # env: - # LLVM_DIR: /home/runner/work/spice/llvm/build/lib/cmake/llvm - # run: | - # mkdir bin - # cd bin - # cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" -DWITH_TESTS=ON ../compiler - # cmake --build . --target Spice_run -- -j 6 \ No newline at end of file + - name: Build + env: + LLVM_DIR: /home/runner/work/spice/llvm/build/lib/cmake/llvm + run: | + mkdir bin + cd bin + cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" -DWITH_TESTS=ON ../compiler + cmake --build . --target Spice_run -- -j 6