blob: c71301598bde6631928bbde17792c676df0f24c2 [file] [log] [blame]
Nandor Licker950b70d2019-09-13 09:46:16 +00001//===--- 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
18using namespace clang;
19using namespace clang::interp;
20
21template <typename T> using Expected = llvm::Expected<T>;
22template <typename T> using Optional = llvm::Optional<T>;
23
24namespace clang {
25namespace interp {
26
27/// Scope managing label targets.
28template <class Emitter> class LabelScope {
29public:
30 virtual ~LabelScope() { }
31
32protected:
33 LabelScope(ByteCodeStmtGen<Emitter> *Ctx) : Ctx(Ctx) {}
34 /// ByteCodeStmtGen instance.
35 ByteCodeStmtGen<Emitter> *Ctx;
36};
37
38/// Sets the context for break/continue statements.
39template <class Emitter> class LoopScope final : public LabelScope<Emitter> {
40public:
41 using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy;
42 using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy;
43
44 LoopScope(ByteCodeStmtGen<Emitter> *Ctx, LabelTy BreakLabel,
45 LabelTy ContinueLabel)
46 : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
47 OldContinueLabel(Ctx->ContinueLabel) {
48 this->Ctx->BreakLabel = BreakLabel;
49 this->Ctx->ContinueLabel = ContinueLabel;
50 }
51
52 ~LoopScope() {
53 this->Ctx->BreakLabel = OldBreakLabel;
54 this->Ctx->ContinueLabel = OldContinueLabel;
55 }
56
57private:
58 OptLabelTy OldBreakLabel;
59 OptLabelTy OldContinueLabel;
60};
61
62// Sets the context for a switch scope, mapping labels.
63template <class Emitter> class SwitchScope final : public LabelScope<Emitter> {
64public:
65 using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy;
66 using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy;
67 using CaseMap = typename ByteCodeStmtGen<Emitter>::CaseMap;
68
69 SwitchScope(ByteCodeStmtGen<Emitter> *Ctx, CaseMap &&CaseLabels,
70 LabelTy BreakLabel, OptLabelTy DefaultLabel)
71 : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
72 OldDefaultLabel(this->Ctx->DefaultLabel),
73 OldCaseLabels(std::move(this->Ctx->CaseLabels)) {
74 this->Ctx->BreakLabel = BreakLabel;
75 this->Ctx->DefaultLabel = DefaultLabel;
76 this->Ctx->CaseLabels = std::move(CaseLabels);
77 }
78
79 ~SwitchScope() {
80 this->Ctx->BreakLabel = OldBreakLabel;
81 this->Ctx->DefaultLabel = OldDefaultLabel;
82 this->Ctx->CaseLabels = std::move(OldCaseLabels);
83 }
84
85private:
86 OptLabelTy OldBreakLabel;
87 OptLabelTy OldDefaultLabel;
88 CaseMap OldCaseLabels;
89};
90
91} // namespace interp
92} // namespace clang
93
94template <class Emitter>
95bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
96 // Classify the return type.
97 ReturnType = this->classify(F->getReturnType());
98
99 // Set up fields and context if a constructor.
100 if (auto *MD = dyn_cast<CXXMethodDecl>(F))
101 return this->bail(MD);
102
103 if (auto *Body = F->getBody())
104 if (!visitStmt(Body))
105 return false;
106
107 // Emit a guard return to protect against a code path missing one.
108 if (F->getReturnType()->isVoidType())
109 return this->emitRetVoid(SourceInfo{});
110 else
111 return this->emitNoRet(SourceInfo{});
112}
113
114template <class Emitter>
115bool ByteCodeStmtGen<Emitter>::visitStmt(const Stmt *S) {
116 switch (S->getStmtClass()) {
117 case Stmt::CompoundStmtClass:
118 return visitCompoundStmt(cast<CompoundStmt>(S));
119 case Stmt::DeclStmtClass:
120 return visitDeclStmt(cast<DeclStmt>(S));
121 case Stmt::ReturnStmtClass:
122 return visitReturnStmt(cast<ReturnStmt>(S));
123 case Stmt::IfStmtClass:
124 return visitIfStmt(cast<IfStmt>(S));
125 case Stmt::NullStmtClass:
126 return true;
127 default: {
128 if (auto *Exp = dyn_cast<Expr>(S))
129 return this->discard(Exp);
130 return this->bail(S);
131 }
132 }
133}
134
135template <class Emitter>
136bool ByteCodeStmtGen<Emitter>::visitCompoundStmt(
137 const CompoundStmt *CompoundStmt) {
138 BlockScope<Emitter> Scope(this);
139 for (auto *InnerStmt : CompoundStmt->body())
140 if (!visitStmt(InnerStmt))
141 return false;
142 return true;
143}
144
145template <class Emitter>
146bool ByteCodeStmtGen<Emitter>::visitDeclStmt(const DeclStmt *DS) {
147 for (auto *D : DS->decls()) {
148 // Variable declarator.
149 if (auto *VD = dyn_cast<VarDecl>(D)) {
150 if (!visitVarDecl(VD))
151 return false;
152 continue;
153 }
154
155 // Decomposition declarator.
156 if (auto *DD = dyn_cast<DecompositionDecl>(D)) {
157 return this->bail(DD);
158 }
159 }
160
161 return true;
162}
163
164template <class Emitter>
165bool ByteCodeStmtGen<Emitter>::visitReturnStmt(const ReturnStmt *RS) {
166 if (const Expr *RE = RS->getRetValue()) {
167 ExprScope<Emitter> RetScope(this);
168 if (ReturnType) {
169 // Primitive types are simply returned.
170 if (!this->visit(RE))
171 return false;
172 this->emitCleanup();
173 return this->emitRet(*ReturnType, RS);
174 } else {
175 // RVO - construct the value in the return location.
176 auto ReturnLocation = [this, RE] { return this->emitGetParamPtr(0, RE); };
177 if (!this->visitInitializer(RE, ReturnLocation))
178 return false;
179 this->emitCleanup();
180 return this->emitRetVoid(RS);
181 }
182 } else {
183 this->emitCleanup();
184 if (!this->emitRetVoid(RS))
185 return false;
186 return true;
187 }
188}
189
190template <class Emitter>
191bool ByteCodeStmtGen<Emitter>::visitIfStmt(const IfStmt *IS) {
192 BlockScope<Emitter> IfScope(this);
193 if (auto *CondInit = IS->getInit())
194 if (!visitStmt(IS->getInit()))
195 return false;
196
197 if (const DeclStmt *CondDecl = IS->getConditionVariableDeclStmt())
198 if (!visitDeclStmt(CondDecl))
199 return false;
200
201 if (!this->visitBool(IS->getCond()))
202 return false;
203
204 if (const Stmt *Else = IS->getElse()) {
205 LabelTy LabelElse = this->getLabel();
206 LabelTy LabelEnd = this->getLabel();
207 if (!this->jumpFalse(LabelElse))
208 return false;
209 if (!visitStmt(IS->getThen()))
210 return false;
211 if (!this->jump(LabelEnd))
212 return false;
213 this->emitLabel(LabelElse);
214 if (!visitStmt(Else))
215 return false;
216 this->emitLabel(LabelEnd);
217 } else {
218 LabelTy LabelEnd = this->getLabel();
219 if (!this->jumpFalse(LabelEnd))
220 return false;
221 if (!visitStmt(IS->getThen()))
222 return false;
223 this->emitLabel(LabelEnd);
224 }
225
226 return true;
227}
228
229template <class Emitter>
230bool ByteCodeStmtGen<Emitter>::visitVarDecl(const VarDecl *VD) {
231 auto DT = VD->getType();
232
233 if (!VD->hasLocalStorage()) {
234 // No code generation required.
235 return true;
236 }
237
238 // Integers, pointers, primitives.
239 if (Optional<PrimType> T = this->classify(DT)) {
240 auto Off = this->allocateLocalPrimitive(VD, *T, DT.isConstQualified());
241 // Compile the initialiser in its own scope.
242 {
243 ExprScope<Emitter> Scope(this);
244 if (!this->visit(VD->getInit()))
245 return false;
246 }
247 // Set the value.
248 return this->emitSetLocal(*T, Off, VD);
249 } else {
250 // Composite types - allocate storage and initialize it.
251 if (auto Off = this->allocateLocal(VD)) {
252 return this->visitLocalInitializer(VD->getInit(), *Off);
253 } else {
254 return this->bail(VD);
255 }
256 }
257}
258
259namespace clang {
260namespace interp {
261
262template class ByteCodeStmtGen<ByteCodeEmitter>;
263
264} // namespace interp
265} // namespace clang