diff --git a/src/compiler/compiler.cpp b/src/compiler/compiler.cpp new file mode 100644 index 0000000..575e02e --- /dev/null +++ b/src/compiler/compiler.cpp @@ -0,0 +1,170 @@ +#include "compiler.h" +#include "../main.h" +#include +#include +#include + +void error(std::string in) { + std::cout << "Compiler error:" << in << std::endl; + exit(1); +} + +GroundCompiler::GroundCompiler(const std::string& moduleName) { + context = std::make_unique(); + module = std::make_unique(moduleName, *context); + builder = std::make_unique>(*context); + + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + llvm::InitializeNativeTargetAsmParser(); +} + +void GroundCompiler::createMainFunction() { + llvm::FunctionType* mainType = llvm::FunctionType::get( + llvm::Type::getInt32Ty(*context), false + ); + + currentFunction = llvm::Function::Create( + mainType, llvm::Function::ExternalLinkage, "main", module.get() + ); + + llvm::BasicBlock* entry = llvm::BasicBlock::Create( + *context, "entry", currentFunction + ); + builder -> SetInsertPoint(entry); +} + +llvm::Function* GroundCompiler::getPrintfFunction() { + llvm::Function* printfFunc = module->getFunction("printf"); + if (!printfFunc) { + llvm::FunctionType* printfType = llvm::FunctionType::get( + llvm::Type::getInt32Ty(*context), + //llvm::Type::getInt8PtrTy(*context), + true + ); + printfFunc = llvm::Function::Create( + printfType, + llvm::Function::ExternalLinkage, + "printf", + module.get() + ); + } + return printfFunc; +} + +llvm::AllocaInst* GroundCompiler::createVariable(const std::string& name, llvm::Type* type) { + if (namedVals.find(name) != namedVals.end()) { + return namedVals[name]; + } + + llvm::IRBuilder<> tmpBuilder( + ¤tFunction -> getEntryBlock(), + currentFunction -> getEntryBlock().begin() + ); + llvm::AllocaInst* alloca = tmpBuilder.CreateAlloca(type, nullptr, name); + namedVals[name] = alloca; + return alloca; +} + +void GroundCompiler::compileInstruction(const Instruction& inst) { + switch (inst.inst) { + case Instructions::Set: + { + if (inst.args.size() < 2) break; + + const Direct& varRef = std::get(inst.args[0]); + const Literal& value = std::get(inst.args[1]); + + llvm::Value* val = nullptr; + llvm::Type* type = nullptr; + + if (std::holds_alternative(value.val)) { + int intVal = std::get(value.val); + val = llvm::ConstantInt::get(*context, llvm::APInt(32, intVal, true)); + type = llvm::Type::getInt32Ty(*context); + } else { + error("Unsupported type at present"); + } + + llvm::AllocaInst* variable = createVariable(varRef.varName, type); + builder->CreateStore(val, variable); + break; + } + default: + error("For now, only set instruction is supported in compiler"); + } +} + +void GroundCompiler::createBasicBlocks(const std::vector& instructions) { + for (size_t i = 0; i < instructions.size(); i++) { + llvm::BasicBlock* bb = llvm::BasicBlock::Create( + *context, "line_" + std::to_string(i), currentFunction + ); + lineBlocks[i] = bb; + } +} + +void GroundCompiler::compile(const std::vector& instructions) { + createMainFunction(); + createBasicBlocks(instructions); + + for (const auto& inst : instructions) { + compileInstruction(inst); + } + + std::string errorStr; + llvm::raw_string_ostream errorStream(errorStr); + if (llvm::verifyModule(*module, &errorStream)) { + error("Module verification error" + errorStr); + } +} + +bool GroundCompiler::writeObjectFile(const std::string& filename) { + char* targetTripleCStr = LLVMGetDefaultTargetTriple(); + std::string targetTriple(targetTripleCStr); + LLVMDisposeErrorMessage(targetTripleCStr); + module -> setTargetTriple(targetTriple); + std::string error; + const llvm::Target* target = llvm::TargetRegistry::lookupTarget(targetTriple, error); + + if (!target) { + llvm::errs() << "Target Error: " << error; + return false; + } + + llvm::TargetOptions opt; + llvm::TargetMachine* targetMachine = target -> createTargetMachine( + targetTriple, "generic", "", opt, llvm::Reloc::PIC_ + ); + + module -> setDataLayout(targetMachine -> createDataLayout()); + + std::error_code ec; + llvm::raw_fd_ostream dest(filename, ec, llvm::sys::fs::OF_None); + + if (ec) { + llvm::errs() << "Couldn't open file, error: " << ec.message(); + return false; + } + + llvm::legacy::PassManager pass; + if (targetMachine -> addPassesToEmitFile(pass, dest, nullptr, llvm::CodeGenFileType::ObjectFile)) { + llvm::errs() << "Target machine cannot emit object file"; + return false; + } + + pass.run(*module); + dest.flush(); + return true; +} + +void GroundCompiler::printIR() { + module->print(llvm::outs(), nullptr); +} + +void compile(std::vector instructions) { + std::cout << "gonna compile some crap" << std::endl; + GroundCompiler compiler("cool_program"); + compiler.compile(instructions); + compiler.printIR(); +} diff --git a/src/compiler/compiler.h b/src/compiler/compiler.h new file mode 100644 index 0000000..1d88e46 --- /dev/null +++ b/src/compiler/compiler.h @@ -0,0 +1,47 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include "../main.h" + +void error(std::string in); + +// class to make llvming around easier +class GroundCompiler { +private: + std::unique_ptr context; + std::unique_ptr module; + std::unique_ptr> builder; + + std::map namedVals; + + llvm::Function* currentFunction; + + std::map lineBlocks; +public: + GroundCompiler(const std::string& moduleName); + void createMainFunction(); + llvm::Function* getPrintfFunction(); + llvm::AllocaInst* createVariable(const std::string& name, llvm::Type* type); + void compileInstruction(const Instruction& inst); + void createBasicBlocks(const std::vector& instructions); + void compile(const std::vector& instructions); + bool writeObjectFile(const std::string& filename); + void printIR(); +}; + +void compile(std::vector instructions); + diff --git a/src/main.cpp b/src/main.cpp index 2209ff6..cbd909b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include "main.h" #include "data/data.h" @@ -45,6 +46,7 @@ #include "lexer/lexer.h" #include "parser/parser.h" #include "interpreter/interpreter.h" +#include "compiler/compiler.h" using namespace std; @@ -58,9 +60,15 @@ int main(int argc, char* argv[]) { cout << "Usage: ground " << endl; return 1; } - ifstream f(argv[1]); + int fileArg = 1; + bool compiling = false; + if (strcmp(argv[1], "-c") == 0 || strcmp(argv[1], "--compile") == 0) { + fileArg++; + compiling = true; + } + ifstream f(argv[fileArg]); if (!f) { - cout << "Could not open file " << argv[1] << endl; + cout << "Could not open file " << argv[fileArg] << endl; return 1; } string file_contents((istreambuf_iterator(f)), istreambuf_iterator()); @@ -68,8 +76,12 @@ int main(int argc, char* argv[]) { vector> lexed = lexer(file_contents); vector parsed = parser(lexed); - preProcessLabels(parsed); - exec(parsed); + if (compiling) { + compile(parsed); + } else { + preProcessLabels(parsed); + exec(parsed); + } return 0; -} \ No newline at end of file +}