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