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:
~LabelScope()28 virtual ~LabelScope() { }
29
30 protected:
LabelScope(ByteCodeStmtGen<Emitter> * Ctx)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
LoopScope(ByteCodeStmtGen<Emitter> * Ctx,LabelTy BreakLabel,LabelTy ContinueLabel)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
~LoopScope()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
SwitchScope(ByteCodeStmtGen<Emitter> * Ctx,CaseMap && CaseLabels,LabelTy BreakLabel,OptLabelTy DefaultLabel)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
~SwitchScope()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>
visitFunc(const FunctionDecl * F)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>
visitStmt(const Stmt * S)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>
visitCompoundStmt(const CompoundStmt * CompoundStmt)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>
visitDeclStmt(const DeclStmt * DS)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>
visitReturnStmt(const ReturnStmt * RS)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>
visitIfStmt(const IfStmt * IS)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>
visitVarDecl(const VarDecl * VD)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