1950b70dcSNandor Licker //===--- ByteCodeStmtGen.cpp - Code generator for expressions ---*- C++ -*-===//
2950b70dcSNandor Licker //
3950b70dcSNandor Licker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4950b70dcSNandor Licker // See https://llvm.org/LICENSE.txt for license information.
5950b70dcSNandor Licker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6950b70dcSNandor Licker //
7950b70dcSNandor Licker //===----------------------------------------------------------------------===//
8950b70dcSNandor Licker 
9950b70dcSNandor Licker #include "ByteCodeStmtGen.h"
10950b70dcSNandor Licker #include "ByteCodeEmitter.h"
11950b70dcSNandor Licker #include "ByteCodeGenError.h"
12950b70dcSNandor Licker #include "Context.h"
13950b70dcSNandor Licker #include "Function.h"
14950b70dcSNandor Licker #include "PrimType.h"
15950b70dcSNandor Licker #include "Program.h"
16950b70dcSNandor Licker #include "State.h"
1719f1dc7bSReid Kleckner #include "clang/Basic/LLVM.h"
18950b70dcSNandor Licker 
19950b70dcSNandor Licker using namespace clang;
20950b70dcSNandor Licker using namespace clang::interp;
21950b70dcSNandor Licker 
22950b70dcSNandor Licker namespace clang {
23950b70dcSNandor Licker namespace interp {
24950b70dcSNandor Licker 
25950b70dcSNandor Licker /// Scope managing label targets.
26950b70dcSNandor Licker template <class Emitter> class LabelScope {
27950b70dcSNandor Licker public:
~LabelScope()28950b70dcSNandor Licker   virtual ~LabelScope() {  }
29950b70dcSNandor Licker 
30950b70dcSNandor Licker protected:
LabelScope(ByteCodeStmtGen<Emitter> * Ctx)31950b70dcSNandor Licker   LabelScope(ByteCodeStmtGen<Emitter> *Ctx) : Ctx(Ctx) {}
32950b70dcSNandor Licker   /// ByteCodeStmtGen instance.
33950b70dcSNandor Licker   ByteCodeStmtGen<Emitter> *Ctx;
34950b70dcSNandor Licker };
35950b70dcSNandor Licker 
36950b70dcSNandor Licker /// Sets the context for break/continue statements.
37950b70dcSNandor Licker template <class Emitter> class LoopScope final : public LabelScope<Emitter> {
38950b70dcSNandor Licker public:
39950b70dcSNandor Licker   using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy;
40950b70dcSNandor Licker   using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy;
41950b70dcSNandor Licker 
LoopScope(ByteCodeStmtGen<Emitter> * Ctx,LabelTy BreakLabel,LabelTy ContinueLabel)42950b70dcSNandor Licker   LoopScope(ByteCodeStmtGen<Emitter> *Ctx, LabelTy BreakLabel,
43950b70dcSNandor Licker             LabelTy ContinueLabel)
44950b70dcSNandor Licker       : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
45950b70dcSNandor Licker         OldContinueLabel(Ctx->ContinueLabel) {
46950b70dcSNandor Licker     this->Ctx->BreakLabel = BreakLabel;
47950b70dcSNandor Licker     this->Ctx->ContinueLabel = ContinueLabel;
48950b70dcSNandor Licker   }
49950b70dcSNandor Licker 
~LoopScope()50950b70dcSNandor Licker   ~LoopScope() {
51950b70dcSNandor Licker     this->Ctx->BreakLabel = OldBreakLabel;
52950b70dcSNandor Licker     this->Ctx->ContinueLabel = OldContinueLabel;
53950b70dcSNandor Licker   }
54950b70dcSNandor Licker 
55950b70dcSNandor Licker private:
56950b70dcSNandor Licker   OptLabelTy OldBreakLabel;
57950b70dcSNandor Licker   OptLabelTy OldContinueLabel;
58950b70dcSNandor Licker };
59950b70dcSNandor Licker 
60950b70dcSNandor Licker // Sets the context for a switch scope, mapping labels.
61950b70dcSNandor Licker template <class Emitter> class SwitchScope final : public LabelScope<Emitter> {
62950b70dcSNandor Licker public:
63950b70dcSNandor Licker   using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy;
64950b70dcSNandor Licker   using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy;
65950b70dcSNandor Licker   using CaseMap = typename ByteCodeStmtGen<Emitter>::CaseMap;
66950b70dcSNandor Licker 
SwitchScope(ByteCodeStmtGen<Emitter> * Ctx,CaseMap && CaseLabels,LabelTy BreakLabel,OptLabelTy DefaultLabel)67950b70dcSNandor Licker   SwitchScope(ByteCodeStmtGen<Emitter> *Ctx, CaseMap &&CaseLabels,
68950b70dcSNandor Licker               LabelTy BreakLabel, OptLabelTy DefaultLabel)
69950b70dcSNandor Licker       : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
70950b70dcSNandor Licker         OldDefaultLabel(this->Ctx->DefaultLabel),
71950b70dcSNandor Licker         OldCaseLabels(std::move(this->Ctx->CaseLabels)) {
72950b70dcSNandor Licker     this->Ctx->BreakLabel = BreakLabel;
73950b70dcSNandor Licker     this->Ctx->DefaultLabel = DefaultLabel;
74950b70dcSNandor Licker     this->Ctx->CaseLabels = std::move(CaseLabels);
75950b70dcSNandor Licker   }
76950b70dcSNandor Licker 
~SwitchScope()77950b70dcSNandor Licker   ~SwitchScope() {
78950b70dcSNandor Licker     this->Ctx->BreakLabel = OldBreakLabel;
79950b70dcSNandor Licker     this->Ctx->DefaultLabel = OldDefaultLabel;
80950b70dcSNandor Licker     this->Ctx->CaseLabels = std::move(OldCaseLabels);
81950b70dcSNandor Licker   }
82950b70dcSNandor Licker 
83950b70dcSNandor Licker private:
84950b70dcSNandor Licker   OptLabelTy OldBreakLabel;
85950b70dcSNandor Licker   OptLabelTy OldDefaultLabel;
86950b70dcSNandor Licker   CaseMap OldCaseLabels;
87950b70dcSNandor Licker };
88950b70dcSNandor Licker 
89950b70dcSNandor Licker } // namespace interp
90950b70dcSNandor Licker } // namespace clang
91950b70dcSNandor Licker 
92950b70dcSNandor Licker template <class Emitter>
visitFunc(const FunctionDecl * F)93950b70dcSNandor Licker bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
94950b70dcSNandor Licker   // Classify the return type.
95950b70dcSNandor Licker   ReturnType = this->classify(F->getReturnType());
96950b70dcSNandor Licker 
97950b70dcSNandor Licker   // Set up fields and context if a constructor.
98950b70dcSNandor Licker   if (auto *MD = dyn_cast<CXXMethodDecl>(F))
99950b70dcSNandor Licker     return this->bail(MD);
100950b70dcSNandor Licker 
101950b70dcSNandor Licker   if (auto *Body = F->getBody())
102950b70dcSNandor Licker     if (!visitStmt(Body))
103950b70dcSNandor Licker       return false;
104950b70dcSNandor Licker 
105950b70dcSNandor Licker   // Emit a guard return to protect against a code path missing one.
106950b70dcSNandor Licker   if (F->getReturnType()->isVoidType())
107950b70dcSNandor Licker     return this->emitRetVoid(SourceInfo{});
108950b70dcSNandor Licker   else
109950b70dcSNandor Licker     return this->emitNoRet(SourceInfo{});
110950b70dcSNandor Licker }
111950b70dcSNandor Licker 
112950b70dcSNandor Licker template <class Emitter>
visitStmt(const Stmt * S)113950b70dcSNandor Licker bool ByteCodeStmtGen<Emitter>::visitStmt(const Stmt *S) {
114950b70dcSNandor Licker   switch (S->getStmtClass()) {
115950b70dcSNandor Licker   case Stmt::CompoundStmtClass:
116950b70dcSNandor Licker     return visitCompoundStmt(cast<CompoundStmt>(S));
117950b70dcSNandor Licker   case Stmt::DeclStmtClass:
118950b70dcSNandor Licker     return visitDeclStmt(cast<DeclStmt>(S));
119950b70dcSNandor Licker   case Stmt::ReturnStmtClass:
120950b70dcSNandor Licker     return visitReturnStmt(cast<ReturnStmt>(S));
121950b70dcSNandor Licker   case Stmt::IfStmtClass:
122950b70dcSNandor Licker     return visitIfStmt(cast<IfStmt>(S));
123950b70dcSNandor Licker   case Stmt::NullStmtClass:
124950b70dcSNandor Licker     return true;
125950b70dcSNandor Licker   default: {
126950b70dcSNandor Licker     if (auto *Exp = dyn_cast<Expr>(S))
127950b70dcSNandor Licker       return this->discard(Exp);
128950b70dcSNandor Licker     return this->bail(S);
129950b70dcSNandor Licker   }
130950b70dcSNandor Licker   }
131950b70dcSNandor Licker }
132950b70dcSNandor Licker 
133950b70dcSNandor Licker template <class Emitter>
visitCompoundStmt(const CompoundStmt * CompoundStmt)134950b70dcSNandor Licker bool ByteCodeStmtGen<Emitter>::visitCompoundStmt(
135950b70dcSNandor Licker     const CompoundStmt *CompoundStmt) {
136950b70dcSNandor Licker   BlockScope<Emitter> Scope(this);
137950b70dcSNandor Licker   for (auto *InnerStmt : CompoundStmt->body())
138950b70dcSNandor Licker     if (!visitStmt(InnerStmt))
139950b70dcSNandor Licker       return false;
140950b70dcSNandor Licker   return true;
141950b70dcSNandor Licker }
142950b70dcSNandor Licker 
143950b70dcSNandor Licker template <class Emitter>
visitDeclStmt(const DeclStmt * DS)144950b70dcSNandor Licker bool ByteCodeStmtGen<Emitter>::visitDeclStmt(const DeclStmt *DS) {
145950b70dcSNandor Licker   for (auto *D : DS->decls()) {
146950b70dcSNandor Licker     // Variable declarator.
147950b70dcSNandor Licker     if (auto *VD = dyn_cast<VarDecl>(D)) {
148950b70dcSNandor Licker       if (!visitVarDecl(VD))
149950b70dcSNandor Licker         return false;
150950b70dcSNandor Licker       continue;
151950b70dcSNandor Licker     }
152950b70dcSNandor Licker 
153950b70dcSNandor Licker     // Decomposition declarator.
154950b70dcSNandor Licker     if (auto *DD = dyn_cast<DecompositionDecl>(D)) {
155950b70dcSNandor Licker       return this->bail(DD);
156950b70dcSNandor Licker     }
157950b70dcSNandor Licker   }
158950b70dcSNandor Licker 
159950b70dcSNandor Licker   return true;
160950b70dcSNandor Licker }
161950b70dcSNandor Licker 
162950b70dcSNandor Licker template <class Emitter>
visitReturnStmt(const ReturnStmt * RS)163950b70dcSNandor Licker bool ByteCodeStmtGen<Emitter>::visitReturnStmt(const ReturnStmt *RS) {
164950b70dcSNandor Licker   if (const Expr *RE = RS->getRetValue()) {
165950b70dcSNandor Licker     ExprScope<Emitter> RetScope(this);
166950b70dcSNandor Licker     if (ReturnType) {
167950b70dcSNandor Licker       // Primitive types are simply returned.
168950b70dcSNandor Licker       if (!this->visit(RE))
169950b70dcSNandor Licker         return false;
170950b70dcSNandor Licker       this->emitCleanup();
171950b70dcSNandor Licker       return this->emitRet(*ReturnType, RS);
172950b70dcSNandor Licker     } else {
173950b70dcSNandor Licker       // RVO - construct the value in the return location.
174950b70dcSNandor Licker       auto ReturnLocation = [this, RE] { return this->emitGetParamPtr(0, RE); };
175950b70dcSNandor Licker       if (!this->visitInitializer(RE, ReturnLocation))
176950b70dcSNandor Licker         return false;
177950b70dcSNandor Licker       this->emitCleanup();
178950b70dcSNandor Licker       return this->emitRetVoid(RS);
179950b70dcSNandor Licker     }
180950b70dcSNandor Licker   } else {
181950b70dcSNandor Licker     this->emitCleanup();
182950b70dcSNandor Licker     if (!this->emitRetVoid(RS))
183950b70dcSNandor Licker       return false;
184950b70dcSNandor Licker     return true;
185950b70dcSNandor Licker   }
186950b70dcSNandor Licker }
187950b70dcSNandor Licker 
188950b70dcSNandor Licker template <class Emitter>
visitIfStmt(const IfStmt * IS)189950b70dcSNandor Licker bool ByteCodeStmtGen<Emitter>::visitIfStmt(const IfStmt *IS) {
190950b70dcSNandor Licker   BlockScope<Emitter> IfScope(this);
191*424733c1SCorentin Jabot 
192*424733c1SCorentin Jabot   if (IS->isNonNegatedConsteval())
193*424733c1SCorentin Jabot     return visitStmt(IS->getThen());
194*424733c1SCorentin Jabot   if (IS->isNegatedConsteval())
195*424733c1SCorentin Jabot     return IS->getElse() ? visitStmt(IS->getElse()) : true;
196*424733c1SCorentin Jabot 
197950b70dcSNandor Licker   if (auto *CondInit = IS->getInit())
198950b70dcSNandor Licker     if (!visitStmt(IS->getInit()))
199950b70dcSNandor Licker       return false;
200950b70dcSNandor Licker 
201950b70dcSNandor Licker   if (const DeclStmt *CondDecl = IS->getConditionVariableDeclStmt())
202950b70dcSNandor Licker     if (!visitDeclStmt(CondDecl))
203950b70dcSNandor Licker       return false;
204950b70dcSNandor Licker 
205950b70dcSNandor Licker   if (!this->visitBool(IS->getCond()))
206950b70dcSNandor Licker     return false;
207950b70dcSNandor Licker 
208950b70dcSNandor Licker   if (const Stmt *Else = IS->getElse()) {
209950b70dcSNandor Licker     LabelTy LabelElse = this->getLabel();
210950b70dcSNandor Licker     LabelTy LabelEnd = this->getLabel();
211950b70dcSNandor Licker     if (!this->jumpFalse(LabelElse))
212950b70dcSNandor Licker       return false;
213950b70dcSNandor Licker     if (!visitStmt(IS->getThen()))
214950b70dcSNandor Licker       return false;
215950b70dcSNandor Licker     if (!this->jump(LabelEnd))
216950b70dcSNandor Licker       return false;
217950b70dcSNandor Licker     this->emitLabel(LabelElse);
218950b70dcSNandor Licker     if (!visitStmt(Else))
219950b70dcSNandor Licker       return false;
220950b70dcSNandor Licker     this->emitLabel(LabelEnd);
221950b70dcSNandor Licker   } else {
222950b70dcSNandor Licker     LabelTy LabelEnd = this->getLabel();
223950b70dcSNandor Licker     if (!this->jumpFalse(LabelEnd))
224950b70dcSNandor Licker       return false;
225950b70dcSNandor Licker     if (!visitStmt(IS->getThen()))
226950b70dcSNandor Licker       return false;
227950b70dcSNandor Licker     this->emitLabel(LabelEnd);
228950b70dcSNandor Licker   }
229950b70dcSNandor Licker 
230950b70dcSNandor Licker   return true;
231950b70dcSNandor Licker }
232950b70dcSNandor Licker 
233950b70dcSNandor Licker template <class Emitter>
visitVarDecl(const VarDecl * VD)234950b70dcSNandor Licker bool ByteCodeStmtGen<Emitter>::visitVarDecl(const VarDecl *VD) {
235950b70dcSNandor Licker   auto DT = VD->getType();
236950b70dcSNandor Licker 
237950b70dcSNandor Licker   if (!VD->hasLocalStorage()) {
238950b70dcSNandor Licker     // No code generation required.
239950b70dcSNandor Licker     return true;
240950b70dcSNandor Licker   }
241950b70dcSNandor Licker 
242950b70dcSNandor Licker   // Integers, pointers, primitives.
243950b70dcSNandor Licker   if (Optional<PrimType> T = this->classify(DT)) {
244950b70dcSNandor Licker     auto Off = this->allocateLocalPrimitive(VD, *T, DT.isConstQualified());
245950b70dcSNandor Licker     // Compile the initialiser in its own scope.
246950b70dcSNandor Licker     {
247950b70dcSNandor Licker       ExprScope<Emitter> Scope(this);
248950b70dcSNandor Licker       if (!this->visit(VD->getInit()))
249950b70dcSNandor Licker         return false;
250950b70dcSNandor Licker     }
251950b70dcSNandor Licker     // Set the value.
252950b70dcSNandor Licker     return this->emitSetLocal(*T, Off, VD);
253950b70dcSNandor Licker   } else {
254950b70dcSNandor Licker     // Composite types - allocate storage and initialize it.
255950b70dcSNandor Licker     if (auto Off = this->allocateLocal(VD)) {
256950b70dcSNandor Licker       return this->visitLocalInitializer(VD->getInit(), *Off);
257950b70dcSNandor Licker     } else {
258950b70dcSNandor Licker       return this->bail(VD);
259950b70dcSNandor Licker     }
260950b70dcSNandor Licker   }
261950b70dcSNandor Licker }
262950b70dcSNandor Licker 
263950b70dcSNandor Licker namespace clang {
264950b70dcSNandor Licker namespace interp {
265950b70dcSNandor Licker 
266950b70dcSNandor Licker template class ByteCodeStmtGen<ByteCodeEmitter>;
267950b70dcSNandor Licker 
268950b70dcSNandor Licker } // namespace interp
269950b70dcSNandor Licker } // namespace clang
270