From ec87178c5070016a426521888df8d087093fee65 Mon Sep 17 00:00:00 2001 From: Peter Matta <mattapet@fit.cvut.cz> Date: Mon, 30 Apr 2018 10:17:51 +0200 Subject: [PATCH] Generating object files --- include/dusk/Frontend/CompilerInstance.h | 3 ++ include/dusk/IRGen/Context.h | 6 +++ include/dusk/IRGen/IRGenerator.h | 2 +- lib/Frontend/CompilerInstance.cpp | 69 ++++++++++++++++++++++++ lib/IRGen/Context.cpp | 13 +++++ lib/IRGen/GenExpr.cpp | 5 +- lib/IRGen/GenStmt.cpp | 11 ++-- lib/IRGen/GenStmt.h | 1 + lib/IRGen/IRGenerator.cpp | 12 ++--- lib/Sema/TypeCheckDecl.cpp | 12 +++++ lib/Sema/TypeCheckStmt.cpp | 1 - tools/dusk-format/main.cpp | 1 - 12 files changed, 119 insertions(+), 17 deletions(-) diff --git a/include/dusk/Frontend/CompilerInstance.h b/include/dusk/Frontend/CompilerInstance.h index bfee280..8a33a4c 100644 --- a/include/dusk/Frontend/CompilerInstance.h +++ b/include/dusk/Frontend/CompilerInstance.h @@ -14,6 +14,7 @@ #include "dusk/Frontend/SourceFile.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/IR/Module.h" #include <memory> #ifndef DUSK_COMPILER_INSTANCE_H @@ -75,6 +76,8 @@ public: virtual void consume(SMDiagnostic &Diagnostic); private: + void emitObjectFile(llvm::Module *M); + // Explicitly forbid copying of any kind. CompilerInstance(const CompilerInstance &other) = delete; CompilerInstance &operator=(const CompilerInstance &other) = delete; diff --git a/include/dusk/IRGen/Context.h b/include/dusk/IRGen/Context.h index 720c40f..2ef5bc6 100644 --- a/include/dusk/IRGen/Context.h +++ b/include/dusk/IRGen/Context.h @@ -118,6 +118,12 @@ public: /// \return \c true on success, \c false if the current scope is already /// a value or function with the same identifier. bool declareVal(const Decl *); + + /// \brief Declares a value in current scope. + /// + /// \return \c true on success, \c false if the current scope is already + /// a value or function with the same identifier. + bool declareVal(const Decl *, llvm::Function *); /// \brief Declares a function. /// diff --git a/include/dusk/IRGen/IRGenerator.h b/include/dusk/IRGen/IRGenerator.h index b8f7fcc..0ef4005 100644 --- a/include/dusk/IRGen/IRGenerator.h +++ b/include/dusk/IRGen/IRGenerator.h @@ -56,7 +56,7 @@ public: llvm::Module *perform(); private: - bool prepareGlobals(Context &Ctx, ModuleDecl *M); + bool declareFuncs(Context &Ctx, ModuleDecl *M); }; } // namespace ir diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 0a6572d..5b5fecb 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -8,10 +8,24 @@ //===----------------------------------------------------------------------===// #include "dusk/Frontend/CompilerInstance.h" + #include "dusk/AST/Diagnostics.h" #include "dusk/Parse/Parser.h" #include "dusk/Sema/Sema.h" #include "dusk/IRGen/IRGenerator.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Verifier.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include <string> using namespace dusk; @@ -36,6 +50,8 @@ void CompilerInstance::performCompilation() { auto M = Gen.perform(); M->print(llvm::errs(), nullptr); llvm::errs() << "\n"; + + emitObjectFile(M); } void CompilerInstance::performSema() { @@ -65,3 +81,56 @@ void CompilerInstance::reset(CompilerInvocation &&I) { void CompilerInstance::consume(SMDiagnostic &Diagnostic) { Diagnostic.print("duskc", llvm::errs()); } + +void CompilerInstance::emitObjectFile(llvm::Module *M) { + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargets(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmParsers(); + llvm::InitializeAllAsmPrinters(); + + std::string Err; + auto Target = + llvm::TargetRegistry::lookupTarget(Invocation.getTargetTriple(), Err); + + if (!Target) { + llvm::errs() << Err; + return; + } + + auto CPU = "generic"; + auto Features = ""; + llvm::TargetOptions Opt; + auto RM = Optional<llvm::Reloc::Model>(); + auto TargetMachine = Target->createTargetMachine(Invocation.getTargetTriple(), + CPU, Features, Opt, RM); + + M->setDataLayout(TargetMachine->createDataLayout()); + M->setTargetTriple(Invocation.getTargetTriple()); + + // Open output file + auto Filename = "output.o"; // Invocation.getOutputFilename(); + std::error_code EC; + llvm::raw_fd_ostream dest(Filename, EC, llvm::sys::fs::F_None); + + if (EC) { + llvm::errs() << "Could not open file '" << Filename + << "': " << EC.message(); + return; + } + + // Emit pass + llvm::legacy::PassManager pass; + auto FileType = llvm::TargetMachine::CGFT_ObjectFile; + if (TargetMachine->addPassesToEmitFile(pass, dest, FileType)) { + llvm::errs() << "TargetMachine can't emit a file of this type"; + return; + } + llvm::verifyModule(*M, &llvm::errs()); + pass.run(*M); + dest.flush(); +} + + + + diff --git a/lib/IRGen/Context.cpp b/lib/IRGen/Context.cpp index 6fce761..584ffcd 100644 --- a/lib/IRGen/Context.cpp +++ b/lib/IRGen/Context.cpp @@ -79,6 +79,19 @@ bool Context::declareVal(const Decl *D) { return true; } +bool Context::declareVal(const Decl *D, llvm::Function *F) { + // Check if already declared in current scope + if (Impl->isDeclared(D->getName()) || Funcs[D->getName()] != nullptr) + return false; + + llvm::IRBuilder<> TmpB(&F->getEntryBlock(), F->getEntryBlock().begin()); + + auto Ty = llvm::Type::getInt64Ty(Ctx); + auto Var = TmpB.CreateAlloca(Ty, 0, D->getName()); + Impl->Values[D->getName()] = Var; + return true; +} + bool Context::declareFunc(const FuncDecl *Fn) { // Validate that we're in global scope. assert(Depth == 0 && "Function declaration must be declared in global scope"); diff --git a/lib/IRGen/GenExpr.cpp b/lib/IRGen/GenExpr.cpp index 8b37716..c6933a2 100644 --- a/lib/IRGen/GenExpr.cpp +++ b/lib/IRGen/GenExpr.cpp @@ -22,7 +22,7 @@ using namespace dusk; using namespace irgen; llvm::Value *cast(llvm::Value *V, Context &Ctx, llvm::Type *Ty) { - return Ctx.Builder.CreateBitCast(V, Ty); + return Ctx.Builder.CreateIntCast(V, Ty, true); } llvm::Value *irgen::codegenExpr(Context &Ctx, NumberLiteralExpr *E) { @@ -121,7 +121,8 @@ llvm::Value *irgen::codegenExpr(Context &Ctx, CallExpr *E) { // Get declared function auto Fn = Ctx.getFunc(CalleeID->getName()); - auto Args = std::vector<llvm::Value *>(Fn->arg_size()); + auto Args = std::vector<llvm::Value *>(); + llvm::errs() << Fn->arg_size(); for (auto Arg : ArgsPttrn->getValues()) Args.push_back(codegenExpr(Ctx, Arg)); return Ctx.Builder.CreateCall(Fn, Args); diff --git a/lib/IRGen/GenStmt.cpp b/lib/IRGen/GenStmt.cpp index 8f87053..4b0170a 100644 --- a/lib/IRGen/GenStmt.cpp +++ b/lib/IRGen/GenStmt.cpp @@ -10,7 +10,6 @@ #include "GenStmt.h" #include "GenDecl.h" #include "GenExpr.h" -#include <iostream> using namespace dusk; using namespace irgen; @@ -54,10 +53,12 @@ bool irgen::codegenStmt(Context &Ctx, Scope &Scp, BlockStmt *S) { // MARK: - Func statement -void genArgs(Context &Ctx, VarPattern *P) { +void genArgs(Context &Ctx, VarPattern *P, llvm::Function *F) { for (auto Arg : P->getVars()) - if (!Ctx.declareVal(Arg)) + if (!Ctx.declareVal(Arg, F)) llvm_unreachable("Redefinition of arg"); + for (auto &Arg : F->args()) + Ctx.Builder.CreateStore(&Arg, Ctx.getVal(Arg.getName())); } bool irgen::codegenStmt(Context &Ctx, Scope &Scp, FuncStmt *S) { @@ -69,7 +70,7 @@ bool irgen::codegenStmt(Context &Ctx, Scope &Scp, FuncStmt *S) { auto BB = llvm::BasicBlock::Create(Ctx, "entry", F); Ctx.Builder.SetInsertPoint(BB); Ctx.push(); - genArgs(Ctx, Args); + genArgs(Ctx, Args, F); codegenStmt(Ctx, Scp_, S->getBody()); Ctx.pop(); return true; @@ -103,8 +104,10 @@ bool irgen::codegenStmt(Context &Ctx, Scope &Scp, IfStmt *S) { Ctx.Builder.CreateCondBr(Cond, ThenBB, ElseBB); genBranch(Ctx, Scp_, ThenBB, S->getThen()); + Ctx.Builder.CreateBr(MergeBB); if (S->hasElseBlock()) genBranch(Ctx, Scp_, ElseBB, S->getElse()); + Ctx.Builder.CreateBr(MergeBB); Ctx.Builder.SetInsertPoint(MergeBB); return true; } diff --git a/lib/IRGen/GenStmt.h b/lib/IRGen/GenStmt.h index 34a7f97..dcd07be 100644 --- a/lib/IRGen/GenStmt.h +++ b/lib/IRGen/GenStmt.h @@ -32,6 +32,7 @@ bool codegenStmt(Context &Ctx, Scope &Scp, IfStmt *S); bool codegenStmt(Context &Ctx, Scope &Scp, WhileStmt *S); bool codegenStmt(Context &Ctx, Scope &Scp, ForStmt *S); bool codegenStmt(Context &Ctx, Scope &Scp, FuncStmt *S); +bool codegenStmt(Context &Ctx, Scope &Scp, ExternStmt *S); } // namespace irgen diff --git a/lib/IRGen/IRGenerator.cpp b/lib/IRGen/IRGenerator.cpp index 76480a0..cc4b0df 100644 --- a/lib/IRGen/IRGenerator.cpp +++ b/lib/IRGen/IRGenerator.cpp @@ -20,19 +20,18 @@ using namespace dusk; using namespace irgen; + IRGenerator::IRGenerator(ASTContext &C, DiagnosticEngine &Diag) : ASTCtx(C), Diag(Diag), Builder({Ctx}) {} IRGenerator::~IRGenerator() {} - - llvm::Module *IRGenerator::perform() { auto M = ASTCtx.getRootModule(); Module = std::make_unique<llvm::Module>(M->getName(), Ctx); Context Ctx(this->Ctx, Module.get(), Builder); Scope Scp; - prepareGlobals(Ctx, M); + declareFuncs(Ctx, M); for (auto &N : M->getContents()) { bool R = true; if (auto D = dynamic_cast<Decl *>(N)) @@ -43,18 +42,15 @@ llvm::Module *IRGenerator::perform() { R = codegenStmt(Ctx, Scp, S); else llvm_unreachable("Unexpected node"); - + if (!R) return nullptr; } return Module.release(); } -bool IRGenerator::prepareGlobals(Context &Ctx, ModuleDecl *M) { +bool IRGenerator::declareFuncs(Context &Ctx, ModuleDecl *M) { for (auto N : M->getContents()) { - if (auto D = dynamic_cast<Decl *>(N)) - if (!codegenDecl(Ctx, D)) - return false; if (auto Fn = dynamic_cast<FuncStmt *>(N)) if (!codegenDecl(Ctx, Fn->getPrototype())) return false; diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 9c94ffa..f96a16b 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -62,6 +62,12 @@ bool TypeChecker::postWalkLetDecl(LetDecl *D) { if (!D->getType() || !D->getValue()->getType()) return false; + if (!D->getType()->isValueType()) { + diagnose(D->getValue()->getLocStart(), + diag::expected_value_type_expression); + return false; + } + // Validate types if (D->getType()->isClassOf(D->getValue()->getType())) { // If types match, declare @@ -86,6 +92,12 @@ bool TypeChecker::postWalkVarDecl(VarDecl *D) { if (!D->getType() || (D->hasValue() && !D->getValue()->getType())) return false; + if (!D->getType()->isValueType()) { + diagnose(D->getValue()->getLocStart(), + diag::expected_value_type_expression); + return false; + } + // Validate types if (!D->hasValue() || D->getType()->isClassOf(D->getValue()->getType())) // If types match, declare diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 9824952..d09737c 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -152,4 +152,3 @@ bool TypeChecker::postWalkWhileStmt(WhileStmt *S) { diagnose(S->getCond()->getLocStart(), diag::expected_value_type_expression); return false; } - diff --git a/tools/dusk-format/main.cpp b/tools/dusk-format/main.cpp index 4b52ee8..066d714 100644 --- a/tools/dusk-format/main.cpp +++ b/tools/dusk-format/main.cpp @@ -3,7 +3,6 @@ #include "dusk/Frontend/CompilerInstance.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/CommandLine.h" -#include <iostream> #include <string> using namespace dusk; -- GitLab