Skip to content
Snippets Groups Projects
GenFunc.cpp 7.27 KiB
Newer Older
Peter Matta's avatar
Peter Matta committed
//===--- GenFunc.cpp ------------------------------------------------------===//
//
//                                 dusk-lang
// This source file is part of a dusk-lang project, which is a semestral
// assignement for BI-PJP course at Czech Technical University in Prague.
// The software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND.
//
//===----------------------------------------------------------------------===//

#include "GenFunc.h"

#include "dusk/AST/Decl.h"
#include "dusk/AST/Expr.h"
#include "dusk/AST/Stmt.h"
#include "dusk/AST/Pattern.h"
#include "dusk/AST/Type.h"
#include "dusk/AST/Decl.h"
#include "dusk/AST/ASTVisitor.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Type.h"

#include "GenExpr.h"
#include "IRGenFunc.h"

using namespace dusk;
using namespace irgen;

static llvm::Value *emitCond(IRGenFunc &IRGF, Expr *E) {
  auto Cond = codegenExpr(IRGF.IRGM, E);
  auto Ty = llvm::Type::getInt64Ty(IRGF.IRGM.LLVMContext);
  auto Zero = llvm::ConstantInt::get(Ty, 0);
  return IRGF.Builder.CreateICmpNE(Cond, Zero, "ifcond");
}

namespace {

class GenFunc: public ASTVisitor<GenFunc> {
  typedef ASTVisitor super;

  IRGenFunc &IRGF;

public:
  GenFunc(IRGenFunc &IRGF) : IRGF(IRGF) {}

  bool visit(ValDecl *D) {
Peter Matta's avatar
Peter Matta committed
    return IRGF.declare(D).isValid();
Peter Matta's avatar
Peter Matta committed
  }

  bool visit(BlockStmt *S) {
    for (auto N : S->getNodes())
      if (!super::visit_(N))
Peter Matta's avatar
Peter Matta committed
        return false;
    return true;
  }

  bool visit(BreakStmt *S) {
    // Get end block of top level loop
    auto EndBB = IRGF.LoopStack.getInfo().getEndBlock();
    return IRGF.Builder.CreateBr(EndBB) != nullptr;
  }

  bool visit(ReturnStmt *S) {
    if (!IRGF.Fn->getReturnType()->isVoidTy()) {
      auto RetVal = codegenExpr(IRGF.IRGM, S->getValue());
      IRGF.setRetVal(RetVal);
    }
    IRGF.Builder.CreateBr(IRGF.getRetBlock());
    return true;
  }

  bool visit(IfStmt *S) {
    // Create basic blocks
    auto ThenBB =
        llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "if.then", IRGF.Fn);
    auto ElseBB = llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "if.else");
    auto ContBB = llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "if.cont");
    // Add basic blocks to function
    IRGF.Fn->getBasicBlockList().push_back(ElseBB);
    IRGF.Fn->getBasicBlockList().push_back(ContBB);

    // Emit conditional jump
    auto Cond = emitCond(IRGF, S->getCond());
    if (S->hasElseBlock())
      IRGF.Builder.CreateCondBr(Cond, ThenBB, ElseBB);
    else
      IRGF.Builder.CreateCondBr(Cond, ThenBB, ContBB);

    // Emit Then branch
    IRGF.Builder.SetInsertPoint(ThenBB);
    IRGF.IRGM.Lookup.push();
    if (!super::visit_(S->getThen()))
Peter Matta's avatar
Peter Matta committed
      return false;
    IRGF.IRGM.Lookup.pop();
    if (IRGF.Builder.GetInsertBlock()->getTerminator() == nullptr)
      IRGF.Builder.CreateBr(ContBB);

    // Emit else branch
    if (S->hasElseBlock()) {
      IRGF.Builder.SetInsertPoint(ElseBB);
      IRGF.IRGM.Lookup.push();
      if (!super::visit_(S->getElse()))
Peter Matta's avatar
Peter Matta committed
        return false;
      IRGF.IRGM.Lookup.pop();
      if (IRGF.Builder.GetInsertBlock()->getTerminator() == nullptr)
        IRGF.Builder.CreateBr(ContBB);
    } else {
      ElseBB->removeFromParent();
    }

    // Set pointer to the cont block.
    IRGF.Builder.SetInsertPoint(ContBB);
    return true;
  }

  bool visit(WhileStmt *S) {
    // Create loop blocks
    auto HeaderBlock =
        llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "loop.header", IRGF.Fn);
    auto BodyBlock =
        llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "loop.body");
    auto EndBlock = llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "loop.end");
    IRGF.IRGM.Lookup.push();
    IRGF.LoopStack.push(HeaderBlock, EndBlock);

    // Add block to function.
    IRGF.Fn->getBasicBlockList().push_back(BodyBlock);
    IRGF.Fn->getBasicBlockList().push_back(EndBlock);

    IRGF.Builder.CreateBr(HeaderBlock);
    // Emit condition
    IRGF.Builder.SetInsertPoint(HeaderBlock);
    auto Cond = emitCond(IRGF, S->getCond());
    IRGF.Builder.CreateCondBr(Cond, BodyBlock, EndBlock);

    // Emit loop body
    IRGF.Builder.SetInsertPoint(BodyBlock);
    if (!super::visit_(S->getBody()))
Peter Matta's avatar
Peter Matta committed
      return false;
    // Jump back to the condition
    if (IRGF.Builder.GetInsertBlock()->getTerminator() == nullptr)
      IRGF.Builder.CreateBr(HeaderBlock);

    IRGF.Builder.SetInsertPoint(EndBlock);
    IRGF.LoopStack.pop();
    IRGF.IRGM.Lookup.pop();
    return true;
  }

Peter Matta's avatar
Peter Matta committed
  bool visit(ForStmt *S) {
    // Create loop blocks
    auto HeaderBlock =
        llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "loop.header", IRGF.Fn);
    auto BodyBlock =
        llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "loop.body");
    auto EndBlock = llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "loop.end");
    IRGF.IRGM.Lookup.push();
    IRGF.LoopStack.push(HeaderBlock, EndBlock);
    
    // Add block to function.
    IRGF.Fn->getBasicBlockList().push_back(BodyBlock);
    IRGF.Fn->getBasicBlockList().push_back(EndBlock);
    
    // Emit initialization
    auto Iter = IRGF.declare(S->getIter());
    auto Rng = static_cast<RangeStmt *>(S->getRange());
    auto Val = codegenExpr(IRGF.IRGM, Rng->getStart());
    IRGF.Builder.CreateStore(Val, Iter);
    IRGF.Builder.CreateBr(HeaderBlock);
    
    // Emit condition
    IRGF.Builder.SetInsertPoint(HeaderBlock);
    auto LHS = IRGF.Builder.CreateLoad(Iter);
    auto RHS = codegenExpr(IRGF.IRGM, Rng->getEnd());
    auto Cond = IRGF.Builder.CreateICmpNE(LHS, RHS);
    IRGF.Builder.CreateCondBr(Cond, BodyBlock, EndBlock);
    
    // Emit loop body
    IRGF.Builder.SetInsertPoint(BodyBlock);
    if (!super::visit_(S->getBody()))
Peter Matta's avatar
Peter Matta committed
      return false;
    // Jump back to the condition
    auto Ty = llvm::Type::getInt64Ty(IRGF.IRGM.LLVMContext);
    auto IV = llvm::ConstantInt::get(Ty, 1);
    auto Incr = IRGF.Builder.CreateAdd(IRGF.Builder.CreateLoad(Iter), IV);
    IRGF.Builder.CreateStore(Incr, Iter);
    if (IRGF.Builder.GetInsertBlock()->getTerminator() == nullptr)
      IRGF.Builder.CreateBr(HeaderBlock);
    
    IRGF.Builder.SetInsertPoint(EndBlock);
    IRGF.LoopStack.pop();
    IRGF.IRGM.Lookup.pop();
    return true;
  }
  
  
Peter Matta's avatar
Peter Matta committed
  bool visit(FuncStmt *S) { return true; }
  bool visit(RangeStmt *S) { return true; }
  bool visit(SubscriptStmt *S) { return true; }
  bool visit(ExternStmt *S) { return true; }
  bool visit(FuncDecl *S) { return true; }
  bool visit(ModuleDecl *D) { return true; }
  bool visit(ParamDecl *D) { return true; }
  bool visit(NumberLiteralExpr *E) {
    return codegenExpr(IRGF.IRGM, E) != nullptr;
  }
Peter Matta's avatar
Peter Matta committed
  bool visit(ArrayLiteralExpr *E) {
    return codegenExpr(IRGF.IRGM, E) != nullptr;
  }
Peter Matta's avatar
Peter Matta committed
  bool visit(IdentifierExpr *E) {
    return codegenExpr(IRGF.IRGM, E) != nullptr;
  }
  bool visit(ParenExpr *E) {
    return codegenExpr(IRGF.IRGM, E) != nullptr;
  }
  bool visit(AssignExpr *E) {
    return codegenExpr(IRGF.IRGM, E) != nullptr;
  }
  bool visit(InfixExpr *E) {
    return codegenExpr(IRGF.IRGM, E) != nullptr;
  }
  bool visit(PrefixExpr *E) {
    return codegenExpr(IRGF.IRGM, E) != nullptr;
  }
  bool visit(CallExpr *E) {
    return codegenExpr(IRGF.IRGM, E) != nullptr;
  }
  bool visit(SubscriptExpr *E) {
    return codegenExpr(IRGF.IRGM, E) != nullptr;
  }
};

} // anonymous namespace

bool irgen::genFunc(IRGenFunc &IRGF, FuncStmt *F) {
  GenFunc GF(IRGF);
  return GF.ASTVisitor::visit_(F->getBody());