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