1e5dd7070Spatrick //===--- ByteCodeStmtGen.cpp - Code generator for expressions ---*- C++ -*-===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick
9e5dd7070Spatrick #include "ByteCodeStmtGen.h"
10e5dd7070Spatrick #include "ByteCodeEmitter.h"
11e5dd7070Spatrick #include "ByteCodeGenError.h"
12e5dd7070Spatrick #include "Context.h"
13e5dd7070Spatrick #include "Function.h"
14e5dd7070Spatrick #include "PrimType.h"
15e5dd7070Spatrick #include "Program.h"
16e5dd7070Spatrick #include "State.h"
17e5dd7070Spatrick #include "clang/Basic/LLVM.h"
18e5dd7070Spatrick
19e5dd7070Spatrick using namespace clang;
20e5dd7070Spatrick using namespace clang::interp;
21e5dd7070Spatrick
22e5dd7070Spatrick namespace clang {
23e5dd7070Spatrick namespace interp {
24e5dd7070Spatrick
25e5dd7070Spatrick /// Scope managing label targets.
26e5dd7070Spatrick template <class Emitter> class LabelScope {
27e5dd7070Spatrick public:
~LabelScope()28e5dd7070Spatrick virtual ~LabelScope() { }
29e5dd7070Spatrick
30e5dd7070Spatrick protected:
LabelScope(ByteCodeStmtGen<Emitter> * Ctx)31e5dd7070Spatrick LabelScope(ByteCodeStmtGen<Emitter> *Ctx) : Ctx(Ctx) {}
32e5dd7070Spatrick /// ByteCodeStmtGen instance.
33e5dd7070Spatrick ByteCodeStmtGen<Emitter> *Ctx;
34e5dd7070Spatrick };
35e5dd7070Spatrick
36e5dd7070Spatrick /// Sets the context for break/continue statements.
37e5dd7070Spatrick template <class Emitter> class LoopScope final : public LabelScope<Emitter> {
38e5dd7070Spatrick public:
39e5dd7070Spatrick using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy;
40e5dd7070Spatrick using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy;
41e5dd7070Spatrick
LoopScope(ByteCodeStmtGen<Emitter> * Ctx,LabelTy BreakLabel,LabelTy ContinueLabel)42e5dd7070Spatrick LoopScope(ByteCodeStmtGen<Emitter> *Ctx, LabelTy BreakLabel,
43e5dd7070Spatrick LabelTy ContinueLabel)
44e5dd7070Spatrick : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
45e5dd7070Spatrick OldContinueLabel(Ctx->ContinueLabel) {
46e5dd7070Spatrick this->Ctx->BreakLabel = BreakLabel;
47e5dd7070Spatrick this->Ctx->ContinueLabel = ContinueLabel;
48e5dd7070Spatrick }
49e5dd7070Spatrick
~LoopScope()50e5dd7070Spatrick ~LoopScope() {
51e5dd7070Spatrick this->Ctx->BreakLabel = OldBreakLabel;
52e5dd7070Spatrick this->Ctx->ContinueLabel = OldContinueLabel;
53e5dd7070Spatrick }
54e5dd7070Spatrick
55e5dd7070Spatrick private:
56e5dd7070Spatrick OptLabelTy OldBreakLabel;
57e5dd7070Spatrick OptLabelTy OldContinueLabel;
58e5dd7070Spatrick };
59e5dd7070Spatrick
60e5dd7070Spatrick // Sets the context for a switch scope, mapping labels.
61e5dd7070Spatrick template <class Emitter> class SwitchScope final : public LabelScope<Emitter> {
62e5dd7070Spatrick public:
63e5dd7070Spatrick using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy;
64e5dd7070Spatrick using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy;
65e5dd7070Spatrick using CaseMap = typename ByteCodeStmtGen<Emitter>::CaseMap;
66e5dd7070Spatrick
SwitchScope(ByteCodeStmtGen<Emitter> * Ctx,CaseMap && CaseLabels,LabelTy BreakLabel,OptLabelTy DefaultLabel)67e5dd7070Spatrick SwitchScope(ByteCodeStmtGen<Emitter> *Ctx, CaseMap &&CaseLabels,
68e5dd7070Spatrick LabelTy BreakLabel, OptLabelTy DefaultLabel)
69e5dd7070Spatrick : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
70e5dd7070Spatrick OldDefaultLabel(this->Ctx->DefaultLabel),
71e5dd7070Spatrick OldCaseLabels(std::move(this->Ctx->CaseLabels)) {
72e5dd7070Spatrick this->Ctx->BreakLabel = BreakLabel;
73e5dd7070Spatrick this->Ctx->DefaultLabel = DefaultLabel;
74e5dd7070Spatrick this->Ctx->CaseLabels = std::move(CaseLabels);
75e5dd7070Spatrick }
76e5dd7070Spatrick
~SwitchScope()77e5dd7070Spatrick ~SwitchScope() {
78e5dd7070Spatrick this->Ctx->BreakLabel = OldBreakLabel;
79e5dd7070Spatrick this->Ctx->DefaultLabel = OldDefaultLabel;
80e5dd7070Spatrick this->Ctx->CaseLabels = std::move(OldCaseLabels);
81e5dd7070Spatrick }
82e5dd7070Spatrick
83e5dd7070Spatrick private:
84e5dd7070Spatrick OptLabelTy OldBreakLabel;
85e5dd7070Spatrick OptLabelTy OldDefaultLabel;
86e5dd7070Spatrick CaseMap OldCaseLabels;
87e5dd7070Spatrick };
88e5dd7070Spatrick
89e5dd7070Spatrick } // namespace interp
90e5dd7070Spatrick } // namespace clang
91e5dd7070Spatrick
92e5dd7070Spatrick template <class Emitter>
visitFunc(const FunctionDecl * F)93e5dd7070Spatrick bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
94e5dd7070Spatrick // Classify the return type.
95e5dd7070Spatrick ReturnType = this->classify(F->getReturnType());
96e5dd7070Spatrick
97*12c85518Srobert // Constructor. Set up field initializers.
98*12c85518Srobert if (const auto Ctor = dyn_cast<CXXConstructorDecl>(F)) {
99*12c85518Srobert const RecordDecl *RD = Ctor->getParent();
100*12c85518Srobert const Record *R = this->getRecord(RD);
101*12c85518Srobert if (!R)
102*12c85518Srobert return false;
103e5dd7070Spatrick
104*12c85518Srobert for (const auto *Init : Ctor->inits()) {
105*12c85518Srobert const Expr *InitExpr = Init->getInit();
106*12c85518Srobert if (const FieldDecl *Member = Init->getMember()) {
107*12c85518Srobert const Record::Field *F = R->getField(Member);
108*12c85518Srobert
109*12c85518Srobert if (std::optional<PrimType> T = this->classify(InitExpr)) {
110*12c85518Srobert if (!this->emitThis(InitExpr))
111*12c85518Srobert return false;
112*12c85518Srobert
113*12c85518Srobert if (!this->visit(InitExpr))
114*12c85518Srobert return false;
115*12c85518Srobert
116*12c85518Srobert if (!this->emitInitField(*T, F->Offset, InitExpr))
117*12c85518Srobert return false;
118*12c85518Srobert
119*12c85518Srobert if (!this->emitPopPtr(InitExpr))
120*12c85518Srobert return false;
121*12c85518Srobert } else {
122*12c85518Srobert // Non-primitive case. Get a pointer to the field-to-initialize
123*12c85518Srobert // on the stack and call visitInitialzer() for it.
124*12c85518Srobert if (!this->emitThis(InitExpr))
125*12c85518Srobert return false;
126*12c85518Srobert
127*12c85518Srobert if (!this->emitGetPtrField(F->Offset, InitExpr))
128*12c85518Srobert return false;
129*12c85518Srobert
130*12c85518Srobert if (!this->visitInitializer(InitExpr))
131*12c85518Srobert return false;
132*12c85518Srobert
133*12c85518Srobert if (!this->emitPopPtr(InitExpr))
134*12c85518Srobert return false;
135*12c85518Srobert }
136*12c85518Srobert } else if (const Type *Base = Init->getBaseClass()) {
137*12c85518Srobert // Base class initializer.
138*12c85518Srobert // Get This Base and call initializer on it.
139*12c85518Srobert auto *BaseDecl = Base->getAsCXXRecordDecl();
140*12c85518Srobert assert(BaseDecl);
141*12c85518Srobert const Record::Base *B = R->getBase(BaseDecl);
142*12c85518Srobert assert(B);
143*12c85518Srobert if (!this->emitGetPtrThisBase(B->Offset, InitExpr))
144*12c85518Srobert return false;
145*12c85518Srobert if (!this->visitInitializer(InitExpr))
146*12c85518Srobert return false;
147*12c85518Srobert if (!this->emitPopPtr(InitExpr))
148*12c85518Srobert return false;
149*12c85518Srobert }
150*12c85518Srobert }
151*12c85518Srobert }
152*12c85518Srobert
153*12c85518Srobert if (const auto *Body = F->getBody())
154e5dd7070Spatrick if (!visitStmt(Body))
155e5dd7070Spatrick return false;
156e5dd7070Spatrick
157e5dd7070Spatrick // Emit a guard return to protect against a code path missing one.
158e5dd7070Spatrick if (F->getReturnType()->isVoidType())
159e5dd7070Spatrick return this->emitRetVoid(SourceInfo{});
160e5dd7070Spatrick else
161e5dd7070Spatrick return this->emitNoRet(SourceInfo{});
162e5dd7070Spatrick }
163e5dd7070Spatrick
164e5dd7070Spatrick template <class Emitter>
visitStmt(const Stmt * S)165e5dd7070Spatrick bool ByteCodeStmtGen<Emitter>::visitStmt(const Stmt *S) {
166e5dd7070Spatrick switch (S->getStmtClass()) {
167e5dd7070Spatrick case Stmt::CompoundStmtClass:
168e5dd7070Spatrick return visitCompoundStmt(cast<CompoundStmt>(S));
169e5dd7070Spatrick case Stmt::DeclStmtClass:
170e5dd7070Spatrick return visitDeclStmt(cast<DeclStmt>(S));
171e5dd7070Spatrick case Stmt::ReturnStmtClass:
172e5dd7070Spatrick return visitReturnStmt(cast<ReturnStmt>(S));
173e5dd7070Spatrick case Stmt::IfStmtClass:
174e5dd7070Spatrick return visitIfStmt(cast<IfStmt>(S));
175*12c85518Srobert case Stmt::WhileStmtClass:
176*12c85518Srobert return visitWhileStmt(cast<WhileStmt>(S));
177*12c85518Srobert case Stmt::DoStmtClass:
178*12c85518Srobert return visitDoStmt(cast<DoStmt>(S));
179*12c85518Srobert case Stmt::ForStmtClass:
180*12c85518Srobert return visitForStmt(cast<ForStmt>(S));
181*12c85518Srobert case Stmt::BreakStmtClass:
182*12c85518Srobert return visitBreakStmt(cast<BreakStmt>(S));
183*12c85518Srobert case Stmt::ContinueStmtClass:
184*12c85518Srobert return visitContinueStmt(cast<ContinueStmt>(S));
185e5dd7070Spatrick case Stmt::NullStmtClass:
186e5dd7070Spatrick return true;
187e5dd7070Spatrick default: {
188e5dd7070Spatrick if (auto *Exp = dyn_cast<Expr>(S))
189e5dd7070Spatrick return this->discard(Exp);
190e5dd7070Spatrick return this->bail(S);
191e5dd7070Spatrick }
192e5dd7070Spatrick }
193e5dd7070Spatrick }
194e5dd7070Spatrick
195e5dd7070Spatrick template <class Emitter>
visitCompoundStmt(const CompoundStmt * CompoundStmt)196e5dd7070Spatrick bool ByteCodeStmtGen<Emitter>::visitCompoundStmt(
197e5dd7070Spatrick const CompoundStmt *CompoundStmt) {
198e5dd7070Spatrick BlockScope<Emitter> Scope(this);
199e5dd7070Spatrick for (auto *InnerStmt : CompoundStmt->body())
200e5dd7070Spatrick if (!visitStmt(InnerStmt))
201e5dd7070Spatrick return false;
202e5dd7070Spatrick return true;
203e5dd7070Spatrick }
204e5dd7070Spatrick
205e5dd7070Spatrick template <class Emitter>
visitDeclStmt(const DeclStmt * DS)206e5dd7070Spatrick bool ByteCodeStmtGen<Emitter>::visitDeclStmt(const DeclStmt *DS) {
207e5dd7070Spatrick for (auto *D : DS->decls()) {
208e5dd7070Spatrick // Variable declarator.
209e5dd7070Spatrick if (auto *VD = dyn_cast<VarDecl>(D)) {
210*12c85518Srobert if (!this->visitVarDecl(VD))
211e5dd7070Spatrick return false;
212e5dd7070Spatrick continue;
213e5dd7070Spatrick }
214e5dd7070Spatrick
215e5dd7070Spatrick // Decomposition declarator.
216e5dd7070Spatrick if (auto *DD = dyn_cast<DecompositionDecl>(D)) {
217e5dd7070Spatrick return this->bail(DD);
218e5dd7070Spatrick }
219e5dd7070Spatrick }
220e5dd7070Spatrick
221e5dd7070Spatrick return true;
222e5dd7070Spatrick }
223e5dd7070Spatrick
224e5dd7070Spatrick template <class Emitter>
visitReturnStmt(const ReturnStmt * RS)225e5dd7070Spatrick bool ByteCodeStmtGen<Emitter>::visitReturnStmt(const ReturnStmt *RS) {
226e5dd7070Spatrick if (const Expr *RE = RS->getRetValue()) {
227e5dd7070Spatrick ExprScope<Emitter> RetScope(this);
228e5dd7070Spatrick if (ReturnType) {
229e5dd7070Spatrick // Primitive types are simply returned.
230e5dd7070Spatrick if (!this->visit(RE))
231e5dd7070Spatrick return false;
232e5dd7070Spatrick this->emitCleanup();
233e5dd7070Spatrick return this->emitRet(*ReturnType, RS);
234e5dd7070Spatrick } else {
235e5dd7070Spatrick // RVO - construct the value in the return location.
236*12c85518Srobert if (!this->emitRVOPtr(RE))
237e5dd7070Spatrick return false;
238*12c85518Srobert if (!this->visitInitializer(RE))
239*12c85518Srobert return false;
240*12c85518Srobert if (!this->emitPopPtr(RE))
241*12c85518Srobert return false;
242*12c85518Srobert
243e5dd7070Spatrick this->emitCleanup();
244e5dd7070Spatrick return this->emitRetVoid(RS);
245e5dd7070Spatrick }
246e5dd7070Spatrick }
247*12c85518Srobert
248*12c85518Srobert // Void return.
249*12c85518Srobert this->emitCleanup();
250*12c85518Srobert return this->emitRetVoid(RS);
251e5dd7070Spatrick }
252e5dd7070Spatrick
253e5dd7070Spatrick template <class Emitter>
visitIfStmt(const IfStmt * IS)254e5dd7070Spatrick bool ByteCodeStmtGen<Emitter>::visitIfStmt(const IfStmt *IS) {
255e5dd7070Spatrick BlockScope<Emitter> IfScope(this);
256*12c85518Srobert
257*12c85518Srobert if (IS->isNonNegatedConsteval())
258*12c85518Srobert return visitStmt(IS->getThen());
259*12c85518Srobert if (IS->isNegatedConsteval())
260*12c85518Srobert return IS->getElse() ? visitStmt(IS->getElse()) : true;
261*12c85518Srobert
262e5dd7070Spatrick if (auto *CondInit = IS->getInit())
263e5dd7070Spatrick if (!visitStmt(IS->getInit()))
264e5dd7070Spatrick return false;
265e5dd7070Spatrick
266e5dd7070Spatrick if (const DeclStmt *CondDecl = IS->getConditionVariableDeclStmt())
267e5dd7070Spatrick if (!visitDeclStmt(CondDecl))
268e5dd7070Spatrick return false;
269e5dd7070Spatrick
270e5dd7070Spatrick if (!this->visitBool(IS->getCond()))
271e5dd7070Spatrick return false;
272e5dd7070Spatrick
273e5dd7070Spatrick if (const Stmt *Else = IS->getElse()) {
274e5dd7070Spatrick LabelTy LabelElse = this->getLabel();
275e5dd7070Spatrick LabelTy LabelEnd = this->getLabel();
276e5dd7070Spatrick if (!this->jumpFalse(LabelElse))
277e5dd7070Spatrick return false;
278e5dd7070Spatrick if (!visitStmt(IS->getThen()))
279e5dd7070Spatrick return false;
280e5dd7070Spatrick if (!this->jump(LabelEnd))
281e5dd7070Spatrick return false;
282e5dd7070Spatrick this->emitLabel(LabelElse);
283e5dd7070Spatrick if (!visitStmt(Else))
284e5dd7070Spatrick return false;
285e5dd7070Spatrick this->emitLabel(LabelEnd);
286e5dd7070Spatrick } else {
287e5dd7070Spatrick LabelTy LabelEnd = this->getLabel();
288e5dd7070Spatrick if (!this->jumpFalse(LabelEnd))
289e5dd7070Spatrick return false;
290e5dd7070Spatrick if (!visitStmt(IS->getThen()))
291e5dd7070Spatrick return false;
292e5dd7070Spatrick this->emitLabel(LabelEnd);
293e5dd7070Spatrick }
294e5dd7070Spatrick
295e5dd7070Spatrick return true;
296e5dd7070Spatrick }
297e5dd7070Spatrick
298e5dd7070Spatrick template <class Emitter>
visitWhileStmt(const WhileStmt * S)299*12c85518Srobert bool ByteCodeStmtGen<Emitter>::visitWhileStmt(const WhileStmt *S) {
300*12c85518Srobert const Expr *Cond = S->getCond();
301*12c85518Srobert const Stmt *Body = S->getBody();
302e5dd7070Spatrick
303*12c85518Srobert LabelTy CondLabel = this->getLabel(); // Label before the condition.
304*12c85518Srobert LabelTy EndLabel = this->getLabel(); // Label after the loop.
305*12c85518Srobert LoopScope<Emitter> LS(this, EndLabel, CondLabel);
306*12c85518Srobert
307*12c85518Srobert this->emitLabel(CondLabel);
308*12c85518Srobert if (!this->visitBool(Cond))
309*12c85518Srobert return false;
310*12c85518Srobert if (!this->jumpFalse(EndLabel))
311*12c85518Srobert return false;
312*12c85518Srobert
313*12c85518Srobert if (!this->visitStmt(Body))
314*12c85518Srobert return false;
315*12c85518Srobert if (!this->jump(CondLabel))
316*12c85518Srobert return false;
317*12c85518Srobert
318*12c85518Srobert this->emitLabel(EndLabel);
319*12c85518Srobert
320e5dd7070Spatrick return true;
321e5dd7070Spatrick }
322e5dd7070Spatrick
323*12c85518Srobert template <class Emitter>
visitDoStmt(const DoStmt * S)324*12c85518Srobert bool ByteCodeStmtGen<Emitter>::visitDoStmt(const DoStmt *S) {
325*12c85518Srobert const Expr *Cond = S->getCond();
326*12c85518Srobert const Stmt *Body = S->getBody();
327*12c85518Srobert
328*12c85518Srobert LabelTy StartLabel = this->getLabel();
329*12c85518Srobert LabelTy EndLabel = this->getLabel();
330*12c85518Srobert LabelTy CondLabel = this->getLabel();
331*12c85518Srobert LoopScope<Emitter> LS(this, EndLabel, CondLabel);
332*12c85518Srobert
333*12c85518Srobert this->emitLabel(StartLabel);
334*12c85518Srobert if (!this->visitStmt(Body))
335*12c85518Srobert return false;
336*12c85518Srobert this->emitLabel(CondLabel);
337*12c85518Srobert if (!this->visitBool(Cond))
338*12c85518Srobert return false;
339*12c85518Srobert if (!this->jumpTrue(StartLabel))
340*12c85518Srobert return false;
341*12c85518Srobert this->emitLabel(EndLabel);
342*12c85518Srobert return true;
343*12c85518Srobert }
344*12c85518Srobert
345*12c85518Srobert template <class Emitter>
visitForStmt(const ForStmt * S)346*12c85518Srobert bool ByteCodeStmtGen<Emitter>::visitForStmt(const ForStmt *S) {
347*12c85518Srobert // for (Init; Cond; Inc) { Body }
348*12c85518Srobert const Stmt *Init = S->getInit();
349*12c85518Srobert const Expr *Cond = S->getCond();
350*12c85518Srobert const Expr *Inc = S->getInc();
351*12c85518Srobert const Stmt *Body = S->getBody();
352*12c85518Srobert
353*12c85518Srobert LabelTy EndLabel = this->getLabel();
354*12c85518Srobert LabelTy CondLabel = this->getLabel();
355*12c85518Srobert LabelTy IncLabel = this->getLabel();
356*12c85518Srobert LoopScope<Emitter> LS(this, EndLabel, IncLabel);
357*12c85518Srobert
358*12c85518Srobert if (Init && !this->visitStmt(Init))
359*12c85518Srobert return false;
360*12c85518Srobert this->emitLabel(CondLabel);
361*12c85518Srobert if (Cond) {
362*12c85518Srobert if (!this->visitBool(Cond))
363*12c85518Srobert return false;
364*12c85518Srobert if (!this->jumpFalse(EndLabel))
365e5dd7070Spatrick return false;
366e5dd7070Spatrick }
367*12c85518Srobert if (Body && !this->visitStmt(Body))
368*12c85518Srobert return false;
369*12c85518Srobert this->emitLabel(IncLabel);
370*12c85518Srobert if (Inc && !this->discard(Inc))
371*12c85518Srobert return false;
372*12c85518Srobert if (!this->jump(CondLabel))
373*12c85518Srobert return false;
374*12c85518Srobert this->emitLabel(EndLabel);
375*12c85518Srobert return true;
376e5dd7070Spatrick }
377*12c85518Srobert
378*12c85518Srobert template <class Emitter>
visitBreakStmt(const BreakStmt * S)379*12c85518Srobert bool ByteCodeStmtGen<Emitter>::visitBreakStmt(const BreakStmt *S) {
380*12c85518Srobert if (!BreakLabel)
381*12c85518Srobert return false;
382*12c85518Srobert
383*12c85518Srobert return this->jump(*BreakLabel);
384e5dd7070Spatrick }
385*12c85518Srobert
386*12c85518Srobert template <class Emitter>
visitContinueStmt(const ContinueStmt * S)387*12c85518Srobert bool ByteCodeStmtGen<Emitter>::visitContinueStmt(const ContinueStmt *S) {
388*12c85518Srobert if (!ContinueLabel)
389*12c85518Srobert return false;
390*12c85518Srobert
391*12c85518Srobert return this->jump(*ContinueLabel);
392e5dd7070Spatrick }
393e5dd7070Spatrick
394e5dd7070Spatrick namespace clang {
395e5dd7070Spatrick namespace interp {
396e5dd7070Spatrick
397e5dd7070Spatrick template class ByteCodeStmtGen<ByteCodeEmitter>;
398e5dd7070Spatrick
399e5dd7070Spatrick } // namespace interp
400e5dd7070Spatrick } // namespace clang
401