diff --git a/CMakeLists.txt b/CMakeLists.txt index 76493d03aa95d40587a42cde6990f434f083521f..dba0d98815f16600b5a12a2ba98e7d0c9662640f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.4 FATAL_ERROR) -set(LIB_TARGET dusklib) +set(LIB_TARGET dusk) set(PROJECT_VERSION 1.0.0) project( "dusk-lang" @@ -23,12 +23,12 @@ add_definitions(${LLVM_DEFINITIONS}) include_directories(${LLVM_INCLUDE_DIRS}) llvm_map_components_to_libnames(llvm_libs all) -# add dusklib target +# add lib target include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/include) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib) -# setup dusklib +# setup lib add_library(${LIB_TARGET} SHARED ${SOURCE}) set_target_properties(${LIB_TARGET} PROPERTIES VERSION ${PROJECT_VERSION} diff --git a/examples/funcDecl.dusk b/examples/funcDecl.dusk index 4b34590da67bcbf2bad48d4f143617f87cadfafc..2b13d556e106100b00d9f83ec4012b0b72671877 100644 --- a/examples/funcDecl.dusk +++ b/examples/funcDecl.dusk @@ -1,14 +1,22 @@ -extern func test(); -extern func println(output: Int) -> Void; +//extern func test(); +extern func println(output: Int) -> Int; -func main(arg1: Int) -> Int { - if arg1 % 2 == 0 { - return inc(arg1); - } - println(arg1); +/*func main(arg1: Int) -> Int { return arg1; +}*/ + +func isEven(val: Int) { + var i = 0; + while 1 { + println(i); + i = i + 1; + if i > val { + break; + } + } } func inc(i: Int) -> Int { + println(i); return i + 1; } diff --git a/examples/globExpr.dusk b/examples/globExpr.dusk index 4166ea3bf3db8c2d0d061da64f2adb89e66a6986..49a177689e3a61a584944d4bacb4e7d06c7cae9e 100644 --- a/examples/globExpr.dusk +++ b/examples/globExpr.dusk @@ -7,3 +7,11 @@ a = (1 + 2) * 8 == 2; a = (1 + 2 * d) || (4 % 3); ext(d); + +// var v = ext(a); +// var vv; +// var vvv: Int; +// let l: Int = 4; +// let ll = 44; +// let lll: Int; +ll = 14; diff --git a/include/dusk/AST/CMakeLists.txt b/include/dusk/AST/CMakeLists.txt index 1fa3515f0dc92fa81f43633e4bb36f8936fb6176..8b7c4a4eae2c0d68d95ee005112a0758cf8f3e1f 100644 --- a/include/dusk/AST/CMakeLists.txt +++ b/include/dusk/AST/CMakeLists.txt @@ -8,6 +8,7 @@ set(HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/Diagnostics.h ${CMAKE_CURRENT_SOURCE_DIR}/DiagnosticsParse.h ${CMAKE_CURRENT_SOURCE_DIR}/Expr.h + ${CMAKE_CURRENT_SOURCE_DIR}/NameLookup.h ${CMAKE_CURRENT_SOURCE_DIR}/Pattern.h ${CMAKE_CURRENT_SOURCE_DIR}/Scope.h ${CMAKE_CURRENT_SOURCE_DIR}/Stmt.h diff --git a/include/dusk/Sema/Context.h b/include/dusk/AST/NameLookup.h similarity index 80% rename from include/dusk/Sema/Context.h rename to include/dusk/AST/NameLookup.h index 3c3a08c415cb06b8dd24742d3ed87f4b7e66588a..f4283898f19e70e7f1bf58a9810f59b6d5567c28 100644 --- a/include/dusk/Sema/Context.h +++ b/include/dusk/AST/NameLookup.h @@ -1,4 +1,4 @@ -//===--- Context.h - Semantic declaration context ---------------*- C++ -*-===// +//===--- NameLookup.h - Name lookup of declarations -------------*- C++ -*-===// // // dusk-lang // This source file is part of a dusk-lang project, which is a semestral @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef DUSK_SEMA_CONTEXT_H -#define DUSK_SEMA_CONTEXT_H +#ifndef DUSK_CONTEXT_H +#define DUSK_CONTEXT_H #include "dusk/Basic/LLVM.h" #include "llvm/ADT/StringRef.h" @@ -17,16 +17,14 @@ namespace dusk { class Decl; - -namespace sema { /// Represents current context declaration level. /// /// Constructors of this struct are private, instances of \c ContextVals class /// can be made by only \c Context instances. -struct ContextImpl { +struct LookupImpl { /// Holds pointer to the parent context. - std::unique_ptr<ContextImpl> Parent = nullptr; + std::unique_ptr<LookupImpl> Parent = nullptr; /// Holds constant declarations of current scope. llvm::StringMap<Decl *> Consts; @@ -49,37 +47,37 @@ public: /// Returns variable for given name, if found, \c nullptr otherwise. Decl *get(StringRef Str) const; - /// Pushes a new context to the stack and returns a pointer to the top of the - /// stack. - ContextImpl *push(); + /// Pushes a new context layer to the stack and returns a pointer to the top + /// of the stack. + LookupImpl *push(); - /// Pop a top context from the stack and returns a pointer to the top of the - /// stack. + /// Pop a top context layer from the stack and returns a pointer to the top + /// of the stack. /// /// \note This method calls \c delete \c this on itself, therefore noone /// should access this object after calling this method. - ContextImpl *pop(); + LookupImpl *pop(); private: - friend class Context; - ContextImpl() = default; - ContextImpl(ContextImpl *P); + friend class NameLookup; + LookupImpl() = default; + LookupImpl(LookupImpl *P); - ContextImpl(const ContextImpl &other) = delete; - ContextImpl &operator=(const ContextImpl &other) = delete; + LookupImpl(const LookupImpl &other) = delete; + LookupImpl &operator=(const LookupImpl &other) = delete; }; -/// Represents a current declaration context. +/// Represents a current declaration lookup context. /// /// Holds declaration of variables, constatnts and functions. -class Context { +class NameLookup { llvm::StringMap<Decl *> Funcs; - ContextImpl *Impl; + LookupImpl *Impl; unsigned Depth = 0; public: - Context(); - ~Context(); + NameLookup(); + ~NameLookup(); /// Returns current depth of the context. unsigned getDepth() const { return Depth; } @@ -131,9 +129,7 @@ public: /// Pops current scope from the internal stack. void pop(); }; - -} // namespace sema } // namespace dusk -#endif /* DUSK_SEMA_CONTEXT_H */ +#endif /* DUSK_NAME_LOOKUP_H */ diff --git a/include/dusk/IRGen/CMakeLists.txt b/include/dusk/IRGen/CMakeLists.txt index 7c9df5ca67fa2dda671b7954bd526167bce034c9..a5c99b172835fd56238fbe2aafde372bc5e74bff 100644 --- a/include/dusk/IRGen/CMakeLists.txt +++ b/include/dusk/IRGen/CMakeLists.txt @@ -1,5 +1,4 @@ set(HEADERS - ${CMAKE_CURRENT_SOURCE_DIR}/Context.h ${CMAKE_CURRENT_SOURCE_DIR}/IRGenerator.h ${HEADERS} PARENT_SCOPE diff --git a/include/dusk/IRGen/Context.h b/include/dusk/IRGen/Context.h deleted file mode 100644 index 2ef5bc6f7bdfd4dde91c6f468c866f1f9b7c976b..0000000000000000000000000000000000000000 --- a/include/dusk/IRGen/Context.h +++ /dev/null @@ -1,171 +0,0 @@ -//===--- Context.h - Dusck context interface --------------------*- C++ -*-===// -// -// 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. -// -//===----------------------------------------------------------------------===// -// -// This file implements Dusk context interaface. -// -//===----------------------------------------------------------------------===// - -#ifndef DUSK_IRGEN_CONTEXT_H -#define DUSK_IRGEN_CONTEXT_H - -#include "dusk/Basic/LLVM.h" -#include "dusk/AST/Scope.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/IR/Value.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/GlobalVariable.h" -#include "llvm/IR/BasicBlock.h" -#include <utility> -#include <memory> - -namespace dusk { -class Decl; -class FuncDecl; -class ParamDecl; - -namespace irgen { - -/// Represents a basic block range. -struct BlockRange { - llvm::BasicBlock *Start; - llvm::BasicBlock *End; - - BlockRange(); - BlockRange(llvm::BasicBlock *S, llvm::BasicBlock *E); -}; - -/// Represents current context declaration level. -/// -/// Constructors of this struct are private, instances of \c ContextVals class -/// can be made by only \c Context instances. -struct ContextImpl { - /// Holds pointer to the parent context. - std::unique_ptr<ContextImpl> Parent = nullptr; - - /// Holds value declarations of current scope. - llvm::StringMap<llvm::Value *> Values; - -public: - /// Returns \c true if there is a reachable value delcaration for given name - /// the scope, \c false otherwise. - bool contains(StringRef Str) const { return get(Str) != nullptr; } - - /// Returns \c true if a declaration for given name was performed in current - /// scope. - bool isDeclared(StringRef Str) const; - - /// Returns variable for given name, if found, \c nullptr otherwise. - llvm::Value *get(StringRef Str) const; - - /// Pushes a new context to the stack and returns a pointer to the top of the - /// stack. - ContextImpl *push(); - - /// Pop a top context from the stack and returns a pointer to the top of the - /// stack. - /// - /// \note This method calls \c delete \c this on itself, therefore noone - /// should access this object after calling this method. - ContextImpl *pop(); - -private: - friend class Context; - ContextImpl() = default; - ContextImpl(ContextImpl *P); - - ContextImpl(const ContextImpl &other) = delete; - ContextImpl &operator=(const ContextImpl &other) = delete; -}; - -/// Represents a current declaration context. -/// -/// Holds declaration of variables, constatnts and functions. -class Context { - typedef std::pair<llvm::BasicBlock *, llvm::BasicBlock> BBRange; - - llvm::LLVMContext &Ctx; - llvm::StringMap<llvm::FunctionType *> Funcs; - llvm::DenseMap<Scope *, BlockRange> ScopeRanges; - ContextImpl *Impl; - unsigned Depth = 0; - -public: - llvm::Module *Module; - llvm::IRBuilder<> &Builder; - - Context(llvm::LLVMContext &C, llvm::Module *M, llvm::IRBuilder<> &B); - ~Context(); - - operator llvm::LLVMContext &() { return Ctx; } - - /// Returns current depth of the context. - unsigned getDepth() const { return Depth; } - - /// \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 *); - - /// \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. - /// - /// \note Function can be delcared only in the global scope. - /// - /// \return \c true on success, \c false if a function with given identifier - /// already exists. - bool declareFunc(const FuncDecl *); - - /// Returns a value for given identifier. - /// - /// If no value is found, \c nullptr is returned. - llvm::Value *getVal(StringRef Str) const; - - - /// Returns function type for given identifier. - /// - /// If no type is found, \c nullptr is returned. - llvm::FunctionType *getFuncProto(StringRef Str); - - /// Return function for given identifier. - llvm::Function *getFunc(StringRef Str); - - /// Returns \c true, if in the current scope if a declaration associated with - /// given identifier. - bool contains(StringRef Str) const; - - /// Pushes a new scope to the internal stack. - void push(); - - /// Pops current scope from the internal stack. - void pop(); - - void pushScope(Scope *S, BlockRange R); - - BlockRange &getRange(Scope *S); - - void popScope(Scope *S); -}; - -} // namespace irgen - -} // namespace dusk - -#endif /* DUSK_IRGEN_CONTEXT_H */ diff --git a/include/dusk/IRGen/IRGenerator.h b/include/dusk/IRGen/IRGenerator.h index 0ef40053790f110c10beda6b0d3658e7f8dd06fd..93354b02bdc5566bc9715043fb008c8cbc087aaa 100644 --- a/include/dusk/IRGen/IRGenerator.h +++ b/include/dusk/IRGen/IRGenerator.h @@ -16,8 +16,8 @@ #include "dusk/AST/Pattern.h" #include "dusk/AST/ASTWalker.h" #include "dusk/AST/Diagnostics.h" +#include "dusk/AST/NameLookup.h" #include "dusk/AST/ASTContext.h" -#include "dusk/IRGen/Context.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/APInt.h" @@ -41,22 +41,17 @@ namespace irgen { class IRGenerator : public ASTWalker { llvm::StringMap<llvm::AllocaInst *> NamedValues; - ASTContext &ASTCtx; + ASTContext &Context; DiagnosticEngine &Diag; - llvm::LLVMContext Ctx; + llvm::LLVMContext LLVMContext; llvm::IRBuilder<> Builder; std::unique_ptr<llvm::Module> Module; - - public: IRGenerator(ASTContext &Ctx, DiagnosticEngine &Diag); ~IRGenerator(); llvm::Module *perform(); - -private: - bool declareFuncs(Context &Ctx, ModuleDecl *M); }; } // namespace ir diff --git a/include/dusk/Sema/CMakeLists.txt b/include/dusk/Sema/CMakeLists.txt index 899180fcce42a5666254a11597f7cd2dfcd2a6aa..f79444778b836feb3bd5b3a34cabc30a94b63d4e 100644 --- a/include/dusk/Sema/CMakeLists.txt +++ b/include/dusk/Sema/CMakeLists.txt @@ -1,5 +1,4 @@ set(HEADERS - ${CMAKE_CURRENT_SOURCE_DIR}/Context.h ${CMAKE_CURRENT_SOURCE_DIR}/Sema.h ${HEADERS} PARENT_SCOPE diff --git a/include/dusk/Sema/Sema.h b/include/dusk/Sema/Sema.h index 4cb08fdbc947640ed712ae53d6a7ba2f7fd19c73..b282121e40ae159cb5e500186fa9696c121bbedc 100644 --- a/include/dusk/Sema/Sema.h +++ b/include/dusk/Sema/Sema.h @@ -13,7 +13,7 @@ #include "dusk/AST/ASTContext.h" #include "dusk/AST/ASTNode.h" #include "dusk/AST/Diagnostics.h" -#include "dusk/Sema/Context.h" +#include "dusk/AST/NameLookup.h" #include "dusk/AST/Scope.h" #include "llvm/Support/SourceMgr.h" @@ -38,7 +38,7 @@ class Sema { ASTContext &Ctx; DiagnosticEngine &Diag; - Context DeclCtx; + NameLookup DeclCtx; Scope Scp; public: diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 8cf5d93b600b8b0ec528ce5586233e2dc4dd73a9..205f2e292865b992790e641f12d5484c283e758a 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -6,6 +6,7 @@ set(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/Decl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Diagnostics.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Expr.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/NameLookup.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Pattern.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Scope.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Stmt.cpp diff --git a/lib/Sema/Context.cpp b/lib/AST/NameLookup.cpp similarity index 67% rename from lib/Sema/Context.cpp rename to lib/AST/NameLookup.cpp index f979db6012c23e5968691284032037835e187d2d..346290203c9cee0eda74e180425650cba343ad0a 100644 --- a/lib/Sema/Context.cpp +++ b/lib/AST/NameLookup.cpp @@ -1,4 +1,4 @@ -//===--- Context.cpp ------------------------------------------------------===// +//===--- NameLookup.cpp ---------------------------------------------------===// // // dusk-lang // This source file is part of a dusk-lang project, which is a semestral @@ -7,29 +7,28 @@ // //===----------------------------------------------------------------------===// -#include "dusk/Sema/Context.h" +#include "dusk/AST/NameLookup.h" #include "dusk/AST/Decl.h" using namespace dusk; -using namespace sema; // MARK: - Context values -ContextImpl::ContextImpl(ContextImpl *P) : Parent(P) {} +LookupImpl::LookupImpl(LookupImpl *P) : Parent(P) {} -ContextImpl *ContextImpl::push() { return new ContextImpl(this); } +LookupImpl *LookupImpl::push() { return new LookupImpl(this); } -ContextImpl *ContextImpl::pop() { +LookupImpl *LookupImpl::pop() { auto Ret = Parent.release(); delete this; return Ret; } -bool ContextImpl::isDeclared(StringRef Str) const { +bool LookupImpl::isDeclared(StringRef Str) const { return Vars.find(Str) != Vars.end() || Consts.find(Str) != Consts.end(); } -Decl *ContextImpl::getVar(StringRef Str) const { +Decl *LookupImpl::getVar(StringRef Str) const { auto Var = Vars.find(Str); if (Var != Vars.end()) return Var->second; @@ -39,7 +38,7 @@ Decl *ContextImpl::getVar(StringRef Str) const { return nullptr; } -Decl *ContextImpl::get(StringRef Str) const { +Decl *LookupImpl::get(StringRef Str) const { if (auto Var = getVar(Str)) return Var; @@ -54,11 +53,11 @@ Decl *ContextImpl::get(StringRef Str) const { // MARK: - Context -Context::Context(): Impl(new ContextImpl()) {} +NameLookup::NameLookup(): Impl(new LookupImpl()) {} -Context::~Context() { delete Impl; } +NameLookup::~NameLookup() { delete Impl; } -bool Context::declareVar(Decl *D) { +bool NameLookup::declareVar(Decl *D) { // Check if already declared in current scope if (Impl->isDeclared(D->getName()) || Funcs[D->getName()] != nullptr) return false; @@ -67,7 +66,7 @@ bool Context::declareVar(Decl *D) { return true; } -bool Context::declareLet(Decl *D) { +bool NameLookup::declareLet(Decl *D) { // Check if already declared in current scope if (Impl->isDeclared(D->getName()) || Funcs[D->getName()] != nullptr) return false; @@ -75,7 +74,7 @@ bool Context::declareLet(Decl *D) { return true; } -bool Context::declareFunc(Decl *Fn) { +bool NameLookup::declareFunc(Decl *Fn) { // Validate that we're in global scope. assert(Depth == 0 && "Function declaration must be declared in global scope"); @@ -86,24 +85,24 @@ bool Context::declareFunc(Decl *Fn) { return true; } -Decl *Context::getVal(StringRef Str) const { return Impl->get(Str); } +Decl *NameLookup::getVal(StringRef Str) const { return Impl->get(Str); } -Decl *Context::getVar(StringRef Str) const { return Impl->getVar(Str); } +Decl *NameLookup::getVar(StringRef Str) const { return Impl->getVar(Str); } -Decl *Context::getFunc(StringRef Str) { return Funcs[Str]; } +Decl *NameLookup::getFunc(StringRef Str) { return Funcs[Str]; } -bool Context::contains(StringRef Str) const { +bool NameLookup::contains(StringRef Str) const { return Funcs.find(Str) != Funcs.end() || Impl->contains(Str); } -void Context::push() { +void NameLookup::push() { ++Depth; // Update the 'virtual' stack. Impl = Impl->push(); } -void Context::pop() { +void NameLookup::pop() { assert(Depth != 0 && "Cannot pop from global scope"); --Depth; // Update the 'virtual' stack. diff --git a/lib/IRGen/Address.h b/lib/IRGen/Address.h new file mode 100644 index 0000000000000000000000000000000000000000..dbb894ee38dd5b369e8a4d8684550ce1349124ec --- /dev/null +++ b/lib/IRGen/Address.h @@ -0,0 +1,67 @@ +//===--- Address.h - Address representation ---------------------*- C++ -*-===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#ifndef DUSK_IRGEN_ADDRESS_H +#define DUSK_IRGEN_ADDRESS_H + +#include "dusk/Basic/LLVM.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/Value.h" +#include "llvm/IR/DerivedTypes.h" + +namespace dusk { + +namespace irgen { + +/// A simple convenience address wrapper. +class Address { + /// Encapsulated address. + llvm::Value *Addr; + +public: + /// Creates an invalid address. + Address() : Addr(nullptr) {} + + /// Creates a valid address. + Address(llvm::Value *A) : Addr(A) { + assert(Addr != nullptr && "Creating an invalid address"); + } + + /// Convenience imlicit conversion + operator llvm::Value *() const { + return getAddress(); + } + + /// Access the address. + llvm::Value *operator->() const { + assert(isValid() && "Accessing an invalid address"); + return getAddress(); + } + + /// Returns \c true if address is no null, \c false otherwise. + bool isValid() const { return Addr != nullptr; } + + /// Returns address value. + llvm::Value *getAddress() const { return Addr; } + + /// Returns address type as a pointer type. + llvm::PointerType *getType() const { + return llvm::cast<llvm::PointerType>(Addr->getType()); + } + + /// Returns IR name of address. + llvm::StringRef getName() const { + return getAddress()->getName(); + } +}; + +} // namespace irgen +} // namespcae dusk + +#endif /* DUSK_IRGEN_ADDRESS_H */ diff --git a/lib/IRGen/CMakeLists.txt b/lib/IRGen/CMakeLists.txt index f0a2add9efe19ebc4b0018ad9497cd436160e3d5..f02686421abb9ad62e044a7fc7e6a4d4255086c4 100644 --- a/lib/IRGen/CMakeLists.txt +++ b/lib/IRGen/CMakeLists.txt @@ -1,12 +1,18 @@ set(SOURCE - ${CMAKE_CURRENT_SOURCE_DIR}/Context.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/GenDecl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/GenDecl.h + ${CMAKE_CURRENT_SOURCE_DIR}/Address.h ${CMAKE_CURRENT_SOURCE_DIR}/GenExpr.cpp ${CMAKE_CURRENT_SOURCE_DIR}/GenExpr.h - ${CMAKE_CURRENT_SOURCE_DIR}/GenStmt.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/GenStmt.h + ${CMAKE_CURRENT_SOURCE_DIR}/GenFunc.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/GenFunc.h + ${CMAKE_CURRENT_SOURCE_DIR}/GenModule.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/GenModule.h ${CMAKE_CURRENT_SOURCE_DIR}/IRGenerator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/IRGenFunc.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/IRGenFunc.h + ${CMAKE_CURRENT_SOURCE_DIR}/IRGenModule.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/IRGenModule.h + ${CMAKE_CURRENT_SOURCE_DIR}/LoopInfo.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/LoopInfo.h ${SOURCE} PARENT_SCOPE ) diff --git a/lib/IRGen/Context.cpp b/lib/IRGen/Context.cpp deleted file mode 100644 index 584ffcdedd0d61a84b05b1bb30fe9da0f6e3e6bb..0000000000000000000000000000000000000000 --- a/lib/IRGen/Context.cpp +++ /dev/null @@ -1,164 +0,0 @@ -//===--- Context.cpp - Dusck context implementation -----------------------===// -// -// 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. -// -//===----------------------------------------------------------------------===// -// -// This file implements Dusk context implementation. -// -//===----------------------------------------------------------------------===// - -#include "dusk/IRGen/Context.h" -#include "dusk/AST/Decl.h" -#include "dusk/AST/Pattern.h" -#include "dusk/AST/Type.h" -#include <vector> - -#include "GenExpr.h" - -using namespace dusk; -using namespace irgen; - -// MARK: - Block range - -BlockRange::BlockRange() : Start(nullptr), End(nullptr) {} -BlockRange::BlockRange(llvm::BasicBlock *S, llvm::BasicBlock *E) - : Start(S), End(E) {} - -// MARK: - Context values - -ContextImpl::ContextImpl(ContextImpl *P) : Parent(P) {} - -ContextImpl *ContextImpl::push() { return new ContextImpl(this); } - -ContextImpl *ContextImpl::pop() { - auto Ret = Parent.release(); - delete this; - return Ret; -} - -bool ContextImpl::isDeclared(StringRef Str) const { - return Values.find(Str) != Values.end(); -} - -llvm::Value *ContextImpl::get(StringRef Str) const { - auto Val = Values.find(Str); - if (Val != Values.end()) - return Val->second; - if (Parent != nullptr) - return Parent->get(Str); - return nullptr; -} - -// MARK: - Context - -Context::Context(llvm::LLVMContext &C, llvm::Module *M, llvm::IRBuilder<> &B) - : Ctx(C), Impl(new ContextImpl()), Module(M), Builder(B) {} - -Context::~Context() { delete Impl; } - -bool Context::declareVal(const Decl *D) { - // Check if already declared in current scope - if (Impl->isDeclared(D->getName()) || Funcs[D->getName()] != nullptr) - return false; - - // Check if global - if (Depth == 0) { - auto GV = - Module->getOrInsertGlobal(D->getName(), llvm::Type::getInt64Ty(Ctx)); - Impl->Values[D->getName()] = GV; - return true; - } - - auto Ty = llvm::Type::getInt64Ty(Ctx); - auto Var = Builder.CreateAlloca(Ty, 0, D->getName()); - Impl->Values[D->getName()] = Var; - 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"); - - // Check if already declared in current scope - if (Funcs[Fn->getName()] != nullptr) - return false; - - auto FnType = static_cast<FunctionType *>(Fn->getType()); - auto Ty = llvm::Type::getInt64Ty(Ctx); - auto Args = std::vector<llvm::Type *>(Fn->getArgs()->count(), Ty); - llvm::Type *RetTy; - - // Resolve return type - switch (FnType->getRetType()->getKind()) { - case TypeKind::Int: - RetTy = llvm::Type::getInt64Ty(Ctx); - break; - case TypeKind::Void: - RetTy = llvm::Type::getVoidTy(Ctx); - break; - default: - llvm_unreachable("Unsupported return type"); - } - auto FT = llvm::FunctionType::get(RetTy, Args, false); - Funcs[Fn->getName()] = FT; - return true; -} - -llvm::Value *Context::getVal(StringRef Str) const { return Impl->get(Str); } - -llvm::FunctionType *Context::getFuncProto(StringRef Str) { return Funcs[Str]; } - -llvm::Function *Context::getFunc(StringRef Str) { - if (auto F = Module->getFunction(Str)) - return F; - return nullptr; -} - -bool Context::contains(StringRef Str) const { - return Funcs.find(Str) != Funcs.end() || Impl->contains(Str); -} - -void Context::push() { - ++Depth; - // Update the 'virtual' stack. - Impl = Impl->push(); -} - -void Context::pop() { - assert(Depth != 0 && "Cannot pop from global scope"); - --Depth; - // Update the 'virtual' stack. - Impl = Impl->pop(); -} - -void Context::pushScope(Scope *S, BlockRange R) { - assert(ScopeRanges.find(S) == ScopeRanges.end() && "Duplicate scope range"); - ScopeRanges.try_emplace(S, R); -} - -BlockRange &Context::getRange(Scope *S) { - assert(ScopeRanges.find(S) != ScopeRanges.end() && "Missing scope range"); - return ScopeRanges[S]; -} - -void Context::popScope(Scope *S) { - assert(ScopeRanges.find(S) != ScopeRanges.end() && "Missing scope range"); - ScopeRanges.erase(S); -} diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp deleted file mode 100644 index 71199f2567739de974511d8bff331b10a70edaf3..0000000000000000000000000000000000000000 --- a/lib/IRGen/GenDecl.cpp +++ /dev/null @@ -1,70 +0,0 @@ -//===--- GenDecl.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 "GenDecl.h" -#include "GenExpr.h" - -using namespace dusk; -using namespace irgen; - -bool irgen::codegenDecl(Context &Ctx, VarDecl *D) { - if (!Ctx.declareVal(D)) - llvm_unreachable("Redefinition"); - - auto Addr = Ctx.getVal(D->getName()); - auto Val = codegenExpr(Ctx, D->getValue()); - Ctx.Builder.CreateStore(Val, Addr); - return true; -} - -bool irgen::codegenDecl(Context &Ctx, LetDecl *D) { - if (!Ctx.declareVal(D)) - llvm_unreachable("Redefinition"); - - auto Addr = Ctx.getVal(D->getName()); - auto Val = codegenExpr(Ctx, D->getValue()); - Ctx.Builder.CreateStore(Val, Addr); - return true; -} - -bool irgen::codegenDecl(Context &Ctx, FuncDecl *D) { - if (!Ctx.declareFunc(D)) - llvm_unreachable("Redefinition of function"); - - auto P = Ctx.getFuncProto(D->getName()); - auto F = llvm::Function::Create(P, llvm::Function::ExternalLinkage, - D->getName(), Ctx.Module); - unsigned Idx = 0; - auto Args = D->getArgs()->getVars(); - for (auto &Arg : F->args()) - Arg.setName(Args[Idx++]->getName()); - return true; -} - -bool irgen::codegenDecl(Context &Ctx, ParamDecl *D) { - if (!Ctx.declareVal(D)) - llvm_unreachable("Redefinition."); - return true; -} - -bool irgen::codegenDecl(Context &Ctx, Decl *D) { - switch (D->getKind()) { - case DeclKind::Var: - return codegenDecl(Ctx, static_cast<VarDecl *>(D)); - case DeclKind::Let: - return codegenDecl(Ctx, static_cast<LetDecl *>(D)); - case DeclKind::Func: - return codegenDecl(Ctx, static_cast<FuncDecl *>(D)); - case DeclKind::Param: - return codegenDecl(Ctx, static_cast<ParamDecl *>(D)); - default: - llvm_unreachable("Invalid declaration"); - } -} - diff --git a/lib/IRGen/GenDecl.h b/lib/IRGen/GenDecl.h deleted file mode 100644 index 802ab7ded75aa6e6017419f91c5b1c8c13988f3a..0000000000000000000000000000000000000000 --- a/lib/IRGen/GenDecl.h +++ /dev/null @@ -1,37 +0,0 @@ -//===--- GenDecl.h - Dusk IR declaration generation -------------*- C++ -*-===// -// -// 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. -// -//===----------------------------------------------------------------------===// - -#ifndef DUSK_IRGEN_DECL_H -#define DUSK_IRGEN_DECL_H - -#include "dusk/AST/Decl.h" -#include "dusk/AST/Expr.h" -#include "dusk/AST/Stmt.h" -#include "dusk/AST/Pattern.h" -#include "dusk/IRGen/Context.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Value.h" -#include "llvm/IR/LLVMContext.h" -#include "GenExpr.h" - -namespace dusk { - -namespace irgen { - -bool codegenDecl(Context &Ctx, Decl *D); -bool codegenDecl(Context &Ctx, VarDecl *D); -bool codegenDecl(Context &Ctx, LetDecl *D); -bool codegenDecl(Context &Ctx, FuncDecl *D); -bool codegenDecl(Context &Ctx, ParamDecl *D); - -} // namespace irgen - -} // namespace dusk - -#endif /* DUSK_IRGEN_DECL_H */ diff --git a/lib/IRGen/GenExpr.cpp b/lib/IRGen/GenExpr.cpp index c6933a2385f07b0727282365fcf7b654e133007a..19ede3a6252557e87c1a5a43b010251e6a3e80f3 100644 --- a/lib/IRGen/GenExpr.cpp +++ b/lib/IRGen/GenExpr.cpp @@ -13,105 +13,107 @@ #include "dusk/AST/Expr.h" #include "dusk/AST/Stmt.h" #include "dusk/AST/Pattern.h" -#include "dusk/IRGen/Context.h" #include "llvm/ADT/APSInt.h" #include "llvm/IR/Constant.h" #include <vector> +#include "IRGenModule.h" +#include "IRGenFunc.h" + using namespace dusk; using namespace irgen; -llvm::Value *cast(llvm::Value *V, Context &Ctx, llvm::Type *Ty) { - return Ctx.Builder.CreateIntCast(V, Ty, true); +static llvm::Value *cast(IRGenModule &IRGM, llvm::Value *V, llvm::Type *Ty) { + return IRGM.Builder.CreateIntCast(V, Ty, true); } -llvm::Value *irgen::codegenExpr(Context &Ctx, NumberLiteralExpr *E) { - auto Ty = llvm::Type::getInt64Ty(Ctx); +llvm::Value *irgen::codegenExpr(IRGenModule &IRGM, NumberLiteralExpr *E) { + auto Ty = llvm::Type::getInt64Ty(IRGM.LLVMContext); return llvm::ConstantInt::get(Ty, E->getValue()); } -llvm::Value *irgen::codegenExpr(Context &Ctx, IdentifierExpr *E) { - auto Addr = Ctx.getVal(E->getName()); - return Ctx.Builder.CreateLoad(Addr, E->getName()); +llvm::Value *irgen::codegenExpr(IRGenModule &IRGM, IdentifierExpr *E) { + auto Addr = IRGM.getVal(E->getName()); + return IRGM.Builder.CreateLoad(Addr, E->getName()); } -llvm::Value *irgen::codegenExpr(Context &Ctx, InfixExpr *E) { - auto LHS = codegenExpr(Ctx, E->getLHS()); - auto RHS = codegenExpr(Ctx, E->getRHS()); - auto Ty = llvm::Type::getInt64Ty(Ctx); +llvm::Value *irgen::codegenExpr(IRGenModule &IRGM, InfixExpr *E) { + auto LHS = codegenExpr(IRGM, E->getLHS()); + auto RHS = codegenExpr(IRGM, E->getRHS()); + auto Ty = llvm::Type::getInt64Ty(IRGM.LLVMContext); if (!LHS || !RHS) return nullptr; switch (E->getOp().getKind()) { // Arithemtic operations case tok::plus: - return Ctx.Builder.CreateAdd(LHS, RHS, "addtmp"); + return IRGM.Builder.CreateAdd(LHS, RHS, "addtmp"); case tok::minus: - return Ctx.Builder.CreateSub(LHS, RHS, "subtmp"); + return IRGM.Builder.CreateSub(LHS, RHS, "subtmp"); case tok::multipy: - return Ctx.Builder.CreateMul(LHS, RHS, "multmp"); + return IRGM.Builder.CreateMul(LHS, RHS, "multmp"); case tok::divide: - return Ctx.Builder.CreateSDiv(LHS, RHS, "divtmp"); + return IRGM.Builder.CreateSDiv(LHS, RHS, "divtmp"); case tok::mod: - return Ctx.Builder.CreateSRem(LHS, RHS, "modtmp"); + return IRGM.Builder.CreateSRem(LHS, RHS, "modtmp"); // Logical operations case tok::land: - return cast(Ctx.Builder.CreateAnd(LHS, RHS, "andtmp"), Ctx, Ty); + return cast(IRGM, IRGM.Builder.CreateAnd(LHS, RHS, "andtmp"), Ty); case tok::lor: - return cast(Ctx.Builder.CreateOr(LHS, RHS, "ortmp"), Ctx, Ty); + return cast(IRGM, IRGM.Builder.CreateOr(LHS, RHS, "ortmp"), Ty); case tok::equals: - return cast(Ctx.Builder.CreateICmpEQ(LHS, RHS, "eqtmp"), Ctx, Ty); + return cast(IRGM, IRGM.Builder.CreateICmpEQ(LHS, RHS, "eqtmp"), Ty); case tok::nequals: - return cast(Ctx.Builder.CreateICmpNE(LHS, RHS, "neqtmp"), Ctx, Ty); + return cast(IRGM, IRGM.Builder.CreateICmpNE(LHS, RHS, "neqtmp"), Ty); case tok::greater: - return cast(Ctx.Builder.CreateICmpSGT(LHS, RHS, "gttmp"), Ctx, Ty); + return cast(IRGM, IRGM.Builder.CreateICmpSGT(LHS, RHS, "gttmp"), Ty); case tok::greater_eq: - return cast(Ctx.Builder.CreateICmpSGE(LHS, RHS, "getmp"), Ctx, Ty); + return cast(IRGM, IRGM.Builder.CreateICmpSGE(LHS, RHS, "getmp"), Ty); case tok::less: - return cast(Ctx.Builder.CreateICmpSLT(LHS, RHS, "lttmp"), Ctx, Ty); + return cast(IRGM, IRGM.Builder.CreateICmpSLT(LHS, RHS, "lttmp"), Ty); case tok::less_eq: - return cast(Ctx.Builder.CreateICmpSLE(LHS, RHS, "letmp"), Ctx, Ty); + return cast(IRGM, IRGM.Builder.CreateICmpSLE(LHS, RHS, "letmp"), Ty); default: llvm_unreachable("Invalid infix operand"); } } -llvm::Value *irgen::codegenExpr(Context &Ctx, PrefixExpr *E) { - auto Val = codegenExpr(Ctx, E->getDest()); - auto Ty = llvm::Type::getInt64Ty(Ctx); +llvm::Value *irgen::codegenExpr(IRGenModule &IRGM, PrefixExpr *E) { + auto Val = codegenExpr(IRGM, E->getDest()); + auto Ty = llvm::Type::getInt64Ty(IRGM.LLVMContext); if (!Val) return nullptr; switch (E->getOp().getKind()) { case tok::lnot: - return cast(Ctx.Builder.CreateNot(Val), Ctx, Ty); + return cast(IRGM, IRGM.Builder.CreateNot(Val), Ty); case tok::minus: { - auto Ty = llvm::Type::getInt64Ty(Ctx); + auto Ty = llvm::Type::getInt64Ty(IRGM.LLVMContext); auto Zero = llvm::ConstantInt::get(Ty, 0); - return Ctx.Builder.CreateSub(Zero, Val, "unary-subtmp"); + return IRGM.Builder.CreateSub(Zero, Val, "unary-subtmp"); } default: llvm_unreachable("Invalid prefix operand"); } } -llvm::Value *irgen::codegenExpr(Context &Ctx, AssignExpr *E) { +llvm::Value *irgen::codegenExpr(IRGenModule &IRGM, AssignExpr *E) { // Ensure the LHS is a identifier. auto VarExpr = static_cast<IdentifierExpr *>(E->getDest()); // Get variable address - auto VarAddr = Ctx.getVal(VarExpr->getName()); - auto Val = codegenExpr(Ctx, E->getSource()); + auto VarAddr = IRGM.getVal(VarExpr->getName()); + auto Val = codegenExpr(IRGM, E->getSource()); if (!VarAddr || !Val) llvm_unreachable("Invalid val or addr"); - return Ctx.Builder.CreateStore(Val, VarAddr, "assign"); + return IRGM.Builder.CreateStore(Val, VarAddr, "assign"); } -llvm::Value *irgen::codegenExpr(Context &Ctx, CallExpr *E) { +llvm::Value *irgen::codegenExpr(IRGenModule &IRGM, CallExpr *E) { // Get callee as identifier. auto CalleeID = static_cast<IdentifierExpr *>(E->getCalle()); @@ -119,32 +121,34 @@ llvm::Value *irgen::codegenExpr(Context &Ctx, CallExpr *E) { auto ArgsPttrn = static_cast<ExprPattern *>(E->getArgs()); // Get declared function - auto Fn = Ctx.getFunc(CalleeID->getName()); + auto Fn = IRGM.getFunc(CalleeID->getName()); 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); + Args.push_back(codegenExpr(IRGM, Arg)); + return IRGM.Builder.CreateCall(Fn, Args); } -llvm::Value *irgen::codegenExpr(Context &Ctx, Expr *E) { - switch (E->getKind()) { - case ExprKind::NumberLiteral: - return codegenExpr(Ctx, static_cast<NumberLiteralExpr *>(E)); - case ExprKind::Identifier: - return codegenExpr(Ctx, static_cast<IdentifierExpr *>(E)); - case ExprKind::Paren: - return codegenExpr(Ctx, static_cast<ParenExpr *>(E)->getExpr()); - case ExprKind::Assign: - return codegenExpr(Ctx, static_cast<AssignExpr *>(E)); - case ExprKind::Infix: - return codegenExpr(Ctx, static_cast<InfixExpr *>(E)); - case ExprKind::Prefix: - return codegenExpr(Ctx, static_cast<PrefixExpr *>(E)); - case ExprKind::Call: - return codegenExpr(Ctx, static_cast<CallExpr *>(E)); - case ExprKind::Subscript: - return codegenExpr(Ctx, static_cast<SubscriptExpr *>(E)); + +llvm::Value *irgen::codegenExpr(IRGenModule &IRGM, Expr *E) { + switch (E->getKind()) { + case ExprKind::NumberLiteral: + return codegenExpr(IRGM, static_cast<NumberLiteralExpr *>(E)); + case ExprKind::Identifier: + return codegenExpr(IRGM, static_cast<IdentifierExpr *>(E)); + case ExprKind::Paren: + return codegenExpr(IRGM, static_cast<ParenExpr *>(E)->getExpr()); + case ExprKind::Assign: + return codegenExpr(IRGM, static_cast<AssignExpr *>(E)); + case ExprKind::Infix: + return codegenExpr(IRGM, static_cast<InfixExpr *>(E)); + case ExprKind::Prefix: + return codegenExpr(IRGM, static_cast<PrefixExpr *>(E)); + case ExprKind::Call: + return codegenExpr(IRGM, static_cast<CallExpr *>(E)); + case ExprKind::Subscript: +// return codegenExpr(IRGM, static_cast<SubscriptExpr *>(E)); + llvm_unreachable("Not implemented."); } } + diff --git a/lib/IRGen/GenExpr.h b/lib/IRGen/GenExpr.h index bd3a6f37d60ce290bd71f1ead151a6a1bce8c639..a1e4559ad50f2bcbc87c448be14d59b420db7f5d 100644 --- a/lib/IRGen/GenExpr.h +++ b/lib/IRGen/GenExpr.h @@ -10,6 +10,8 @@ #ifndef DUSK_IRGEN_EXPR_H #define DUSK_IRGEN_EXPR_H +#include "llvm/IR/IRBuilder.h" + namespace llvm { class Value; } @@ -22,20 +24,22 @@ class InfixExpr; class PrefixExpr; class AssignExpr; class CallExpr; - + + namespace irgen { -class Context; - -llvm::Value *codegenExpr(Context &Ctx, Expr *E); -llvm::Value *codegenExpr(Context &Ctx, NumberLiteralExpr *E); -llvm::Value *codegenExpr(Context &Ctx, IdentifierExpr *E); -llvm::Value *codegenExpr(Context &Ctx, InfixExpr *E); -llvm::Value *codegenExpr(Context &Ctx, PrefixExpr *E); -llvm::Value *codegenExpr(Context &Ctx, AssignExpr *E); -llvm::Value *codegenExpr(Context &Ctx, CallExpr *E); - +class IRGenModule; +class IRGenFunc; + +llvm::Value *codegenExpr(IRGenModule &IRGM, NumberLiteralExpr *E); +llvm::Value *codegenExpr(IRGenModule &IRGM, IdentifierExpr *E); +llvm::Value *codegenExpr(IRGenModule &IRGM, InfixExpr *E); +llvm::Value *codegenExpr(IRGenModule &IRGM, PrefixExpr *E); +llvm::Value *codegenExpr(IRGenModule &IRGM, AssignExpr *E); +llvm::Value *codegenExpr(IRGenModule &IRGM, CallExpr *E); +llvm::Value *codegenExpr(IRGenModule &IRGM, Expr *E); + } // namespace irgen - + } // namespace dusk #endif /* DUSK_IRGEN_EXPR_H */ diff --git a/lib/IRGen/GenFunc.cpp b/lib/IRGen/GenFunc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fb11e1b47e5fecfd64b3ad9cf18acbab070d4f1a --- /dev/null +++ b/lib/IRGen/GenFunc.cpp @@ -0,0 +1,196 @@ +//===--- 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) { + auto Addr = IRGF.declare(D); + if (D->hasValue()) { + auto Val = codegenExpr(IRGF.IRGM, D->getValue()); + IRGF.Builder.CreateStore(Val, Addr); + } + return Addr.isValid(); + } + + bool visit(BlockStmt *S) { + for (auto N : S->getNodes()) + if (!super::visit(N)) + 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())) + 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())) + 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())) + 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 visit(ForStmt *S) { return true; } + 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; + } + 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()); +} + diff --git a/lib/IRGen/GenFunc.h b/lib/IRGen/GenFunc.h new file mode 100644 index 0000000000000000000000000000000000000000..5e395c070de0b36892cdad9fb1d7ca95e0255510 --- /dev/null +++ b/lib/IRGen/GenFunc.h @@ -0,0 +1,43 @@ +//===--- GenFunc.h - Function generation state ------------------*- C++ -*-===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#ifndef DUSK_IRGEN_GEN_FUNC_H +#define DUSK_IRGEN_GEN_FUNC_H + +#include "dusk/Basic/LLVM.h" + +#include "Address.h" + +namespace llvm { + +class Function; +class FunctionType; +class BasicBlock; + +} // namespace llvm + +namespace dusk { +class Decl; +class Stmt; +class FuncDecl; +class FuncStmt; +class BlockStmt; +class Type; +class FunctionType; + +namespace irgen { +class IRGenFunc; + +bool genFunc(IRGenFunc &IRGF, FuncStmt *F); + + +} // namespace irgen +} // namespace dusk + +#endif /* DUSK_IRGEN_GEN_FUNC_H */ diff --git a/lib/IRGen/GenModule.cpp b/lib/IRGen/GenModule.cpp new file mode 100644 index 0000000000000000000000000000000000000000..09af283d93c2cf4f4b891670c444a3afe76fe5b5 --- /dev/null +++ b/lib/IRGen/GenModule.cpp @@ -0,0 +1,93 @@ +//===--- GenModule.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 "GenModule.h" + +#include "dusk/AST/Decl.h" +#include "dusk/AST/Expr.h" +#include "dusk/AST/Stmt.h" +#include "dusk/AST/ASTWalker.h" + +#include "IRGenModule.h" +#include "IRGenFunc.h" +#include "GenFunc.h" + +using namespace dusk; +using namespace irgen; + +namespace { + +/// A simple AST walker, that declares all functions. +class FuncDeclarator: public ASTWalker { + IRGenModule &IRGM; + +public: + FuncDeclarator(IRGenModule &IRGM) : IRGM(IRGM) {} + + // Skip all global declarations except function and module declarations + virtual bool preWalk(Decl *D) override { + if (dynamic_cast<FuncDecl *>(D) != nullptr) + return true; + if (dynamic_cast<ModuleDecl *>(D) != nullptr) + return true; + return false; + } + + // Skip all expressions + virtual bool preWalk(Expr *E) override { return false; } + + virtual bool preWalk(Stmt *S) override { + // Skip all statements except function declarations + if (dynamic_cast<FuncStmt *>(S) != nullptr) + return true; + if (dynamic_cast<ExternStmt *>(S) != nullptr) + return true; + return false; + } + + // Actually declare given function + virtual bool postWalk(Decl *D) override { + auto Fn = static_cast<FuncDecl *>(D); + assert(IRGM.declareFunc(Fn) != nullptr && "Redefinition of a function"); + return true; + } +}; + +} // anonymous namespace + + +static void decalreFunctions(IRGenModule &IRGM) { + FuncDeclarator FD(IRGM); + for (auto N : IRGM.Context.getRootModule()->getContents()) + N->walk(FD); +} + +void irgen::genModule(IRGenModule &IRGM) { + decalreFunctions(IRGM); + + for (auto N : IRGM.Context.getRootModule()->getContents()) { + if (auto D = dynamic_cast<ValDecl *>(N)) { + if (IRGM.declareVal(D) == nullptr) + llvm_unreachable("Redefinition of a value"); + + } else if (auto Fn = dynamic_cast<FuncStmt *>(N)) { + IRGenFunc IRGF(IRGM, IRGM.Builder, + IRGM.getFunc(Fn->getPrototype()->getName()), Fn); + + if (!genFunc(IRGF, Fn)) + llvm_unreachable("Error generating a function."); + + } else if (auto Fn = dynamic_cast<ExternStmt *>(N)) { + continue; + + } else { + llvm_unreachable("Unexpected top-level statement"); + } + } +} diff --git a/lib/IRGen/GenModule.h b/lib/IRGen/GenModule.h new file mode 100644 index 0000000000000000000000000000000000000000..ba42b68e25e882dee77431537d194434a7da878c --- /dev/null +++ b/lib/IRGen/GenModule.h @@ -0,0 +1,22 @@ +//===--- GenModule.h - Dusk IR generation for module ------------*- C++ -*-===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#ifndef DUSK_IRGEN_GEN_MODULE_H +#define DUSK_IRGEN_GEN_MODULE_H + +namespace dusk { +namespace irgen { +class IRGenModule; + +void genModule(IRGenModule &IRGM); + +} // namesapce irgen +} // namespace dusk + +#endif /* DUSK_IRGEN_GEN_MODULE_H */ diff --git a/lib/IRGen/GenStmt.cpp b/lib/IRGen/GenStmt.cpp deleted file mode 100644 index 4b0170a1f1f8acbc1d0259aca3f81a3fb3c98bbe..0000000000000000000000000000000000000000 --- a/lib/IRGen/GenStmt.cpp +++ /dev/null @@ -1,153 +0,0 @@ -//===--- GenStmt.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 "GenStmt.h" -#include "GenDecl.h" -#include "GenExpr.h" - -using namespace dusk; -using namespace irgen; - -// MARK: - Break statement - -bool irgen::codegenStmt(Context &Ctx, Scope &Scp, BreakStmt *S) { - auto Ret = Ctx.getRange(Scp.getBreakParent()); - Ctx.Builder.CreateBr(Ret.End); - return true; -} - -// MARK: - Return statement - -bool irgen::codegenStmt(Context &Ctx, Scope &Scp, ReturnStmt *S) { - if (S->hasValue()) - Ctx.Builder.CreateRet(codegenExpr(Ctx, S->getValue())); - else - Ctx.Builder.CreateRetVoid(); - return true; -} - -// MARK: - Block statement - -bool irgen::codegenStmt(Context &Ctx, Scope &Scp, BlockStmt *S) { - for (auto N : S->getNodes()) { - if (auto D = dynamic_cast<Decl *>(N)) - if (!codegenDecl(Ctx, D)) - return false; - - if (auto E = dynamic_cast<Expr *>(N)) - if (codegenExpr(Ctx, E) == nullptr) - return false; - - if (auto S = dynamic_cast<Stmt *>(N)) - if (!codegenStmt(Ctx, Scp, S)) - return false; - } - return true; -} - -// MARK: - Func statement - -void genArgs(Context &Ctx, VarPattern *P, llvm::Function *F) { - for (auto Arg : P->getVars()) - 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) { - auto Scp_ = Scope(&Scp, Scope::FnScope); - auto F = Ctx.getFunc(S->getPrototype()->getName()); - auto Args = static_cast<FuncDecl *>(S->getPrototype())->getArgs(); - - // Create entry block for the function - auto BB = llvm::BasicBlock::Create(Ctx, "entry", F); - Ctx.Builder.SetInsertPoint(BB); - Ctx.push(); - genArgs(Ctx, Args, F); - codegenStmt(Ctx, Scp_, S->getBody()); - Ctx.pop(); - return true; -} - -// MARK: - If statement - -llvm::Value *condGen(Context &Ctx, Expr *E) { - auto CondV = codegenExpr(Ctx, E); - auto Zero = llvm::ConstantInt::get(llvm::Type::getInt64Ty(Ctx), 0); - return Ctx.Builder.CreateICmpNE(CondV, Zero, "cmpZero"); -} - -bool genBranch(Context &Ctx, Scope &Scp, llvm::BasicBlock *BB, Stmt *S) { - Ctx.Builder.SetInsertPoint(BB); - Ctx.push(); - codegenStmt(Ctx, Scp, S); - Ctx.pop(); - return true; -} - -bool irgen::codegenStmt(Context &Ctx, Scope &Scp, IfStmt *S) { - auto Scp_ = Scope(&Scp, Scope::ControlScope); - auto Cond = condGen(Ctx, S->getCond()); - auto F = Ctx.Builder.GetInsertBlock()->getParent(); - auto ThenBB = llvm::BasicBlock::Create(Ctx, "then", F); - auto ElseBB = llvm::BasicBlock::Create(Ctx, "else"); - auto MergeBB = llvm::BasicBlock::Create(Ctx, "endif"); - F->getBasicBlockList().push_back(ElseBB); - F->getBasicBlockList().push_back(MergeBB); - - 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; -} - -// MARK: - While statement - -bool irgen::codegenStmt(Context &Ctx, Scope &Scp, WhileStmt *S) { - return false; -} - -// MARK: - For statement - -bool irgen::codegenStmt(Context &Ctx, Scope &Scp, ForStmt *S) { - return false; -} - -// MARK: - Default statement - -bool irgen::codegenStmt(Context &Ctx, Scope &Scp, Stmt *S) { - switch (S->getKind()) { - case StmtKind::Break: - return codegenStmt(Ctx, Scp, static_cast<BreakStmt *>(S)); - case StmtKind::Return: - return codegenStmt(Ctx, Scp, static_cast<ReturnStmt *>(S)); - case StmtKind::Range: - return codegenStmt(Ctx, Scp, static_cast<RangeStmt *>(S)); - case StmtKind::Block: - return codegenStmt(Ctx, Scp, static_cast<BlockStmt *>(S)); - case StmtKind::Func: - return codegenStmt(Ctx, Scp, static_cast<FuncStmt *>(S)); - case StmtKind::For: - return codegenStmt(Ctx, Scp, static_cast<ForStmt *>(S)); - case StmtKind::While: - return codegenStmt(Ctx, Scp, static_cast<WhileStmt *>(S)); - case StmtKind::If: - return codegenStmt(Ctx, Scp, static_cast<IfStmt *>(S)); - case StmtKind::Extern: - return true; - case StmtKind::Subscript: - llvm_unreachable("Not implemented yet"); - } -} - diff --git a/lib/IRGen/GenStmt.h b/lib/IRGen/GenStmt.h deleted file mode 100644 index dcd07beb8256463d63c2231a49fba4ce6dae437c..0000000000000000000000000000000000000000 --- a/lib/IRGen/GenStmt.h +++ /dev/null @@ -1,43 +0,0 @@ -//===--- GenStmt.h - Dusk IR statement generation ---------------*- C++ -*-===// -// -// 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. -// -//===----------------------------------------------------------------------===// - -#ifndef DUSK_IRGEN_STMT_H -#define DUSK_IRGEN_STMT_H - -#include "dusk/AST/Decl.h" -#include "dusk/AST/Expr.h" -#include "dusk/AST/Stmt.h" -#include "dusk/AST/Pattern.h" -#include "dusk/IRGen/Context.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Value.h" -#include "llvm/IR/LLVMContext.h" - - -namespace dusk { - -namespace irgen { - -bool codegenStmt(Context &Ctx, Scope &Scp, Stmt *S); -bool codegenStmt(Context &Ctx, Scope &Scp, BreakStmt *S); -bool codegenStmt(Context &Ctx, Scope &Scp, ReturnStmt *S); -bool codegenStmt(Context &Ctx, Scope &Scp, BlockStmt *S); -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 - -} // namespace dusk - -#endif /* DUSK_IRGEN_STMT_H */ - diff --git a/lib/IRGen/IRGenFunc.cpp b/lib/IRGen/IRGenFunc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..feb43e9e3708ae170d4afffb8df853da49350914 --- /dev/null +++ b/lib/IRGen/IRGenFunc.cpp @@ -0,0 +1,103 @@ +//===--- IRGenFunc.h - IR generation state for functions --------*- C++ -*-===// +// +// 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 "IRGenFunc.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/NameLookup.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 <vector> + +using namespace dusk; +using namespace irgen; + +IRGenFunc::IRGenFunc(IRGenModule &IRGM, llvm::IRBuilder<> &B, + llvm::Function *F, FuncStmt *FN) + : IRGM(IRGM), Builder(B), Fn(F) { + + Proto = static_cast<FuncDecl *>(FN->getPrototype()); + HeaderBlock = + llvm::BasicBlock::Create(IRGM.LLVMContext, Fn->getName() + ".header", Fn); + BodyBlock = + llvm::BasicBlock::Create(IRGM.LLVMContext, Fn->getName() + ".body"); + RetBlock = llvm::BasicBlock::Create(IRGM.LLVMContext, Fn->getName() + ".ret"); + emitHeader(); + Fn->getBasicBlockList().push_back(BodyBlock); + Builder.SetInsertPoint(BodyBlock); +} + +IRGenFunc::~IRGenFunc() { + emitRet(); +} + +void IRGenFunc::emitHeader() { + IRGM.Lookup.push(); + Builder.SetInsertPoint(HeaderBlock); + // Create a return value if necessary + if (!Fn->getReturnType()->isVoidTy()) + RetValue = Builder.CreateAlloca(llvm::Type::getInt64Ty(IRGM.LLVMContext)); + + unsigned idx = 0; + auto Args = Proto->getArgs()->getVars(); + for (auto &Arg : Fn->args()) { + if (auto Addr = declare(Args[idx])) + Builder.CreateStore(&Arg, Addr); + else + llvm_unreachable("Redefinition of declaration"); + } + Builder.CreateBr(BodyBlock); +} + +void IRGenFunc::emitRet() { + for (auto &BB : Fn->getBasicBlockList()) { + if (BB.size() == 0) { + Builder.SetInsertPoint(&BB); + if (auto Succ = BB.getSingleSuccessor()) + Builder.CreateBr(Succ); + else + Builder.CreateBr(RetBlock); + } + } + + Fn->getBasicBlockList().push_back(RetBlock); + Builder.SetInsertPoint(RetBlock); + if (RetValue.isValid()) { + auto Val = Builder.CreateLoad(RetValue); + Builder.CreateRet(Val); + } else { + Builder.CreateRetVoid(); + } + IRGM.Lookup.pop(); +} + +void IRGenFunc::setRetVal(llvm::Value *V) { + Builder.CreateStore(V, RetValue); +} + +Address IRGenFunc::declare(Decl *N) { + return IRGM.declareVal(N); +} + +Address IRGenFunc::getVal(StringRef N) { + return IRGM.getVal(N); +} + +llvm::Function *IRGenFunc::getFunc(StringRef N) { + return IRGM.getFunc(N); +} diff --git a/lib/IRGen/IRGenFunc.h b/lib/IRGen/IRGenFunc.h new file mode 100644 index 0000000000000000000000000000000000000000..6382813a782ac778713fbe1d97829154210cd6e4 --- /dev/null +++ b/lib/IRGen/IRGenFunc.h @@ -0,0 +1,101 @@ +//===--- IRGenFunc.h - IR generation state for functions --------*- C++ -*-===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#ifndef DUSK_IRGEN_IRGEN_FUNC_H +#define DUSK_IRGEN_IRGEN_FUNC_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/IR/Value.h" +#include "llvm/IR/IRBuilder.h" + +#include "Address.h" +#include "IRGenModule.h" +#include "LoopInfo.h" + +#include <stack> + +namespace llvm { +class StringRef; +class Function; +class BasicBlock; +class Value; +} + +namespace dusk { +class Decl; +class FuncDecl; +class FuncStmt; + +namespace irgen { + +class IRGenFunc { +public: + /// Module which part is this function of. + IRGenModule &IRGM; + + /// Current IR builder + llvm::IRBuilder<> &Builder; + + /// Actual function. + llvm::Function *Fn; + + /// Function statement. + FuncDecl *Proto; + + /// Loop stack encapsulation. + LoopInfoStack LoopStack; + + IRGenFunc(IRGenModule &IRGM, llvm::IRBuilder<> &B, llvm::Function *Fn, + FuncStmt *F); + + ~IRGenFunc(); + + friend class Scope; +private: + /// A block, where all function initialization happen. E.g. parameter + /// allocation and initialization. + llvm::BasicBlock *HeaderBlock; + + /// Main function body block. + llvm::BasicBlock *BodyBlock; + + /// A common return block. + llvm::BasicBlock *RetBlock; + + /// A temporary alloca, that holds a return value. + /// + /// \node This address is invalid if the function does not return a value. + Address RetValue; + +public: + /// Returns function's header block + llvm::BasicBlock *getHeaderBlock() const { return HeaderBlock; } + /// Returns function's body block + llvm::BasicBlock *getBodyBlock() const { return BodyBlock; } + /// Returns function's return block + llvm::BasicBlock *getRetBlock() const { return RetBlock; } + + void setRetVal(llvm::Value *V); + Address declare(Decl *N); + Address getVal(StringRef N); + llvm::Function *getFunc(StringRef N); + +private: + /// Emits function header block. + void emitHeader(); + + /// Return function return block + void emitRet(); +}; + +} // namespace irgen +} // namespace dusk + +#endif /* DUSK_IRGEN_IRGEN_FUNC_H */ + diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8de023c9869f0d36bfb7ada69e0d3d7acb9949cd --- /dev/null +++ b/lib/IRGen/IRGenModule.cpp @@ -0,0 +1,80 @@ +//===--- IRGenModule.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 "IRGenModule.h" + +#include "dusk/AST/Decl.h" +#include "dusk/AST/Type.h" +#include "dusk/AST/ASTContext.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/ADT/DenseMap.h" +#include <vector> + +using namespace dusk; +using namespace irgen; + +IRGenModule::IRGenModule(ASTContext &Ctx, llvm::LLVMContext &LLVMCtx, + llvm::Module *M, llvm::IRBuilder<> &B) + : Context(Ctx), LLVMContext(LLVMCtx), Module(M), Builder(B) {} + +Address IRGenModule::declareVal(Decl *D) { + auto Ty = llvm::Type::getInt64Ty(LLVMContext); + + if (Lookup.getDepth() == 0) { + if (Module->getGlobalVariable(D->getName()) != nullptr) + llvm_unreachable("Redefinition of a variable"); + + return Module->getOrInsertGlobal(D->getName(), Ty); + } else { + Lookup.declareVar(D); + auto Addr = Builder.CreateAlloca(Ty); + Vals[D] = Addr; + return Addr; + } +} + +Address IRGenModule::declareFunc(FuncDecl *D) { + if (Lookup.contains(D->getName())) + llvm_unreachable("Redefinition of a function"); + + auto FnTy = static_cast<FunctionType *>(D->getType()); + auto Ty = llvm::Type::getInt64Ty(LLVMContext); + auto Args = std::vector<llvm::Type *>(D->getArgs()->count(), Ty); + + // Resolve return type + llvm::Type *RetTy; + switch (FnTy->getRetType()->getKind()) { + case TypeKind::Int: + RetTy = llvm::Type::getInt64Ty(LLVMContext); + break; + case TypeKind::Void: + RetTy = llvm::Type::getVoidTy(LLVMContext); + break; + default: + llvm_unreachable("Unsupported return type"); + } + auto Proto = llvm::FunctionType::get(RetTy, Args, false); + auto Fn = llvm::Function::Create(Proto, llvm::Function::ExternalLinkage, + D->getName(), Module); + Lookup.declareFunc(D); + return Fn; +} + +Address IRGenModule::getVal(StringRef N) { + if (auto Val = Vals[Lookup.getVal(N)]) + return Val; + return Module->getGlobalVariable(N); +} + +llvm::Function *IRGenModule::getFunc(StringRef N) { + return Module->getFunction(N); +} diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h new file mode 100644 index 0000000000000000000000000000000000000000..a11ec7ee71c565e07a12aacd704281e814ef637e --- /dev/null +++ b/lib/IRGen/IRGenModule.h @@ -0,0 +1,65 @@ +//===--- IRGenModule.h - Module generation state ----------------*- C++ -*-===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#ifndef DUSK_IRGEN_IRGEN_MODULE_H +#define DUSK_IRGEN_IRGEN_MODULE_H + +#include "dusk/Basic/LLVM.h" +#include "dusk/AST/NameLookup.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/IR/IRBuilder.h" + +#include "Address.h" + +namespace llvm { +class Constant; +class Module; +class Value; +class Function; +class LLVMContext; +class StringRef; +} + +namespace dusk { +class Decl; +class FuncDecl; +class ASTContext; + +namespace irgen { + +/// Main class for IR emittion of global declarations. +class IRGenModule { +public: + ASTContext &Context; + llvm::LLVMContext &LLVMContext; + llvm::Module *Module; + llvm::IRBuilder<> &Builder; + + NameLookup Lookup; + llvm::DenseMap<Decl *, Address> Vals; + + IRGenModule(ASTContext &Ctx, llvm::LLVMContext &LLVMCtx, llvm::Module *M, + llvm::IRBuilder<> &B); + + /// Declares a global variable + Address declareVal(Decl *D); + /// Decalres a fuction. + Address declareFunc(FuncDecl *D); + + /// Returns value of declared variable. + Address getVal(StringRef N); + /// Returns declared function. + llvm::Function *getFunc(StringRef N); +}; + +} // namespace irgen +} // namespace dusk + +#endif /* DUSK_IRGEN_IRGEN_MODULE_H */ + diff --git a/lib/IRGen/IRGenerator.cpp b/lib/IRGen/IRGenerator.cpp index cc4b0df84475ddcd681c55eb40753efbf0334356..b47c26b0040b806fa10e9a8bb6d9ee9df8b279d1 100644 --- a/lib/IRGen/IRGenerator.cpp +++ b/lib/IRGen/IRGenerator.cpp @@ -9,54 +9,27 @@ #include "dusk/AST/ASTVisitor.h" #include "dusk/AST/Scope.h" +#include "dusk/AST/NameLookup.h" #include "dusk/IRGen/IRGenerator.h" -#include "dusk/IRGen/Context.h" #include "llvm/IR/BasicBlock.h" -#include "GenDecl.h" #include "GenExpr.h" -#include "GenStmt.h" +#include "IRGenModule.h" +#include "GenModule.h" using namespace dusk; using namespace irgen; IRGenerator::IRGenerator(ASTContext &C, DiagnosticEngine &Diag) - : ASTCtx(C), Diag(Diag), Builder({Ctx}) {} + : Context(C), Diag(Diag), Builder({LLVMContext}) {} 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; - declareFuncs(Ctx, M); - for (auto &N : M->getContents()) { - bool R = true; - if (auto D = dynamic_cast<Decl *>(N)) - continue; - else if (auto E = dynamic_cast<Expr *>(N)) - R = codegenExpr(Ctx, E) != nullptr; - else if (auto S = dynamic_cast<Stmt *>(N)) - R = codegenStmt(Ctx, Scp, S); - else - llvm_unreachable("Unexpected node"); - - if (!R) - return nullptr; - } + auto M = Context.getRootModule(); + Module = std::make_unique<llvm::Module>(M->getName(), LLVMContext); + IRGenModule IRGM(Context, LLVMContext, Module.get(), Builder); + genModule(IRGM); return Module.release(); } - -bool IRGenerator::declareFuncs(Context &Ctx, ModuleDecl *M) { - for (auto N : M->getContents()) { - if (auto Fn = dynamic_cast<FuncStmt *>(N)) - if (!codegenDecl(Ctx, Fn->getPrototype())) - return false; - if (auto Fn = dynamic_cast<ExternStmt *>(N)) - if (!codegenDecl(Ctx, Fn->getPrototype())) - return false; - } - return true; -} diff --git a/lib/IRGen/LoopInfo.cpp b/lib/IRGen/LoopInfo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2df62cfb5df0aa358591e2bc80516d0d2d81c8c1 --- /dev/null +++ b/lib/IRGen/LoopInfo.cpp @@ -0,0 +1,38 @@ +//===---LoopInfo.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 "LoopInfo.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 "llvm/IR/Value.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/BasicBlock.h" + +using namespace dusk; +using namespace irgen; + +LoopInfo::LoopInfo() : Header(nullptr), EndBlock(nullptr) {} + +LoopInfo::LoopInfo(llvm::BasicBlock *H, llvm::BasicBlock *E) + : Header(H), EndBlock(E) { + assert(isValid() && "Constructing invalid loop info."); +} + +void LoopInfoStack::push(llvm::BasicBlock *H, llvm::BasicBlock *E) { + Active.emplace(H, E); +} + +void LoopInfoStack::pop() { + assert(Active.size() != 0 && "Cannot pop an empty stack."); + Active.pop(); +} diff --git a/lib/IRGen/LoopInfo.h b/lib/IRGen/LoopInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..ad2c9f836925d47840c3a77d676ce946a56e4451 --- /dev/null +++ b/lib/IRGen/LoopInfo.h @@ -0,0 +1,82 @@ +//===--- LoopInfo.h - Loop information encapsulation ------------*- C++ -*-===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#ifndef DUSK_IRGEN_GEN_CONTROL_H +#define DUSK_IRGEN_GEN_CONTROL_H + +#include <stack> + +namespace llvm { + class BasicBlock; +} + +namespace dusk { +class Stmt; +class IfStmt; +class ForStmt; +class WhileStmt; + +namespace irgen { +class Context; + +/// A simple class, than encapsulates information about generated loops. +class LoopInfo { + /// Loop header block used e.g. for condition and/or initial variable + /// allocations. + llvm::BasicBlock *Header; + + /// Loop end block, used e.g. when break statement is encountered. + llvm::BasicBlock *EndBlock; + +public: + /// Creates an invalid loop info. + LoopInfo(); + + /// Creates a valid loop info. + LoopInfo(llvm::BasicBlock *H, llvm::BasicBlock *E); + + /// Returns \c true if loop info is valid, \c false otherwise. + bool isValid() const { return Header != nullptr && EndBlock != nullptr; } + + /// Returns loop header block. + llvm::BasicBlock *getHeader() const { + assert(isValid() && "Accessing invalid loop info"); + return Header; + } + + /// Returns loops end block. + llvm::BasicBlock *getEndBlock() const { + assert(isValid() && "Accessing invalid loop info"); + return EndBlock; + } +}; + +/// Stack of loop information that are currently active. +class LoopInfoStack { + /// Active loop information. + std::stack<LoopInfo> Active; + +public: + LoopInfoStack() = default; + + /// Start a new loop. + void push(llvm::BasicBlock *H, llvm::BasicBlock *E); + + /// End the top loop. + void pop(); + + /// Returns informatin about top level loop. + const LoopInfo &getInfo() const { return Active.top(); } +}; + +} // namespace irgen +} // namesapce dusk + +#endif /* DUSK_IRGEN_GEN_CONTROL_H */ + diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 231e6e149310df27a6c09bd624d2d038f86cfe43..52ffd87b0d36699284dd06b2e332a0ed6afe62aa 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -1,5 +1,4 @@ set(SOURCE - ${CMAKE_CURRENT_SOURCE_DIR}/Context.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Sema.cpp ${CMAKE_CURRENT_SOURCE_DIR}/TypeChecker.h ${CMAKE_CURRENT_SOURCE_DIR}/TypeChecker.cpp diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 7b93672ab6d824538dd570936cc2816c35f6dcf3..46b62e6ca6faef9e58bc37dabcc3fee8acaf4e6e 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -16,6 +16,7 @@ #include "dusk/AST/Type.h" #include "dusk/AST/TypeRepr.h" #include "dusk/AST/Diagnostics.h" +#include "dusk/AST/NameLookup.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/SmallVector.h" @@ -28,11 +29,11 @@ namespace { class FwdDeclarator : public ASTWalker { Sema &S; - Context &Ctx; + NameLookup &Ctx; DiagnosticEngine &Diag; public: - FwdDeclarator(Sema &S, Context &C, DiagnosticEngine &D) + FwdDeclarator(Sema &S, NameLookup &C, DiagnosticEngine &D) : S(S), Ctx(C), Diag(D) {} virtual bool preWalk(Decl *D) override { diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index f96a16b56af263cd9eea2f709c8dbe9d99c90fbb..ada84599127d2ab92b87a1685271be02b65c7331 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -11,8 +11,8 @@ #include "dusk/AST/Diagnostics.h" #include "dusk/AST/Scope.h" +#include "dusk/AST/NameLookup.h" #include "dusk/Sema/Sema.h" -#include "dusk/Sema/Context.h" using namespace dusk; using namespace sema; diff --git a/lib/Sema/TypeCheckExpr.cpp b/lib/Sema/TypeCheckExpr.cpp index 4af883981b9772a80d9adfa5f1cd7675a44a656c..636d8a9424f120b95f38f98d0e46dac28bef12c0 100644 --- a/lib/Sema/TypeCheckExpr.cpp +++ b/lib/Sema/TypeCheckExpr.cpp @@ -10,7 +10,7 @@ #include "TypeChecker.h" #include "dusk/AST/Diagnostics.h" -#include "dusk/Sema/Context.h" +#include "dusk/AST/NameLookup.h" using namespace dusk; using namespace sema; diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index 31f153502348d24589ab4a21b8fd641922136cb1..d0a5a726cccecb669baf3ce82c79b8b52c9d8adf 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -11,8 +11,8 @@ #include "dusk/AST/Diagnostics.h" #include "dusk/AST/Scope.h" +#include "dusk/AST/NameLookup.h" #include "dusk/Sema/Sema.h" -#include "dusk/Sema/Context.h" #include "llvm/ADT/SmallVector.h" #include <memory> diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index d09737c3022d012b08d2b42ff45cef83a9924a26..37afedefdae43a6e971c9fa605244450369ebd99 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -11,7 +11,7 @@ #include "dusk/AST/Diagnostics.h" #include "dusk/AST/Scope.h" -#include "dusk/Sema/Context.h" +#include "dusk/AST/NameLookup.h" using namespace dusk; using namespace sema; diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp index c3505ca48b18ac65931c8ce98dcb824203ac8c8b..fdb4763df1310f270d77252b6e30b90ddf324b6a 100644 --- a/lib/Sema/TypeChecker.cpp +++ b/lib/Sema/TypeChecker.cpp @@ -11,13 +11,13 @@ #include "dusk/AST/Diagnostics.h" #include "dusk/AST/Scope.h" +#include "dusk/AST/NameLookup.h" #include "dusk/Sema/Sema.h" -#include "dusk/Sema/Context.h" using namespace dusk; using namespace sema; -TypeChecker::TypeChecker(Sema &S, Context &C, ASTContext &Ctx, +TypeChecker::TypeChecker(Sema &S, NameLookup &C, ASTContext &Ctx, DiagnosticEngine &D) : S(S), DeclCtx(C), Ctx(Ctx), Diag(D) { Scp.push(Scope()); diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index fd556e5e33796039444d8f60675b74e527b6567e..461d8def9eae021251538a3302fe41a2a4843fa3 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -24,14 +24,14 @@ class Type; class TypeRepr; class DiagnosticEngine; class Scope; - +class NameLookup; + namespace diag { enum DiagID : unsigned; } namespace sema { class Sema; -class Context; /// Dusk language type checker. /// @@ -39,13 +39,13 @@ class Context; /// while validating them. class TypeChecker : public ASTWalker { Sema &S; - Context &DeclCtx; + NameLookup &DeclCtx; ASTContext &Ctx; std::stack<Scope> Scp; DiagnosticEngine &Diag; public: - TypeChecker(Sema &S, Context &DC, ASTContext &Ctx, DiagnosticEngine &Diag); + TypeChecker(Sema &S, NameLookup &DC, ASTContext &Ctx, DiagnosticEngine &Diag); virtual bool preWalk(Decl *D) override; virtual bool postWalk(Decl *D) override; diff --git a/test.cpp b/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b28d983623a6b4fd63a8af654e1830150e01a7fb --- /dev/null +++ b/test.cpp @@ -0,0 +1,30 @@ +#include <iostream> + +extern "C" { + int64_t inc(int64_t); + void isEven(int64_t); +} + +#ifdef _WIN32 +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT +#endif + +/// printd - printf that takes an integer prints it as "%lld\n", returning Void. +extern "C" DLLEXPORT void println(int64_t X) { + std::cout << "being called externally " << X << std::endl; +// fprintf(stderr, "%lld\n", X); + return; +} + +int main() { + int64_t i = 10000; + int64_t j = 5; + // std::cout << i << " " << inc(i) << std::endl; + // isEven(i); + isEven(j); + // std::cout << i << " is even "; isEven(i); std::cout << std::endl; + // std::cout << j << " is even "; isEven(j); std::cout << std::endl; + return 0; +}