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 192 if (IS->isNonNegatedConsteval()) 193 return visitStmt(IS->getThen()); 194 if (IS->isNegatedConsteval()) 195 return IS->getElse() ? visitStmt(IS->getElse()) : true; 196 197 if (auto *CondInit = IS->getInit()) 198 if (!visitStmt(IS->getInit())) 199 return false; 200 201 if (const DeclStmt *CondDecl = IS->getConditionVariableDeclStmt()) 202 if (!visitDeclStmt(CondDecl)) 203 return false; 204 205 if (!this->visitBool(IS->getCond())) 206 return false; 207 208 if (const Stmt *Else = IS->getElse()) { 209 LabelTy LabelElse = this->getLabel(); 210 LabelTy LabelEnd = this->getLabel(); 211 if (!this->jumpFalse(LabelElse)) 212 return false; 213 if (!visitStmt(IS->getThen())) 214 return false; 215 if (!this->jump(LabelEnd)) 216 return false; 217 this->emitLabel(LabelElse); 218 if (!visitStmt(Else)) 219 return false; 220 this->emitLabel(LabelEnd); 221 } else { 222 LabelTy LabelEnd = this->getLabel(); 223 if (!this->jumpFalse(LabelEnd)) 224 return false; 225 if (!visitStmt(IS->getThen())) 226 return false; 227 this->emitLabel(LabelEnd); 228 } 229 230 return true; 231 } 232 233 template <class Emitter> 234 bool ByteCodeStmtGen<Emitter>::visitVarDecl(const VarDecl *VD) { 235 auto DT = VD->getType(); 236 237 if (!VD->hasLocalStorage()) { 238 // No code generation required. 239 return true; 240 } 241 242 // Integers, pointers, primitives. 243 if (Optional<PrimType> T = this->classify(DT)) { 244 auto Off = this->allocateLocalPrimitive(VD, *T, DT.isConstQualified()); 245 // Compile the initialiser in its own scope. 246 { 247 ExprScope<Emitter> Scope(this); 248 if (!this->visit(VD->getInit())) 249 return false; 250 } 251 // Set the value. 252 return this->emitSetLocal(*T, Off, VD); 253 } else { 254 // Composite types - allocate storage and initialize it. 255 if (auto Off = this->allocateLocal(VD)) { 256 return this->visitLocalInitializer(VD->getInit(), *Off); 257 } else { 258 return this->bail(VD); 259 } 260 } 261 } 262 263 namespace clang { 264 namespace interp { 265 266 template class ByteCodeStmtGen<ByteCodeEmitter>; 267 268 } // namespace interp 269 } // namespace clang 270