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