Home | History | Annotate | Line # | Download | only in Interp
      1 //===--- ByteCodeStmtGen.cpp - Code generator for expressions ---*- C++ -*-===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 
      9 #include "ByteCodeStmtGen.h"
     10 #include "ByteCodeEmitter.h"
     11 #include "ByteCodeGenError.h"
     12 #include "Context.h"
     13 #include "Function.h"
     14 #include "PrimType.h"
     15 #include "Program.h"
     16 #include "State.h"
     17 #include "clang/Basic/LLVM.h"
     18 
     19 using namespace clang;
     20 using namespace clang::interp;
     21 
     22 namespace clang {
     23 namespace interp {
     24 
     25 /// Scope managing label targets.
     26 template <class Emitter> class LabelScope {
     27 public:
     28   virtual ~LabelScope() {  }
     29 
     30 protected:
     31   LabelScope(ByteCodeStmtGen<Emitter> *Ctx) : Ctx(Ctx) {}
     32   /// ByteCodeStmtGen instance.
     33   ByteCodeStmtGen<Emitter> *Ctx;
     34 };
     35 
     36 /// Sets the context for break/continue statements.
     37 template <class Emitter> class LoopScope final : public LabelScope<Emitter> {
     38 public:
     39   using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy;
     40   using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy;
     41 
     42   LoopScope(ByteCodeStmtGen<Emitter> *Ctx, LabelTy BreakLabel,
     43             LabelTy ContinueLabel)
     44       : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
     45         OldContinueLabel(Ctx->ContinueLabel) {
     46     this->Ctx->BreakLabel = BreakLabel;
     47     this->Ctx->ContinueLabel = ContinueLabel;
     48   }
     49 
     50   ~LoopScope() {
     51     this->Ctx->BreakLabel = OldBreakLabel;
     52     this->Ctx->ContinueLabel = OldContinueLabel;
     53   }
     54 
     55 private:
     56   OptLabelTy OldBreakLabel;
     57   OptLabelTy OldContinueLabel;
     58 };
     59 
     60 // Sets the context for a switch scope, mapping labels.
     61 template <class Emitter> class SwitchScope final : public LabelScope<Emitter> {
     62 public:
     63   using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy;
     64   using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy;
     65   using CaseMap = typename ByteCodeStmtGen<Emitter>::CaseMap;
     66 
     67   SwitchScope(ByteCodeStmtGen<Emitter> *Ctx, CaseMap &&CaseLabels,
     68               LabelTy BreakLabel, OptLabelTy DefaultLabel)
     69       : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
     70         OldDefaultLabel(this->Ctx->DefaultLabel),
     71         OldCaseLabels(std::move(this->Ctx->CaseLabels)) {
     72     this->Ctx->BreakLabel = BreakLabel;
     73     this->Ctx->DefaultLabel = DefaultLabel;
     74     this->Ctx->CaseLabels = std::move(CaseLabels);
     75   }
     76 
     77   ~SwitchScope() {
     78     this->Ctx->BreakLabel = OldBreakLabel;
     79     this->Ctx->DefaultLabel = OldDefaultLabel;
     80     this->Ctx->CaseLabels = std::move(OldCaseLabels);
     81   }
     82 
     83 private:
     84   OptLabelTy OldBreakLabel;
     85   OptLabelTy OldDefaultLabel;
     86   CaseMap OldCaseLabels;
     87 };
     88 
     89 } // namespace interp
     90 } // namespace clang
     91 
     92 template <class Emitter>
     93 bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
     94   // Classify the return type.
     95   ReturnType = this->classify(F->getReturnType());
     96 
     97   // Set up fields and context if a constructor.
     98   if (auto *MD = dyn_cast<CXXMethodDecl>(F))
     99     return this->bail(MD);
    100 
    101   if (auto *Body = F->getBody())
    102     if (!visitStmt(Body))
    103       return false;
    104 
    105   // Emit a guard return to protect against a code path missing one.
    106   if (F->getReturnType()->isVoidType())
    107     return this->emitRetVoid(SourceInfo{});
    108   else
    109     return this->emitNoRet(SourceInfo{});
    110 }
    111 
    112 template <class Emitter>
    113 bool ByteCodeStmtGen<Emitter>::visitStmt(const Stmt *S) {
    114   switch (S->getStmtClass()) {
    115   case Stmt::CompoundStmtClass:
    116     return visitCompoundStmt(cast<CompoundStmt>(S));
    117   case Stmt::DeclStmtClass:
    118     return visitDeclStmt(cast<DeclStmt>(S));
    119   case Stmt::ReturnStmtClass:
    120     return visitReturnStmt(cast<ReturnStmt>(S));
    121   case Stmt::IfStmtClass:
    122     return visitIfStmt(cast<IfStmt>(S));
    123   case Stmt::NullStmtClass:
    124     return true;
    125   default: {
    126     if (auto *Exp = dyn_cast<Expr>(S))
    127       return this->discard(Exp);
    128     return this->bail(S);
    129   }
    130   }
    131 }
    132 
    133 template <class Emitter>
    134 bool ByteCodeStmtGen<Emitter>::visitCompoundStmt(
    135     const CompoundStmt *CompoundStmt) {
    136   BlockScope<Emitter> Scope(this);
    137   for (auto *InnerStmt : CompoundStmt->body())
    138     if (!visitStmt(InnerStmt))
    139       return false;
    140   return true;
    141 }
    142 
    143 template <class Emitter>
    144 bool ByteCodeStmtGen<Emitter>::visitDeclStmt(const DeclStmt *DS) {
    145   for (auto *D : DS->decls()) {
    146     // Variable declarator.
    147     if (auto *VD = dyn_cast<VarDecl>(D)) {
    148       if (!visitVarDecl(VD))
    149         return false;
    150       continue;
    151     }
    152 
    153     // Decomposition declarator.
    154     if (auto *DD = dyn_cast<DecompositionDecl>(D)) {
    155       return this->bail(DD);
    156     }
    157   }
    158 
    159   return true;
    160 }
    161 
    162 template <class Emitter>
    163 bool ByteCodeStmtGen<Emitter>::visitReturnStmt(const ReturnStmt *RS) {
    164   if (const Expr *RE = RS->getRetValue()) {
    165     ExprScope<Emitter> RetScope(this);
    166     if (ReturnType) {
    167       // Primitive types are simply returned.
    168       if (!this->visit(RE))
    169         return false;
    170       this->emitCleanup();
    171       return this->emitRet(*ReturnType, RS);
    172     } else {
    173       // RVO - construct the value in the return location.
    174       auto ReturnLocation = [this, RE] { return this->emitGetParamPtr(0, RE); };
    175       if (!this->visitInitializer(RE, ReturnLocation))
    176         return false;
    177       this->emitCleanup();
    178       return this->emitRetVoid(RS);
    179     }
    180   } else {
    181     this->emitCleanup();
    182     if (!this->emitRetVoid(RS))
    183       return false;
    184     return true;
    185   }
    186 }
    187 
    188 template <class Emitter>
    189 bool ByteCodeStmtGen<Emitter>::visitIfStmt(const IfStmt *IS) {
    190   BlockScope<Emitter> IfScope(this);
    191   if (auto *CondInit = IS->getInit())
    192     if (!visitStmt(IS->getInit()))
    193       return false;
    194 
    195   if (const DeclStmt *CondDecl = IS->getConditionVariableDeclStmt())
    196     if (!visitDeclStmt(CondDecl))
    197       return false;
    198 
    199   if (!this->visitBool(IS->getCond()))
    200     return false;
    201 
    202   if (const Stmt *Else = IS->getElse()) {
    203     LabelTy LabelElse = this->getLabel();
    204     LabelTy LabelEnd = this->getLabel();
    205     if (!this->jumpFalse(LabelElse))
    206       return false;
    207     if (!visitStmt(IS->getThen()))
    208       return false;
    209     if (!this->jump(LabelEnd))
    210       return false;
    211     this->emitLabel(LabelElse);
    212     if (!visitStmt(Else))
    213       return false;
    214     this->emitLabel(LabelEnd);
    215   } else {
    216     LabelTy LabelEnd = this->getLabel();
    217     if (!this->jumpFalse(LabelEnd))
    218       return false;
    219     if (!visitStmt(IS->getThen()))
    220       return false;
    221     this->emitLabel(LabelEnd);
    222   }
    223 
    224   return true;
    225 }
    226 
    227 template <class Emitter>
    228 bool ByteCodeStmtGen<Emitter>::visitVarDecl(const VarDecl *VD) {
    229   auto DT = VD->getType();
    230 
    231   if (!VD->hasLocalStorage()) {
    232     // No code generation required.
    233     return true;
    234   }
    235 
    236   // Integers, pointers, primitives.
    237   if (Optional<PrimType> T = this->classify(DT)) {
    238     auto Off = this->allocateLocalPrimitive(VD, *T, DT.isConstQualified());
    239     // Compile the initialiser in its own scope.
    240     {
    241       ExprScope<Emitter> Scope(this);
    242       if (!this->visit(VD->getInit()))
    243         return false;
    244     }
    245     // Set the value.
    246     return this->emitSetLocal(*T, Off, VD);
    247   } else {
    248     // Composite types - allocate storage and initialize it.
    249     if (auto Off = this->allocateLocal(VD)) {
    250       return this->visitLocalInitializer(VD->getInit(), *Off);
    251     } else {
    252       return this->bail(VD);
    253     }
    254   }
    255 }
    256 
    257 namespace clang {
    258 namespace interp {
    259 
    260 template class ByteCodeStmtGen<ByteCodeEmitter>;
    261 
    262 } // namespace interp
    263 } // namespace clang
    264