Skip to content
Snippets Groups Projects
GenFunc.cpp 8.15 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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,
                                      /* Decl */ bool,
                                      /* Expr */ bool,
                                      /* Stmt */ bool,
                                      /* Pattern */ bool,
                                      /* TypeRepr */ bool> {
    
    Peter Matta's avatar
    Peter Matta committed
      typedef ASTVisitor super;
    
      IRGenFunc &IRGF;
    
    public:
      GenFunc(IRGenFunc &IRGF) : IRGF(IRGF) {}
    
    
      bool visitLetDecl(ValDecl *D) {
        return IRGF.declare(D).isValid();
      }
      
      bool visitVarDecl(ValDecl *D) {
    
    Peter Matta's avatar
    Peter Matta committed
        return IRGF.declare(D).isValid();
    
      bool visitBlockStmt(BlockStmt *S) {
    
    Peter Matta's avatar
    Peter Matta committed
        for (auto N : S->getNodes())
    
          if (auto D = dynamic_cast<Decl *>(N)) {
            if (!super::visit(D))
              return false;
          } else if (auto E = dynamic_cast<Expr *>(N)) {
            if (!super::visit(E))
              return false;
          } else if (auto S = dynamic_cast<Stmt *>(N)) {
            if (!super::visit(S))
              return false;
          } else {
            llvm_unreachable("Unexpected node.");
          }
    
    Peter Matta's avatar
    Peter Matta committed
        return true;
      }
    
    
      bool visitBreakStmt(BreakStmt *S) {
    
    Peter Matta's avatar
    Peter Matta committed
        // Get end block of top level loop
        auto EndBB = IRGF.LoopStack.getInfo().getEndBlock();
        return IRGF.Builder.CreateBr(EndBB) != nullptr;
      }
    
    
      bool visitReturnStmt(ReturnStmt *S) {
    
    Peter Matta's avatar
    Peter Matta committed
        if (!IRGF.Fn->getReturnType()->isVoidTy()) {
          auto RetVal = codegenExpr(IRGF.IRGM, S->getValue());
          IRGF.setRetVal(RetVal);
        }
        IRGF.Builder.CreateBr(IRGF.getRetBlock());
        return true;
      }
    
    
      bool visitIfStmt(IfStmt *S) {
    
    Peter Matta's avatar
    Peter Matta committed
        // 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 visitWhileStmt(WhileStmt *S) {
    
    Peter Matta's avatar
    Peter Matta committed
        // 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;
      }
    
    
      bool visitForStmt(ForStmt *S) {
    
    Peter Matta's avatar
    Peter Matta committed
        // 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;
      }
      
      
    
      bool visitFuncStmt(FuncStmt *S) { return true; }
      bool visitRangeStmt(RangeStmt *S) { return true; }
      bool visitSubscriptStmt(SubscriptStmt *S) { return true; }
      bool visitExternStmt(ExternStmt *S) { return true; }
      bool visitFuncDecl(FuncDecl *S) { return true; }
      bool visitModuleDecl(ModuleDecl *D) { return true; }
      bool visitParamDecl(ParamDecl *D) { return true; }
      bool visitNumberLiteralExpr(NumberLiteralExpr *E) {
    
    Peter Matta's avatar
    Peter Matta committed
        return codegenExpr(IRGF.IRGM, E) != nullptr;
      }
    
      bool visitArrayLiteralExpr(ArrayLiteralExpr *E) {
    
    Peter Matta's avatar
    Peter Matta committed
        return codegenExpr(IRGF.IRGM, E) != nullptr;
      }
    
      bool visitIdentifierExpr(IdentifierExpr *E) {
    
    Peter Matta's avatar
    Peter Matta committed
        return codegenExpr(IRGF.IRGM, E) != nullptr;
      }
    
      bool visitParenExpr(ParenExpr *E) {
    
    Peter Matta's avatar
    Peter Matta committed
        return codegenExpr(IRGF.IRGM, E) != nullptr;
      }
    
      bool visitAssignExpr(AssignExpr *E) {
    
    Peter Matta's avatar
    Peter Matta committed
        return codegenExpr(IRGF.IRGM, E) != nullptr;
      }
    
      bool visitInfixExpr(InfixExpr *E) {
    
    Peter Matta's avatar
    Peter Matta committed
        return codegenExpr(IRGF.IRGM, E) != nullptr;
      }
    
      bool visitPrefixExpr(PrefixExpr *E) {
    
    Peter Matta's avatar
    Peter Matta committed
        return codegenExpr(IRGF.IRGM, E) != nullptr;
      }
    
      bool visitCallExpr(CallExpr *E) {
    
    Peter Matta's avatar
    Peter Matta committed
        return codegenExpr(IRGF.IRGM, E) != nullptr;
      }
    
      bool visitSubscriptExpr(SubscriptExpr *E) {
    
    Peter Matta's avatar
    Peter Matta committed
        return codegenExpr(IRGF.IRGM, E) != nullptr;
      }
    };
    
    } // anonymous namespace
    
    bool irgen::genFunc(IRGenFunc &IRGF, FuncStmt *F) {
      GenFunc GF(IRGF);
    
      return GF.ASTVisitor::visit(F->getBody());