summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNagi5Yeq <wu@x-nagi.com>2020-05-25 16:14:41 +0800
committerNagi5Yeq <wu@x-nagi.com>2020-05-25 16:14:41 +0800
commit958a811b18aee04e4795cf003fd8e3db00312c91 (patch)
tree92cbc52f7560af0e08febfe1da38ed657ad29735
parentc5e9f890dab0e4595482301d77876793c8bceb8c (diff)
finish function calls and lvalue
-rw-r--r--Context.cc15
-rw-r--r--Context.hh4
-rw-r--r--Parser.y42
-rw-r--r--Type.cc22
-rw-r--r--Type.hh14
-rw-r--r--TypeManager.cc47
-rw-r--r--TypeManager.hh7
-rw-r--r--Version.cc2
-rw-r--r--node/BaseNode.hh5
-rw-r--r--node/ExprNode.cc60
-rw-r--r--node/ExprNode.hh42
-rw-r--r--node/FunctionNode.cc17
-rw-r--r--node/StatementNode.cc21
-rw-r--r--node/StatementNode.hh18
14 files changed, 284 insertions, 32 deletions
diff --git a/Context.cc b/Context.cc
index d009835..97d6ffb 100644
--- a/Context.cc
+++ b/Context.cc
@@ -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
diff --git a/Context.hh b/Context.hh
index 9a30721..6d11db1 100644
--- a/Context.hh
+++ b/Context.hh
@@ -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;
diff --git a/Parser.y b/Parser.y
index c322dd3..74827ba 100644
--- a/Parser.y
+++ b/Parser.y
@@ -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
;
diff --git a/Type.cc b/Type.cc
index aa13f38..a661fde 100644
--- a/Type.cc
+++ b/Type.cc
@@ -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
diff --git a/Type.hh b/Type.hh
index 4413058..ebda567 100644
--- a/Type.hh
+++ b/Type.hh
@@ -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_;
diff --git a/Version.cc b/Version.cc
index 2a58401..7ccbf4b 100644
--- a/Version.cc
+++ b/Version.cc
@@ -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