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