Mercurial > hg > CbC > CbC_llvm
view clang/lib/AST/Interp/ByteCodeStmtGen.cpp @ 176:de4ac79aef9d
...
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 25 May 2020 17:13:11 +0900 |
parents | 1d019706d866 |
children | c4bab56944e8 |
line wrap: on
line source
//===--- ByteCodeStmtGen.cpp - Code generator for expressions ---*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "ByteCodeStmtGen.h" #include "ByteCodeEmitter.h" #include "ByteCodeGenError.h" #include "Context.h" #include "Function.h" #include "PrimType.h" #include "Program.h" #include "State.h" #include "clang/Basic/LLVM.h" using namespace clang; using namespace clang::interp; namespace clang { namespace interp { /// Scope managing label targets. template <class Emitter> class LabelScope { public: virtual ~LabelScope() { } protected: LabelScope(ByteCodeStmtGen<Emitter> *Ctx) : Ctx(Ctx) {} /// ByteCodeStmtGen instance. ByteCodeStmtGen<Emitter> *Ctx; }; /// Sets the context for break/continue statements. template <class Emitter> class LoopScope final : public LabelScope<Emitter> { public: using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy; using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy; LoopScope(ByteCodeStmtGen<Emitter> *Ctx, LabelTy BreakLabel, LabelTy ContinueLabel) : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel), OldContinueLabel(Ctx->ContinueLabel) { this->Ctx->BreakLabel = BreakLabel; this->Ctx->ContinueLabel = ContinueLabel; } ~LoopScope() { this->Ctx->BreakLabel = OldBreakLabel; this->Ctx->ContinueLabel = OldContinueLabel; } private: OptLabelTy OldBreakLabel; OptLabelTy OldContinueLabel; }; // Sets the context for a switch scope, mapping labels. template <class Emitter> class SwitchScope final : public LabelScope<Emitter> { public: using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy; using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy; using CaseMap = typename ByteCodeStmtGen<Emitter>::CaseMap; SwitchScope(ByteCodeStmtGen<Emitter> *Ctx, CaseMap &&CaseLabels, LabelTy BreakLabel, OptLabelTy DefaultLabel) : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel), OldDefaultLabel(this->Ctx->DefaultLabel), OldCaseLabels(std::move(this->Ctx->CaseLabels)) { this->Ctx->BreakLabel = BreakLabel; this->Ctx->DefaultLabel = DefaultLabel; this->Ctx->CaseLabels = std::move(CaseLabels); } ~SwitchScope() { this->Ctx->BreakLabel = OldBreakLabel; this->Ctx->DefaultLabel = OldDefaultLabel; this->Ctx->CaseLabels = std::move(OldCaseLabels); } private: OptLabelTy OldBreakLabel; OptLabelTy OldDefaultLabel; CaseMap OldCaseLabels; }; } // namespace interp } // namespace clang template <class Emitter> bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) { // Classify the return type. ReturnType = this->classify(F->getReturnType()); // Set up fields and context if a constructor. if (auto *MD = dyn_cast<CXXMethodDecl>(F)) return this->bail(MD); if (auto *Body = F->getBody()) if (!visitStmt(Body)) return false; // Emit a guard return to protect against a code path missing one. if (F->getReturnType()->isVoidType()) return this->emitRetVoid(SourceInfo{}); else return this->emitNoRet(SourceInfo{}); } template <class Emitter> bool ByteCodeStmtGen<Emitter>::visitStmt(const Stmt *S) { switch (S->getStmtClass()) { case Stmt::CompoundStmtClass: return visitCompoundStmt(cast<CompoundStmt>(S)); case Stmt::DeclStmtClass: return visitDeclStmt(cast<DeclStmt>(S)); case Stmt::ReturnStmtClass: return visitReturnStmt(cast<ReturnStmt>(S)); case Stmt::IfStmtClass: return visitIfStmt(cast<IfStmt>(S)); case Stmt::NullStmtClass: return true; default: { if (auto *Exp = dyn_cast<Expr>(S)) return this->discard(Exp); return this->bail(S); } } } template <class Emitter> bool ByteCodeStmtGen<Emitter>::visitCompoundStmt( const CompoundStmt *CompoundStmt) { BlockScope<Emitter> Scope(this); for (auto *InnerStmt : CompoundStmt->body()) if (!visitStmt(InnerStmt)) return false; return true; } template <class Emitter> bool ByteCodeStmtGen<Emitter>::visitDeclStmt(const DeclStmt *DS) { for (auto *D : DS->decls()) { // Variable declarator. if (auto *VD = dyn_cast<VarDecl>(D)) { if (!visitVarDecl(VD)) return false; continue; } // Decomposition declarator. if (auto *DD = dyn_cast<DecompositionDecl>(D)) { return this->bail(DD); } } return true; } template <class Emitter> bool ByteCodeStmtGen<Emitter>::visitReturnStmt(const ReturnStmt *RS) { if (const Expr *RE = RS->getRetValue()) { ExprScope<Emitter> RetScope(this); if (ReturnType) { // Primitive types are simply returned. if (!this->visit(RE)) return false; this->emitCleanup(); return this->emitRet(*ReturnType, RS); } else { // RVO - construct the value in the return location. auto ReturnLocation = [this, RE] { return this->emitGetParamPtr(0, RE); }; if (!this->visitInitializer(RE, ReturnLocation)) return false; this->emitCleanup(); return this->emitRetVoid(RS); } } else { this->emitCleanup(); if (!this->emitRetVoid(RS)) return false; return true; } } template <class Emitter> bool ByteCodeStmtGen<Emitter>::visitIfStmt(const IfStmt *IS) { BlockScope<Emitter> IfScope(this); if (auto *CondInit = IS->getInit()) if (!visitStmt(IS->getInit())) return false; if (const DeclStmt *CondDecl = IS->getConditionVariableDeclStmt()) if (!visitDeclStmt(CondDecl)) return false; if (!this->visitBool(IS->getCond())) return false; if (const Stmt *Else = IS->getElse()) { LabelTy LabelElse = this->getLabel(); LabelTy LabelEnd = this->getLabel(); if (!this->jumpFalse(LabelElse)) return false; if (!visitStmt(IS->getThen())) return false; if (!this->jump(LabelEnd)) return false; this->emitLabel(LabelElse); if (!visitStmt(Else)) return false; this->emitLabel(LabelEnd); } else { LabelTy LabelEnd = this->getLabel(); if (!this->jumpFalse(LabelEnd)) return false; if (!visitStmt(IS->getThen())) return false; this->emitLabel(LabelEnd); } return true; } template <class Emitter> bool ByteCodeStmtGen<Emitter>::visitVarDecl(const VarDecl *VD) { auto DT = VD->getType(); if (!VD->hasLocalStorage()) { // No code generation required. return true; } // Integers, pointers, primitives. if (Optional<PrimType> T = this->classify(DT)) { auto Off = this->allocateLocalPrimitive(VD, *T, DT.isConstQualified()); // Compile the initialiser in its own scope. { ExprScope<Emitter> Scope(this); if (!this->visit(VD->getInit())) return false; } // Set the value. return this->emitSetLocal(*T, Off, VD); } else { // Composite types - allocate storage and initialize it. if (auto Off = this->allocateLocal(VD)) { return this->visitLocalInitializer(VD->getInit(), *Off); } else { return this->bail(VD); } } } namespace clang { namespace interp { template class ByteCodeStmtGen<ByteCodeEmitter>; } // namespace interp } // namespace clang