diff options
| author | Nagi5Yeq <wu@x-nagi.com> | 2020-05-30 12:10:38 +0800 |
|---|---|---|
| committer | Nagi5Yeq <wu@x-nagi.com> | 2020-05-30 12:10:38 +0800 |
| commit | 4c9d2d541c90968db2065260dc94c3be9e8adef9 (patch) | |
| tree | d9c67d89bb7709bd76ea4809101efbd55dd1a9b0 | |
| parent | 63d2a1c552b0d190a0131c2db2045d154b9ec138 (diff) | |
use llvm::Function* to call a function for backward compatibility
| -rw-r--r-- | Context.cc | 13 | ||||
| -rw-r--r-- | Context.hh | 8 | ||||
| -rw-r--r-- | Lexer.l | 5 | ||||
| -rw-r--r-- | Parser.y | 11 | ||||
| -rw-r--r-- | Type.cc | 24 | ||||
| -rw-r--r-- | Type.hh | 5 | ||||
| -rw-r--r-- | TypeManager.cc | 30 | ||||
| -rw-r--r-- | TypeManager.hh | 11 | ||||
| -rw-r--r-- | node/ExprNode.cc | 7 | ||||
| -rw-r--r-- | node/FunctionNode.cc | 16 | ||||
| -rw-r--r-- | node/FunctionNode.hh | 4 | ||||
| -rw-r--r-- | t/trivial.pas | 18 |
12 files changed, 113 insertions, 39 deletions
@@ -29,17 +29,16 @@ 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; +Function Context::FindFunction(std::string name) { + decltype(Functions_)::iterator result = Functions_.find(name); + if (result == Functions_.end()) { + return {nullptr, nullptr}; } return std::get<1>(*result); } -void Context::AddFunctionType(std::string name, - std::shared_ptr<FunctionType> type) { - FuncTypes_.insert({name, type}); +void Context ::AddFunction(std::string name, Function func) { + Functions_.emplace(name, func); } void Context::PushBreakDestination(llvm::BasicBlock* dest) { @@ -11,6 +11,8 @@ #include "VariableList.hh" namespace pcc { +using Function = std::pair<std::shared_ptr<FunctionType>, llvm::Function*>; + class Context { public: Context(const char* name); @@ -21,8 +23,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); + Function FindFunction(std::string name); + void AddFunction(std::string name, Function func); // every time we enter a while, repeat or for statement, we push the // destination of break and continue. @@ -41,7 +43,7 @@ class Context { TypeManager TypeManager_; VariableList globals_; std::stack<VariableList*> scopes_; - std::unordered_map<std::string, std::shared_ptr<FunctionType>> FuncTypes_; + std::unordered_map<std::string, Function> Functions_; std::stack<llvm::BasicBlock*> BreakDestinations_; std::stack<llvm::BasicBlock*> ContinueDestinations_; // if statments always link then and else block with the endif block, it @@ -33,7 +33,7 @@ hexadecimal 0[xX][0-9a-fA-F] integer {decimal}|{octal}|{hexadecimal} real_exp [0-9]*(\.[0-9]*)?[eE]{decimal} -real_noexp [0-9]*\.[0-9]* +real_noexp [0-9]*\.[0-9]+ real {real_exp}|{real_noexp} @@ -64,6 +64,7 @@ white [\t\f\r ] ":=" {return Parser::make_ASSIGN(loc);} ":" {return Parser::make_COLON(loc);} ";" {return Parser::make_SEMICOLON(loc);} +".." {return Parser::make_DOTDOT(loc);} "." {return Parser::make_DOT(loc);} "," {return Parser::make_COMMA(loc);} "[" {return Parser::make_LBRACKET(loc);} @@ -116,6 +117,8 @@ white [\t\f\r ] "integer" {return Parser::make_INTEGER(loc);} "real" {return Parser::make_REAL(loc);} "string" {return Parser::make_STRING(loc);} +"array" {return Parser::make_ARRAY(loc);} +"of" {return Parser::make_OF(loc);} "true" {return Parser::make_BOOLEAN_LITERAL(true, loc);} "false" {return Parser::make_BOOLEAN_LITERAL(false, loc);} @@ -41,16 +41,16 @@ YY_DECL; %define parse.assert %token FILE_END 0; -%token COLON SEMICOLON COMMA DOT ASSIGN LBRACKET RBRACKET LPARENTHESIS RPARENTHESIS +%token COLON SEMICOLON COMMA DOTDOT DOT ASSIGN LBRACKET RBRACKET LPARENTHESIS RPARENTHESIS %token PROGRAM IDENTIFIER CONST VAR BEGINS ENDS FUNCTION %token IF THEN ELSE WHILE DO REPEAT UNTIL BREAK CONTINUE -%token VOID BOOLEAN CHAR INTEGER REAL STRING +%token VOID BOOLEAN CHAR INTEGER REAL STRING ARRAY OF %token ADD SUB MUL REAL_DIV DIV MOD LT LE GT GE EQ NE CARET AT %token AND NOT OR XOR SHL SHR %token INTEGER_LITERAL REAL_LITERAL STRING_LITERAL BOOLEAN_LITERAL CHAR_LITERAL %type <std::string> IDENTIFIER program_header -%type <std::shared_ptr<pcc::Type>> type +%type <std::shared_ptr<pcc::Type>> type array_type %type <std::list<Declaration>> var_decls %type <std::pair<std::list<std::string>, std::shared_ptr<pcc::Type>>> var_decl %type <std::list<std::string>> vars @@ -149,6 +149,11 @@ type | REAL {$$=ctx->GetTypeManager()->GetBuiltinType(pcc::BuiltinType::REAL);} | STRING {$$=ctx->GetTypeManager()->GetBuiltinType(pcc::BuiltinType::STRING);} | CARET type {$$=ctx->GetTypeManager()->GetPointerType($2);} + | array_type {$$=$1;} + ; + +array_type + : ARRAY LBRACKET literal DOTDOT literal RBRACKET OF type {$$=ctx->GetTypeManager()->CreateArrayType($8, $3, $5);} ; /* ==================[function part]================== */ @@ -276,15 +276,16 @@ Value RealType::CreateUnaryOperation(UnaryOperator op, Value v, return (this->*operations[ToUnderlying(op)])(v, context); } -ArrayType::ArrayType(std::shared_ptr<Type> ElementType, int ElementNumber, +ArrayType::ArrayType(std::shared_ptr<Type> ElementType, uint64_t ElementNumber, std::shared_ptr<Type> IndexType, Value start, Value end, - std::string&& name) - : Type(std::move(name), llvm::ArrayType::get(ElementType->GetLLVMType(), - (uint64_t) ElementNumber)) + std::string&& name, bool IsZeroStarted) + : Type(std::move(name), + llvm::ArrayType::get(ElementType->GetLLVMType(), ElementNumber)) , ElementType_(ElementType) , IndexType_(IndexType) , start_(start) - , end_(end) {} + , end_(end) + , IsZeroStarted_(IsZeroStarted) {} std::shared_ptr<Type> ArrayType::GetElementType() { return ElementType_; } std::shared_ptr<Type> ArrayType::GetIndexType() { return IndexType_; } @@ -298,10 +299,15 @@ Value ArrayType::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1, } Value ArrayType::CreateArrayAccess(Value v0, Value v1, Context* context) { - Value indices[2] = { - llvm::ConstantInt::get(IndexType_->GetLLVMType(), 0, true), - IndexType_->CreateBinaryOperation(BinaryOperator::SUB, v1, start_, - context)}; + Value Zero = llvm::ConstantInt::get(IndexType_->GetLLVMType(), 0, true); + Value indices[2] = {Zero}; + if (IsZeroStarted_ == false) { + indices[1] = IndexType_->CreateBinaryOperation(BinaryOperator::SUB, v1, + start_, context); + } else { + // saves a sub + indices[1] = v1; + } return context->GetBuilder()->CreateInBoundsGEP(v0, indices); } @@ -152,9 +152,9 @@ class RealType : public Type { class ArrayType : public Type { public: - ArrayType(std::shared_ptr<Type> ElementType, int ElementNumber, + ArrayType(std::shared_ptr<Type> ElementType, uint64_t ElementNumber, std::shared_ptr<Type> IndexType, Value start, Value end, - std::string&& name); + std::string&& name, bool IsZeroStarted = false); std::shared_ptr<Type> GetElementType(); std::shared_ptr<Type> GetIndexType(); virtual Value CreateBinaryOperation(BinaryOperator op, Value v0, Value v1, @@ -165,6 +165,7 @@ class ArrayType : public Type { std::shared_ptr<Type> ElementType_; std::shared_ptr<Type> IndexType_; + bool IsZeroStarted_; Value start_, end_; }; diff --git a/TypeManager.cc b/TypeManager.cc index c4c9c10..55b172e 100644 --- a/TypeManager.cc +++ b/TypeManager.cc @@ -1,5 +1,6 @@ #include "TypeManager.hh" #include "Context.hh" +#include "ExprNode.hh" #include "Log.hh" namespace pcc { @@ -195,6 +196,35 @@ std::shared_ptr<PointerType> return NewType; } +std::shared_ptr<ArrayType> + TypeManager::CreateArrayType(std::shared_ptr<Type> ElementType, + std::shared_ptr<ExprNode> start, + std::shared_ptr<ExprNode> end) { + llvm::Constant* StartValue = llvm::cast<llvm::Constant>(start->CodeGen()); + llvm::Constant* EndValue = llvm::cast<llvm::Constant>(end->CodeGen()); + std::shared_ptr<Type> IndexType = start->GetType(); + if (IndexType != end->GetType()) { + Log(LogLevel::PCC_ERROR, + "the start and end indices of an array type must be same " + "(start=%s, end=%s)", + IndexType->GetCommonName(), end->GetType()->GetCommonName()); + return nullptr; + } + if (std::dynamic_pointer_cast<IntegerBaseType>(IndexType) == nullptr) { + Log(LogLevel::PCC_ERROR, + "array index must have a integer-like type (i.e. integer, char)"); + return nullptr; + } + uint64_t StartIndex = StartValue->getUniqueInteger().getZExtValue(); + uint64_t ElementNumber = + EndValue->getUniqueInteger().getZExtValue() - StartIndex + 1; + std::shared_ptr<ArrayType> NewType = std::make_shared<ArrayType>( + ElementType, ElementNumber, IndexType, StartValue, EndValue, + std::string(ElementType->GetCommonName()) + "[]", StartIndex == 0); + ArrayTypes_.push_back(NewType); + return NewType; +} + std::shared_ptr<FunctionType> TypeManager::CreateFunctionType( std::shared_ptr<Type> ReturnType, std::vector<std::shared_ptr<Type>> ArgTypes) { diff --git a/TypeManager.hh b/TypeManager.hh index e6cd2c0..ce9cfee 100644 --- a/TypeManager.hh +++ b/TypeManager.hh @@ -9,6 +9,8 @@ #include "Type.hh" namespace pcc { +class ExprNode; + enum class BuiltinType { VOID, BOOLEAN, @@ -24,10 +26,19 @@ class TypeManager { TypeManager(); std::shared_ptr<Type> GetBuiltinType(BuiltinType type); + // if call this function twice with the same ElementType, it will return the + // same shared_ptr to the Type. std::shared_ptr<PointerType> GetPointerType(std::shared_ptr<Type> ElementType, const char* CustomName = nullptr); + // array types and function types are considered unique, unless use type + // alias, you can't get the same type as previous call to this function. + std::shared_ptr<ArrayType> + CreateArrayType(std::shared_ptr<Type> ElementType, + std::shared_ptr<ExprNode> start, + std::shared_ptr<ExprNode> end); + std::shared_ptr<FunctionType> CreateFunctionType(std::shared_ptr<Type> ReturnType, std::vector<std::shared_ptr<Type>> ArgTypes); diff --git a/node/ExprNode.cc b/node/ExprNode.cc index 93f0068..f4a26a8 100644 --- a/node/ExprNode.cc +++ b/node/ExprNode.cc @@ -95,14 +95,13 @@ FunctionCallNode::FunctionCallNode(Context* context, const std::string& name, Value FunctionCallNode::CodeGen() { TypeManager* manager = context_->GetTypeManager(); - std::shared_ptr<FunctionType> type = context_->GetFunctionType(name_); + Function function = context_->FindFunction(name_); + std::shared_ptr<FunctionType> type = std::get<0>(function); if (type == nullptr) { Log(LogLevel::PCC_ERROR, "call to undefined function %s", name_.c_str()); return nullptr; } - llvm::FunctionCallee fp = context_->GetModule()->getOrInsertFunction( - name_, llvm::cast<llvm::FunctionType>(type->GetLLVMType())); const std::vector<std::shared_ptr<Type>>& ArgTypes = type->GetArgTypes(); std::vector<Value> ArgValues(args_.size()); auto ArgTypeIt = ArgTypes.begin(); @@ -121,6 +120,6 @@ Value FunctionCallNode::CodeGen() { ++ArgTypeIt, ++ArgValueIt; } type_ = type->GetReturnType(); - return context_->GetBuilder()->CreateCall(fp, ArgValues); + return context_->GetBuilder()->CreateCall(std::get<1>(function), ArgValues); } } // namespace pcc diff --git a/node/FunctionNode.cc b/node/FunctionNode.cc index f6810fd..736007b 100644 --- a/node/FunctionNode.cc +++ b/node/FunctionNode.cc @@ -12,12 +12,12 @@ namespace pcc { FunctionNode::FunctionNode( Context* context, std::string&& name, std::list<Declaration>&& arguments, std::list<std::shared_ptr<DeclNode>>&& LocalDeclarations, - std::shared_ptr<Type> type, std::shared_ptr<StatementListNode> body) + std::shared_ptr<Type> ReturnType, std::shared_ptr<StatementListNode> body) : BaseNode(context) , name_(std::move(name)) , arguments_(std::move(arguments)) , LocalDeclarations_(std::move(LocalDeclarations)) - , type_(type) + , ReturnType_(ReturnType) , locals_(context->GetGlobals()) , body_(body) { for (auto&& decl : LocalDeclarations_) { @@ -33,13 +33,13 @@ Value FunctionNode::CodeGen() { std::transform(arguments_.cbegin(), arguments_.cend(), params.begin(), [](const Declaration& decl) { return std::get<1>(decl); }); std::shared_ptr<FunctionType> type = - manager->CreateFunctionType(type_, params); - context_->AddFunctionType(name_, type); + manager->CreateFunctionType(ReturnType_, params); 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); + context_->AddFunction(name_, {type, function}); llvm::BasicBlock* block = llvm::BasicBlock::Create(GlobalLLVMContext, name_, function); Log(LogLevel::PCC_INFO, "generating function %s of type %s", name_.c_str(), @@ -57,17 +57,17 @@ Value FunctionNode::CodeGen() { decl->CodeGen(); } Value rv = nullptr; - bool IsVoid = type_ == manager->GetBuiltinType(BuiltinType::VOID); + bool IsVoid = ReturnType_ == manager->GetBuiltinType(BuiltinType::VOID); if (IsVoid == false) { // create a variable with the same name as the function for return value - rv = builder->CreateAlloca(type_->GetLLVMType()); - locals_.Add(name_, {type_, rv}); + rv = builder->CreateAlloca(ReturnType_->GetLLVMType()); + locals_.Add(name_, {ReturnType_, rv}); } // push the function scope variables context_->PushScope(&locals_); body_->CodeGen(); if (IsVoid == false) { - builder->CreateRet(builder->CreateLoad(type_->GetLLVMType(), rv)); + builder->CreateRet(builder->CreateLoad(ReturnType_->GetLLVMType(), rv)); } else { builder->CreateRetVoid(); } diff --git a/node/FunctionNode.hh b/node/FunctionNode.hh index 415c2cc..d317402 100644 --- a/node/FunctionNode.hh +++ b/node/FunctionNode.hh @@ -13,7 +13,7 @@ class FunctionNode : public BaseNode { FunctionNode(Context* context, std::string&& name, std::list<Declaration>&& arguments, std::list<std::shared_ptr<DeclNode>>&& LocalDeclarations, - std::shared_ptr<Type> type, + std::shared_ptr<Type> ReturnType, std::shared_ptr<StatementListNode> body); virtual Value CodeGen() override; @@ -21,7 +21,7 @@ class FunctionNode : public BaseNode { std::string name_; std::list<Declaration> arguments_; std::list<std::shared_ptr<DeclNode>> LocalDeclarations_; - std::shared_ptr<Type> type_; + std::shared_ptr<Type> ReturnType_; VariableList locals_; std::shared_ptr<StatementListNode> body_; }; diff --git a/t/trivial.pas b/t/trivial.pas index dd98fad..560bb94 100644 --- a/t/trivial.pas +++ b/t/trivial.pas @@ -42,6 +42,24 @@ begin string_test:=s[b-a] end; +function array_test():integer; +var + ai:array['a'..'z'] of integer; + ac:array[0..25] of char; + i:integer; + c:char; +begin + i:=0; + c:='z'; + repeat + begin + ac[i]:=c; + ai[c]:=i; + i:=i+1; + c:=c-1 + end until i>25; +end; + function pointer_test():integer; var a,b:integer; |
