From 176c8e70f56bbbbe5ab2063f22000b9af0180e85 Mon Sep 17 00:00:00 2001 From: Nagi5Yeq Date: Fri, 5 Jun 2020 01:25:59 +0800 Subject: add case statement support --- node/Node.cc | 41 ++++++++++++++++++++++++++++++ node/StatementNode.cc | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++ node/StatementNode.hh | 18 +++++++++++++ 3 files changed, 129 insertions(+) (limited to 'node') diff --git a/node/Node.cc b/node/Node.cc index 0dcf8ce..9325160 100644 --- a/node/Node.cc +++ b/node/Node.cc @@ -501,4 +501,45 @@ int ContinueStatementNode::Travel(Traveler& traveler) { traveler << TravelPart::END; return 0; } + +int SwitchStatementNode::Travel(Traveler& traveler) { + traveler << TravelPart::PREFIX; + traveler << TravelPart::NAME_BEGIN << "SwitchStatementNode" + << TravelPart::NAME_END; + traveler << TravelPart::DESCRPTION_BEGIN << "NumCases=" + << CasePairs_.size() + (DefaultAction_ == nullptr ? 0 : 1) + << (DefaultAction_ == nullptr ? "" : " HasDefault") + << TravelPart::DESCRPTION_END; + traveler << TravelPart::CHILD_BEGIN; + CaseVariable_->Travel(traveler); + traveler << TravelPart::CHILD_END; + std::shared_ptr PrevAction = nullptr; + std::vector> actions; + for (auto&& child : CasePairs_) { + std::shared_ptr action = std::get<1>(child); + if (action != PrevAction) { + actions.push_back(action); + PrevAction = action; + } + } + auto lambda = [](Traveler& traveler, auto&& action) { + action->Travel(traveler); + }; + NonterminalContainerTravel( + traveler, + [](Traveler& traveler, auto&& child) { + std::get<0>(child)->Travel(traveler); + }, + CasePairs_); + if (DefaultAction_ == nullptr) { + TerminalContainerTravel(traveler, lambda, actions); + } else { + NonterminalContainerTravel(traveler, lambda, actions); + traveler << TravelPart::LAST_CHILD_BEGIN; + DefaultAction_->Travel(traveler); + traveler << TravelPart::LAST_CHILD_END; + } + traveler << TravelPart::END; + return 0; +} } // namespace pcc diff --git a/node/StatementNode.cc b/node/StatementNode.cc index 07babe2..adce4f0 100644 --- a/node/StatementNode.cc +++ b/node/StatementNode.cc @@ -294,4 +294,74 @@ Value ContinueStatementNode::CodeGen() { context_->SetJumpingFlag(true); return nullptr; } + +SwitchStatementNode::SwitchStatementNode( + Context* context, std::shared_ptr CaseVariable, + std::list&& CasePairs, std::shared_ptr DefaultAction) + : BaseNode(context) + , CaseVariable_(CaseVariable) + , CasePairs_(std::move(CasePairs)) + , DefaultAction_(DefaultAction) {} + +Value SwitchStatementNode::CodeGen() { + llvm::IRBuilder<>* builder = context_->GetBuilder(); + Value SwitchValue = CaseVariable_->CodeGen(); + std::shared_ptr type = + std::dynamic_pointer_cast(CaseVariable_->GetType()); + if (type == nullptr) { + Log(LogLevel::PCC_ERROR, + "variable of switch statement variable should have a integer-like " + "type, not %s", + CaseVariable_->GetType()->GetCommonName()); + return nullptr; + } + llvm::Function* body = builder->GetInsertBlock()->getParent(); + llvm::BasicBlock* EndBlock = + llvm::BasicBlock::Create(GlobalLLVMContext, "done"); + llvm::BasicBlock* DefaultBlock = + (DefaultAction_ == nullptr + ? EndBlock + : llvm::BasicBlock::Create(GlobalLLVMContext, "default")); + llvm::SwitchInst* inst = + builder->CreateSwitch(SwitchValue, DefaultBlock, CasePairs_.size() + 1); + std::shared_ptr PrevAcion = nullptr; + llvm::BasicBlock* PrevBlock = nullptr; + for (auto&& CaseChild : CasePairs_) { + llvm::Value* CaseValue = std::get<0>(CaseChild)->CodeGen(); + std::shared_ptr CaseType = + std::dynamic_pointer_cast( + std::get<0>(CaseChild)->GetType()); + if (CaseType == nullptr) { + Log(LogLevel::PCC_ERROR, + "case of switch statement variable should have a " + "integer-like " + "type, not %s", + std::get<0>(CaseChild)->GetType()->GetCommonName()); + return nullptr; + } + CaseValue = builder->CreateSExtOrTrunc(CaseValue, type->GetLLVMType()); + llvm::ConstantInt* CaseConst = llvm::cast(CaseValue); + std::shared_ptr CaseAction = std::get<1>(CaseChild); + if (CaseAction == PrevAcion) { + inst->addCase(CaseConst, PrevBlock); + } else { + llvm::BasicBlock* CaseBlock = + llvm::BasicBlock::Create(GlobalLLVMContext, "case", body); + inst->addCase(CaseConst, CaseBlock); + builder->SetInsertPoint(CaseBlock); + CaseAction->CodeGen(); + builder->CreateBr(EndBlock); + PrevAcion = CaseAction, PrevBlock = CaseBlock; + } + } + if (DefaultAction_ != nullptr) { + body->getBasicBlockList().push_back(DefaultBlock); + builder->SetInsertPoint(DefaultBlock); + DefaultAction_->CodeGen(); + builder->CreateBr(EndBlock); + } + body->getBasicBlockList().push_back(EndBlock); + builder->SetInsertPoint(EndBlock); + return nullptr; +} } // namespace pcc diff --git a/node/StatementNode.hh b/node/StatementNode.hh index b729001..81cbb93 100644 --- a/node/StatementNode.hh +++ b/node/StatementNode.hh @@ -105,6 +105,24 @@ class ContinueStatementNode : public BaseNode { virtual Value CodeGen() override; virtual int Travel(Traveler& traveler) override; }; + +using CasePair = + std::pair, std::shared_ptr>; + +class SwitchStatementNode : public BaseNode { + public: + SwitchStatementNode(Context* context, + std::shared_ptr CaseVariable, + std::list&& CasePairs, + std::shared_ptr DefaultAction); + virtual Value CodeGen() override; + virtual int Travel(Traveler& traveler) override; + + protected: + std::shared_ptr CaseVariable_; + std::list CasePairs_; + std::shared_ptr DefaultAction_; +}; } // namespace pcc #endif -- cgit