diff options
| author | Nagi5Yeq <wu@x-nagi.com> | 2020-05-25 16:14:41 +0800 |
|---|---|---|
| committer | Nagi5Yeq <wu@x-nagi.com> | 2020-05-25 16:14:41 +0800 |
| commit | 958a811b18aee04e4795cf003fd8e3db00312c91 (patch) | |
| tree | 92cbc52f7560af0e08febfe1da38ed657ad29735 | |
| parent | c5e9f890dab0e4595482301d77876793c8bceb8c (diff) | |
finish function calls and lvalue
| -rw-r--r-- | Context.cc | 15 | ||||
| -rw-r--r-- | Context.hh | 4 | ||||
| -rw-r--r-- | Parser.y | 42 | ||||
| -rw-r--r-- | Type.cc | 22 | ||||
| -rw-r--r-- | Type.hh | 14 | ||||
| -rw-r--r-- | TypeManager.cc | 47 | ||||
| -rw-r--r-- | TypeManager.hh | 7 | ||||
| -rw-r--r-- | Version.cc | 2 | ||||
| -rw-r--r-- | node/BaseNode.hh | 5 | ||||
| -rw-r--r-- | node/ExprNode.cc | 60 | ||||
| -rw-r--r-- | node/ExprNode.hh | 42 | ||||
| -rw-r--r-- | node/FunctionNode.cc | 17 | ||||
| -rw-r--r-- | node/StatementNode.cc | 21 | ||||
| -rw-r--r-- | node/StatementNode.hh | 18 |
14 files changed, 284 insertions, 32 deletions
@@ -1,6 +1,7 @@ #include <llvm/IR/LLVMContext.h> #include "Context.hh" +#include "Log.hh" namespace pcc { // llvm needs a LLVMContext for every thread, but we only have one thread, so we @@ -26,4 +27,18 @@ VariableList* Context::GetCurrentScope() { return scopes_.top(); } void Context::PushScope(VariableList* scope) { scopes_.push(scope); } void Context::PopScope() { scopes_.pop(); } + +std::shared_ptr<FunctionType> Context::GetFunctionType(std::string name) { + decltype(FuncTypes_)::iterator result = FuncTypes_.find(name); + if (result == FuncTypes_.end()) { + return nullptr; + } + return std::get<1>(*result); +} + +void Context::AddFunctionType(std::string name, + std::shared_ptr<FunctionType> type) { + FuncTypes_.insert({name, type}); +} + } // namespace pcc @@ -2,6 +2,7 @@ #define PCC_CONTEXT_H #include <stack> +#include <unordered_map> #include <llvm/IR/IRBuilder.h> #include <llvm/IR/Module.h> @@ -20,6 +21,8 @@ class Context { VariableList* GetCurrentScope(); void PushScope(VariableList* scope); void PopScope(); + std::shared_ptr<FunctionType> GetFunctionType(std::string name); + void AddFunctionType(std::string name, std::shared_ptr<FunctionType> type); private: TypeManager TypeManager_; @@ -27,6 +30,7 @@ class Context { std::stack<VariableList*> scopes_; llvm::IRBuilder<> builder_; llvm::Module module_; + std::unordered_map<std::string, std::shared_ptr<FunctionType>> FuncTypes_; }; extern llvm::LLVMContext GlobalLLVMContext; @@ -53,18 +53,20 @@ YY_DECL; %type <std::shared_ptr<pcc::IntegerLiteralNode>> INTEGER_LITERAL %type <std::shared_ptr<pcc::RealLiteralNode>> REAL_LITERAL %type <std::shared_ptr<pcc::StringLiteralNode>> STRING_LITERAL -%type <std::shared_ptr<pcc::ExprNode>> literal - +%type <std::shared_ptr<pcc::ExprNode>> literal lvalue %type <std::shared_ptr<pcc::ExprNode>> expression l1_expression l2_expression l3_expression %type <pcc::BinaryOperator> l1_operator l2_operator l3_operator %type <pcc::UnaryOperator> l4_operator -%type <std::shared_ptr<pcc::StatementListNode>> statements statement_block - %type <std::shared_ptr<pcc::FunctionNode>> function %type <std::list<std::shared_ptr<pcc::BaseNode>>> local_decls %type <std::shared_ptr<pcc::BaseNode>> local_decl +%type <std::shared_ptr<pcc::StatementListNode>> statements statement_block +%type <std::shared_ptr<pcc::BaseNode>> statement open_statement closed_statement normal_statement +%type <std::shared_ptr<pcc::EmptyStatementNode>> empty_statement +%type <std::shared_ptr<pcc::AssignStatementNode>> assign_statement + %% /* ==================[global part]================== */ @@ -119,7 +121,7 @@ type function : FUNCTION IDENTIFIER LPARENTHESIS var_decls RPARENTHESIS COLON type SEMICOLON - local_decls statement_block + local_decls statement_block {$$=std::make_shared<pcc::FunctionNode>(ctx, $2, $4, $9, $7, $10);} ; local_decls @@ -134,13 +136,13 @@ local_decl /* ==================[statements part]================== */ statements - : statements SEMICOLON statement - | statement + : statements SEMICOLON statement {$$=$1; $$->Append($3);} + | statement {$$=std::make_shared<pcc::StatementListNode>(ctx); $$->Append($1);} ; statement - : open_statement - | closed_statement + : open_statement {$$=$1;} + | closed_statement {$$=$1;} ; open_statement @@ -150,28 +152,28 @@ open_statement ; closed_statement - : normal_statement + : normal_statement {$$=$1;} | IF expression THEN closed_statement ELSE closed_statement | WHILE expression DO closed_statement ; normal_statement - : statement_block - | empty_statement - | assign_statement - | expression + : statement_block {$$=$1;} + | empty_statement {$$=$1;} + | assign_statement {$$=$1;} + | expression {$$=$1;} ; statement_block - : BEGINS statements ENDS + : BEGINS statements ENDS {$$=$2;} ; empty_statement - : + : {$$=std::make_shared<pcc::EmptyStatementNode>(ctx);} ; assign_statement - : lvalue ASSIGN expression + : lvalue ASSIGN expression {$$=std::make_shared<pcc::AssignStatementNode>(ctx, $1, $3);} ; /* ==================[expression part]================== */ @@ -192,7 +194,7 @@ l2_expression ; l3_expression - : lvalue + : lvalue {$$=std::make_shared<pcc::L2RCastingNode>(ctx, $1);} | function_call | literal {$$=$1;} | LPARENTHESIS expression RPARENTHESIS {$$=$2;} @@ -229,8 +231,8 @@ l4_operator ; lvalue - : IDENTIFIER - | IDENTIFIER LBRACKET expression RBRACKET + : IDENTIFIER {$$=std::make_shared<pcc::IdentifierNode>(ctx, $1);} + | IDENTIFIER LBRACKET expression RBRACKET {$$=std::make_shared<pcc::BinaryExprNode>(ctx, pcc::BinaryOperator::ARRAY_ACCESS, std::make_shared<pcc::IdentifierNode>(ctx, $1), $3);} | IDENTIFIER DOT IDENTIFIER ; @@ -290,7 +290,6 @@ Value ArrayType::CreateArrayAccess(Value v0, Value v1, Context* context) { return context->GetBuilder()->CreateInBoundsGEP(LLVMType_, v0, indices); } -// we use LLVM i8* type to represent void* PointerType::PointerType(std::shared_ptr<Type> ElementType, std::shared_ptr<Type> DifferenceType, std::shared_ptr<Type> IndexType, std::string&& name) @@ -332,4 +331,25 @@ Value PointerType::CreatePointerSub(Value v0, Value v1, Context* context) { Value PointerType::CreateArrayAccess(Value v0, Value v1, Context* context) { return context->GetBuilder()->CreateInBoundsGEP(LLVMType_, v0, v1); } + +FunctionType::FunctionType(std::shared_ptr<Type> ReturnType, + std::vector<std::shared_ptr<Type>> ArgTypes, + std::string&& name) + : Type(std::move(name), nullptr) + , ReturnType_(ReturnType) + , ArgTypes_(ArgTypes) { + std::vector<llvm::Type*> params(ArgTypes_.size()); + std::transform(ArgTypes_.cbegin(), ArgTypes_.cend(), params.begin(), + [](const Declaration& decl) { + return std::get<1>(decl)->GetLLVMType(); + }); + LLVMType_ = + llvm::FunctionType::get(ReturnType_->GetLLVMType(), params, false); +} + +std::shared_ptr<Type> FunctionType::GetReturnType() { return ReturnType_; } + +std::vector<std::shared_ptr<Type>> FunctionType::GetArgTypes() { + return ArgTypes_; +} } // namespace pcc @@ -3,6 +3,7 @@ #include <memory> #include <string> +#include <vector> #include <llvm/IR/IRBuilder.h> #include <llvm/IR/Module.h> @@ -174,6 +175,19 @@ class PointerType : public Type { std::shared_ptr<Type> DifferenceType_; std::shared_ptr<Type> IndexType_; }; + +class FunctionType : public Type { + public: + FunctionType(std::shared_ptr<Type> ReturnType, + std::vector<std::shared_ptr<Type>> ArgTypes, + std::string&& name); + std::shared_ptr<Type> GetReturnType(); + std::vector<std::shared_ptr<Type>> GetArgTypes(); + + protected: + std::shared_ptr<Type> ReturnType_; + std::vector<std::shared_ptr<Type>> ArgTypes_; +}; } // namespace pcc #endif // PCC_TYPE_H diff --git a/TypeManager.cc b/TypeManager.cc index d3599bd..7481032 100644 --- a/TypeManager.cc +++ b/TypeManager.cc @@ -147,4 +147,51 @@ Value TypeManager::CreateOperation(UnaryOperator op, std::shared_ptr<Type> type, } return result; } + +Value TypeManager::CreateCast(std::shared_ptr<Type> DstType, + std::shared_ptr<Type> SrcType, Value v, + Context* context) { + if (DstType == SrcType) { + return v; + } + llvm::IRBuilder<>* builder = context->GetBuilder(); + // we can only cast between integer and real + std::shared_ptr<IntegerBaseType> DstIntegerBaseType = + std::dynamic_pointer_cast<IntegerBaseType>(DstType); + std::shared_ptr<IntegerBaseType> SrcIntegerBaseType = + std::dynamic_pointer_cast<IntegerBaseType>(SrcType); + std::shared_ptr<RealType> DstRealType = + std::dynamic_pointer_cast<RealType>(DstType); + std::shared_ptr<RealType> SrcRealType = + std::dynamic_pointer_cast<RealType>(SrcType); + if (SrcRealType != nullptr && DstIntegerBaseType != nullptr) { + return builder->CreateFPToSI(v, DstType->GetLLVMType()); + } else if (SrcIntegerBaseType != nullptr) { + if (DstRealType != nullptr) { + return builder->CreateSIToFP(v, DstType->GetLLVMType()); + } else if (DstIntegerBaseType != nullptr) { + return builder->CreateSExtOrTrunc(v, DstType->GetLLVMType()); + } + } + Log(LogLevel::PCC_ERROR, "unsupported type casting from %s to %s", + SrcType->GetCommonName(), DstType->GetCommonName()); + return nullptr; +} + +std::shared_ptr<FunctionType> TypeManager::CreateFunctionType( + std::shared_ptr<Type> ReturnType, + std::vector<std::shared_ptr<Type>> ArgTypes) { + decltype(ArgTypes)::const_iterator ArgIt = ArgTypes.cbegin(); + std::string name = " (*)("; + if (!ArgTypes.empty()) { + name.append((*ArgIt)->GetCommonName()); + for (++ArgIt; ArgIt != ArgTypes.cend(); ++ArgIt) { + name.append(", "); + name.append((*ArgIt)->GetCommonName()); + } + } + types_.push_back(std::make_shared<FunctionType>( + ReturnType, ArgTypes, ReturnType->GetCommonName() + name + ")")); +} + } // namespace pcc diff --git a/TypeManager.hh b/TypeManager.hh index 35a5d78..9cfed8c 100644 --- a/TypeManager.hh +++ b/TypeManager.hh @@ -26,6 +26,13 @@ class TypeManager { Value CreateOperation(UnaryOperator op, std::shared_ptr<Type> type, Value v, Context* context); + Value CreateCast(std::shared_ptr<Type> DstType, + std::shared_ptr<Type> SrcType, Value v, Context* context); + + std::shared_ptr<FunctionType> + CreateFunctionType(std::shared_ptr<Type> ReturnType, + std::vector<std::shared_ptr<Type>> ArgTypes); + private: std::vector<std::shared_ptr<Type>> builtins_; std::vector<std::shared_ptr<Type>> types_; @@ -17,7 +17,7 @@ PCC_NORETURN void ShowVersion() { "Configurations:\n" " LLVM Version: " LLVM_VERSION_STRING "\n" " Host Platform: " PCC_OSNAME "\n" - " Defaule Target: " LLVM_DEFAULT_TARGET_TRIPLE "\n" + " Default Target: " LLVM_DEFAULT_TARGET_TRIPLE "\n" " Built on: " __DATE__ " " __TIME__ << std::endl; std::exit(0); diff --git a/node/BaseNode.hh b/node/BaseNode.hh index bec9ebd..16ee82d 100644 --- a/node/BaseNode.hh +++ b/node/BaseNode.hh @@ -1,7 +1,7 @@ #ifndef PCC_BASENODE_H #define PCC_BASENODE_H -#include <vector> +#include <list> #include "Context.hh" @@ -19,10 +19,11 @@ template <typename T, class Base = BaseNode> class ListNode : public Base { public: ListNode(Context* context) : Base(context) {} + void Append(T child) { childs_.push_back(child); } virtual Value CodeGen(); private: - std::vector<T> childs_; + std::list<T> childs_; }; } // namespace pcc diff --git a/node/ExprNode.cc b/node/ExprNode.cc index 8034fb8..e7ef2aa 100644 --- a/node/ExprNode.cc +++ b/node/ExprNode.cc @@ -1,3 +1,5 @@ +#include <vector> + #include "ExprNode.hh" #include "Log.hh" #include "TypeManager.hh" @@ -51,4 +53,62 @@ Value UnaryExprNode::CodeGen() { } return result; } + +L2RCastingNode::L2RCastingNode(Context* context, + std::shared_ptr<ExprNode> lvalue) + : ExprNode(context) + , lvalue_(lvalue) {} + +Value L2RCastingNode::CodeGen() { + Value left = lvalue_->CodeGen(); + type_ = lvalue_->GetType(); + return context_->GetBuilder()->CreateLoad(type_->GetLLVMType(), left); +} + +IdentifierNode::IdentifierNode(Context* context, const std::string& name) + : ExprNode(context) + , name_(name) {} + +Value IdentifierNode::CodeGen() { + Variable var = context_->GetCurrentScope()->Find(name_); + type_ = std::get<0>(var); + return std::get<1>(var); +} + +FunctionCallNode::FunctionCallNode(Context* context, const std::string& name, + std::list<std::shared_ptr<ExprNode>> args) + : ExprNode(context) + , name_(name) + , args_(args) {} + +Value FunctionCallNode::CodeGen() { + TypeManager* manager = context_->GetTypeManager(); + std::shared_ptr<FunctionType> type = context_->GetFunctionType(name_); + if (type == nullptr) { + Log(LogLevel::PCC_ERROR, "call to undefined function %s", + name_.c_str()); + return nullptr; + } + llvm::FunctionCallee fp = + context_->GetModule()->getOrInsertFunction(name_, type->GetLLVMType()); + const std::vector<std::shared_ptr<Type>>& ArgTypes = type->GetArgTypes(); + std::vector<Value> ArgValues(args_.size()); + auto ArgTypeIt = ArgTypes.begin(); + auto ArgValueIt = ArgValues.begin(); + for (auto arg : args_) { + Value argv = arg->CodeGen(); + Value ConvertedArgv = + manager->CreateCast(*ArgTypeIt, arg->GetType(), argv, context_); + if (ConvertedArgv == nullptr) { + Log(LogLevel ::PCC_ERROR, + "argument type mismatch, the function type is %s, an argument " + "of type %s needed", + type->GetCommonName(), (*ArgTypeIt)->GetCommonName()); + } + *ArgValueIt = ConvertedArgv; + ++ArgTypeIt, ++ArgValueIt; + } + type_ = type->GetReturnType(); + return context_->GetBuilder()->CreateCall(fp, ArgValues); +} } // namespace pcc diff --git a/node/ExprNode.hh b/node/ExprNode.hh index ac62975..c80d955 100644 --- a/node/ExprNode.hh +++ b/node/ExprNode.hh @@ -1,6 +1,8 @@ #ifndef PCC_EXPRNODE_H #define PCC_EXPRNODE_H +#include <list> + #include "BaseNode.hh" #include "Type.hh" @@ -38,6 +40,46 @@ class UnaryExprNode : public ExprNode { std::shared_ptr<ExprNode> value_; }; +// when accessing lvalues, we need an extra load instruction to actually load +// the value from the pointer, this is like clang's 'LValueToRValue' node below. +// c++: int x=7; int y=x; +// `-CompoundStmt 0xd28720 <col:9, line:9:1> +// |-DeclStmt 0xd28638 <line:7:2, col:9> +// | `-VarDecl 0xd285b0 <col:2, col:8> col:6 used x 'int' cinit +// | `-IntegerLiteral 0xd28618 <col:8> 'int' 7 +// `-DeclStmt 0xd28708 <line:8:2, col:9> +// `-VarDecl 0xd28668 <col:2, col:8> col:6 y 'int' cinit +// `-ImplicitCastExpr 0xd286f0 <col:8> 'int' <LValueToRValue> +// `-DeclRefExpr 0xd286d0 <col:8> 'int' lvalue Var 0xd285b0 'x' 'int' +class L2RCastingNode : public ExprNode { + public: + L2RCastingNode(Context* context, std::shared_ptr<ExprNode> lvalue); + virtual Value CodeGen() override; + + protected: + std::shared_ptr<ExprNode> lvalue_; +}; + +class IdentifierNode : public ExprNode { + public: + IdentifierNode(Context* context, const std::string& name); + virtual Value CodeGen() override; + + protected: + std::string name_; +}; + +class FunctionCallNode : public ExprNode { + public: + FunctionCallNode(Context* context, const std::string& name, + std::list<std::shared_ptr<ExprNode>> args); + virtual Value CodeGen() override; + + protected: + std::string name_; + std::list<std::shared_ptr<ExprNode>> args_; +}; + } // namespace pcc #endif // !PCC_EXPRNODE_H diff --git a/node/FunctionNode.cc b/node/FunctionNode.cc index 3346db0..dfb7eff 100644 --- a/node/FunctionNode.cc +++ b/node/FunctionNode.cc @@ -31,15 +31,16 @@ FunctionNode::FunctionNode( Value FunctionNode::CodeGen() { llvm::Module* module = context_->GetModule(); llvm::IRBuilder<>* builder = context_->GetBuilder(); - std::vector<llvm::Type*> params(arguments_.size()); + std::vector<std::shared_ptr<Type>> params(arguments_.size()); std::transform(arguments_.cbegin(), arguments_.cend(), params.begin(), - [](const Declaration& decl) { - return std::get<1>(decl)->GetLLVMType(); - }); - llvm::Type* type = - llvm::FunctionType::get(type_->GetLLVMType(), params, false); - llvm::FunctionCallee f = module->getOrInsertFunction(name_, type); - llvm::Function* function = llvm::cast<llvm::Function>(f.getCallee()); + [](const Declaration& decl) { return std::get<1>(decl); }); + std::shared_ptr<Type> type = + context_->GetTypeManager()->CreateFunctionType(type_, params); + context_->AddFunctionType(name_, type); + llvm::FunctionType* LLVMType = + llvm::cast<llvm::FunctionType>(type->GetLLVMType()); + llvm::Function* function = llvm::Function::Create( + LLVMType, llvm::GlobalValue::ExternalLinkage, name_, *module); function->setCallingConv(llvm::CallingConv::C); llvm::BasicBlock* block = llvm::BasicBlock::Create(GlobalLLVMContext, name_, function); diff --git a/node/StatementNode.cc b/node/StatementNode.cc index b373b70..fd8ee94 100644 --- a/node/StatementNode.cc +++ b/node/StatementNode.cc @@ -8,4 +8,25 @@ template <> Value StatementListNode::CodeGen() { } return result; } + +EmptyStatementNode::EmptyStatementNode(Context* context) + : BaseNode(context) {} + +Value EmptyStatementNode::CodeGen() { return nullptr; } + +AssignStatementNode::AssignStatementNode(Context* context, + std::shared_ptr<ExprNode> lhs, + std::shared_ptr<ExprNode> rhs) + : BaseNode(context) + , lhs_(lhs) + , rhs_(rhs) {} + +Value AssignStatementNode::CodeGen() { + Value LeftValue = lhs_->CodeGen(); + Value RightValue = rhs_->CodeGen(); + RightValue = context_->GetTypeManager()->CreateCast( + lhs_->GetType(), rhs_->GetType(), RightValue, context_); + context_->GetBuilder()->CreateStore(RightValue, LeftValue); + return nullptr; +} } // namespace pcc diff --git a/node/StatementNode.hh b/node/StatementNode.hh index 595298b..68c808f 100644 --- a/node/StatementNode.hh +++ b/node/StatementNode.hh @@ -4,9 +4,27 @@ #include <memory> #include "BaseNode.hh" +#include "ExprNode.hh" namespace pcc { using StatementListNode = ListNode<std::shared_ptr<BaseNode>>; + +class EmptyStatementNode : public BaseNode { + public: + EmptyStatementNode(Context* context); + virtual Value CodeGen() override; +}; + +class AssignStatementNode : public BaseNode { + public: + AssignStatementNode(Context* context, std::shared_ptr<ExprNode> lhs, + std::shared_ptr<ExprNode> rhs); + virtual Value CodeGen() override; + + protected: + std::shared_ptr<ExprNode> lhs_; + std::shared_ptr<ExprNode> rhs_; +}; } // namespace pcc #endif |
