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