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