1353942Sdim//===--- ByteCodeStmtGen.cpp - Code generator for expressions ---*- C++ -*-===//
2353942Sdim//
3353942Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353942Sdim// See https://llvm.org/LICENSE.txt for license information.
5353942Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6353942Sdim//
7353942Sdim//===----------------------------------------------------------------------===//
8353942Sdim
9353942Sdim#include "ByteCodeStmtGen.h"
10353942Sdim#include "ByteCodeEmitter.h"
11353942Sdim#include "ByteCodeGenError.h"
12353942Sdim#include "Context.h"
13353942Sdim#include "Function.h"
14353942Sdim#include "PrimType.h"
15353942Sdim#include "Program.h"
16353942Sdim#include "State.h"
17357095Sdim#include "clang/Basic/LLVM.h"
18353942Sdim
19353942Sdimusing namespace clang;
20353942Sdimusing namespace clang::interp;
21353942Sdim
22353942Sdimnamespace clang {
23353942Sdimnamespace interp {
24353942Sdim
25353942Sdim/// Scope managing label targets.
26353942Sdimtemplate <class Emitter> class LabelScope {
27353942Sdimpublic:
28353942Sdim  virtual ~LabelScope() {  }
29353942Sdim
30353942Sdimprotected:
31353942Sdim  LabelScope(ByteCodeStmtGen<Emitter> *Ctx) : Ctx(Ctx) {}
32353942Sdim  /// ByteCodeStmtGen instance.
33353942Sdim  ByteCodeStmtGen<Emitter> *Ctx;
34353942Sdim};
35353942Sdim
36353942Sdim/// Sets the context for break/continue statements.
37353942Sdimtemplate <class Emitter> class LoopScope final : public LabelScope<Emitter> {
38353942Sdimpublic:
39353942Sdim  using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy;
40353942Sdim  using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy;
41353942Sdim
42353942Sdim  LoopScope(ByteCodeStmtGen<Emitter> *Ctx, LabelTy BreakLabel,
43353942Sdim            LabelTy ContinueLabel)
44353942Sdim      : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
45353942Sdim        OldContinueLabel(Ctx->ContinueLabel) {
46353942Sdim    this->Ctx->BreakLabel = BreakLabel;
47353942Sdim    this->Ctx->ContinueLabel = ContinueLabel;
48353942Sdim  }
49353942Sdim
50353942Sdim  ~LoopScope() {
51353942Sdim    this->Ctx->BreakLabel = OldBreakLabel;
52353942Sdim    this->Ctx->ContinueLabel = OldContinueLabel;
53353942Sdim  }
54353942Sdim
55353942Sdimprivate:
56353942Sdim  OptLabelTy OldBreakLabel;
57353942Sdim  OptLabelTy OldContinueLabel;
58353942Sdim};
59353942Sdim
60353942Sdim// Sets the context for a switch scope, mapping labels.
61353942Sdimtemplate <class Emitter> class SwitchScope final : public LabelScope<Emitter> {
62353942Sdimpublic:
63353942Sdim  using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy;
64353942Sdim  using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy;
65353942Sdim  using CaseMap = typename ByteCodeStmtGen<Emitter>::CaseMap;
66353942Sdim
67353942Sdim  SwitchScope(ByteCodeStmtGen<Emitter> *Ctx, CaseMap &&CaseLabels,
68353942Sdim              LabelTy BreakLabel, OptLabelTy DefaultLabel)
69353942Sdim      : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
70353942Sdim        OldDefaultLabel(this->Ctx->DefaultLabel),
71353942Sdim        OldCaseLabels(std::move(this->Ctx->CaseLabels)) {
72353942Sdim    this->Ctx->BreakLabel = BreakLabel;
73353942Sdim    this->Ctx->DefaultLabel = DefaultLabel;
74353942Sdim    this->Ctx->CaseLabels = std::move(CaseLabels);
75353942Sdim  }
76353942Sdim
77353942Sdim  ~SwitchScope() {
78353942Sdim    this->Ctx->BreakLabel = OldBreakLabel;
79353942Sdim    this->Ctx->DefaultLabel = OldDefaultLabel;
80353942Sdim    this->Ctx->CaseLabels = std::move(OldCaseLabels);
81353942Sdim  }
82353942Sdim
83353942Sdimprivate:
84353942Sdim  OptLabelTy OldBreakLabel;
85353942Sdim  OptLabelTy OldDefaultLabel;
86353942Sdim  CaseMap OldCaseLabels;
87353942Sdim};
88353942Sdim
89353942Sdim} // namespace interp
90353942Sdim} // namespace clang
91353942Sdim
92353942Sdimtemplate <class Emitter>
93353942Sdimbool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
94353942Sdim  // Classify the return type.
95353942Sdim  ReturnType = this->classify(F->getReturnType());
96353942Sdim
97353942Sdim  // Set up fields and context if a constructor.
98353942Sdim  if (auto *MD = dyn_cast<CXXMethodDecl>(F))
99353942Sdim    return this->bail(MD);
100353942Sdim
101353942Sdim  if (auto *Body = F->getBody())
102353942Sdim    if (!visitStmt(Body))
103353942Sdim      return false;
104353942Sdim
105353942Sdim  // Emit a guard return to protect against a code path missing one.
106353942Sdim  if (F->getReturnType()->isVoidType())
107353942Sdim    return this->emitRetVoid(SourceInfo{});
108353942Sdim  else
109353942Sdim    return this->emitNoRet(SourceInfo{});
110353942Sdim}
111353942Sdim
112353942Sdimtemplate <class Emitter>
113353942Sdimbool ByteCodeStmtGen<Emitter>::visitStmt(const Stmt *S) {
114353942Sdim  switch (S->getStmtClass()) {
115353942Sdim  case Stmt::CompoundStmtClass:
116353942Sdim    return visitCompoundStmt(cast<CompoundStmt>(S));
117353942Sdim  case Stmt::DeclStmtClass:
118353942Sdim    return visitDeclStmt(cast<DeclStmt>(S));
119353942Sdim  case Stmt::ReturnStmtClass:
120353942Sdim    return visitReturnStmt(cast<ReturnStmt>(S));
121353942Sdim  case Stmt::IfStmtClass:
122353942Sdim    return visitIfStmt(cast<IfStmt>(S));
123353942Sdim  case Stmt::NullStmtClass:
124353942Sdim    return true;
125353942Sdim  default: {
126353942Sdim    if (auto *Exp = dyn_cast<Expr>(S))
127353942Sdim      return this->discard(Exp);
128353942Sdim    return this->bail(S);
129353942Sdim  }
130353942Sdim  }
131353942Sdim}
132353942Sdim
133353942Sdimtemplate <class Emitter>
134353942Sdimbool ByteCodeStmtGen<Emitter>::visitCompoundStmt(
135353942Sdim    const CompoundStmt *CompoundStmt) {
136353942Sdim  BlockScope<Emitter> Scope(this);
137353942Sdim  for (auto *InnerStmt : CompoundStmt->body())
138353942Sdim    if (!visitStmt(InnerStmt))
139353942Sdim      return false;
140353942Sdim  return true;
141353942Sdim}
142353942Sdim
143353942Sdimtemplate <class Emitter>
144353942Sdimbool ByteCodeStmtGen<Emitter>::visitDeclStmt(const DeclStmt *DS) {
145353942Sdim  for (auto *D : DS->decls()) {
146353942Sdim    // Variable declarator.
147353942Sdim    if (auto *VD = dyn_cast<VarDecl>(D)) {
148353942Sdim      if (!visitVarDecl(VD))
149353942Sdim        return false;
150353942Sdim      continue;
151353942Sdim    }
152353942Sdim
153353942Sdim    // Decomposition declarator.
154353942Sdim    if (auto *DD = dyn_cast<DecompositionDecl>(D)) {
155353942Sdim      return this->bail(DD);
156353942Sdim    }
157353942Sdim  }
158353942Sdim
159353942Sdim  return true;
160353942Sdim}
161353942Sdim
162353942Sdimtemplate <class Emitter>
163353942Sdimbool ByteCodeStmtGen<Emitter>::visitReturnStmt(const ReturnStmt *RS) {
164353942Sdim  if (const Expr *RE = RS->getRetValue()) {
165353942Sdim    ExprScope<Emitter> RetScope(this);
166353942Sdim    if (ReturnType) {
167353942Sdim      // Primitive types are simply returned.
168353942Sdim      if (!this->visit(RE))
169353942Sdim        return false;
170353942Sdim      this->emitCleanup();
171353942Sdim      return this->emitRet(*ReturnType, RS);
172353942Sdim    } else {
173353942Sdim      // RVO - construct the value in the return location.
174353942Sdim      auto ReturnLocation = [this, RE] { return this->emitGetParamPtr(0, RE); };
175353942Sdim      if (!this->visitInitializer(RE, ReturnLocation))
176353942Sdim        return false;
177353942Sdim      this->emitCleanup();
178353942Sdim      return this->emitRetVoid(RS);
179353942Sdim    }
180353942Sdim  } else {
181353942Sdim    this->emitCleanup();
182353942Sdim    if (!this->emitRetVoid(RS))
183353942Sdim      return false;
184353942Sdim    return true;
185353942Sdim  }
186353942Sdim}
187353942Sdim
188353942Sdimtemplate <class Emitter>
189353942Sdimbool ByteCodeStmtGen<Emitter>::visitIfStmt(const IfStmt *IS) {
190353942Sdim  BlockScope<Emitter> IfScope(this);
191353942Sdim  if (auto *CondInit = IS->getInit())
192353942Sdim    if (!visitStmt(IS->getInit()))
193353942Sdim      return false;
194353942Sdim
195353942Sdim  if (const DeclStmt *CondDecl = IS->getConditionVariableDeclStmt())
196353942Sdim    if (!visitDeclStmt(CondDecl))
197353942Sdim      return false;
198353942Sdim
199353942Sdim  if (!this->visitBool(IS->getCond()))
200353942Sdim    return false;
201353942Sdim
202353942Sdim  if (const Stmt *Else = IS->getElse()) {
203353942Sdim    LabelTy LabelElse = this->getLabel();
204353942Sdim    LabelTy LabelEnd = this->getLabel();
205353942Sdim    if (!this->jumpFalse(LabelElse))
206353942Sdim      return false;
207353942Sdim    if (!visitStmt(IS->getThen()))
208353942Sdim      return false;
209353942Sdim    if (!this->jump(LabelEnd))
210353942Sdim      return false;
211353942Sdim    this->emitLabel(LabelElse);
212353942Sdim    if (!visitStmt(Else))
213353942Sdim      return false;
214353942Sdim    this->emitLabel(LabelEnd);
215353942Sdim  } else {
216353942Sdim    LabelTy LabelEnd = this->getLabel();
217353942Sdim    if (!this->jumpFalse(LabelEnd))
218353942Sdim      return false;
219353942Sdim    if (!visitStmt(IS->getThen()))
220353942Sdim      return false;
221353942Sdim    this->emitLabel(LabelEnd);
222353942Sdim  }
223353942Sdim
224353942Sdim  return true;
225353942Sdim}
226353942Sdim
227353942Sdimtemplate <class Emitter>
228353942Sdimbool ByteCodeStmtGen<Emitter>::visitVarDecl(const VarDecl *VD) {
229353942Sdim  auto DT = VD->getType();
230353942Sdim
231353942Sdim  if (!VD->hasLocalStorage()) {
232353942Sdim    // No code generation required.
233353942Sdim    return true;
234353942Sdim  }
235353942Sdim
236353942Sdim  // Integers, pointers, primitives.
237353942Sdim  if (Optional<PrimType> T = this->classify(DT)) {
238353942Sdim    auto Off = this->allocateLocalPrimitive(VD, *T, DT.isConstQualified());
239353942Sdim    // Compile the initialiser in its own scope.
240353942Sdim    {
241353942Sdim      ExprScope<Emitter> Scope(this);
242353942Sdim      if (!this->visit(VD->getInit()))
243353942Sdim        return false;
244353942Sdim    }
245353942Sdim    // Set the value.
246353942Sdim    return this->emitSetLocal(*T, Off, VD);
247353942Sdim  } else {
248353942Sdim    // Composite types - allocate storage and initialize it.
249353942Sdim    if (auto Off = this->allocateLocal(VD)) {
250353942Sdim      return this->visitLocalInitializer(VD->getInit(), *Off);
251353942Sdim    } else {
252353942Sdim      return this->bail(VD);
253353942Sdim    }
254353942Sdim  }
255353942Sdim}
256353942Sdim
257353942Sdimnamespace clang {
258353942Sdimnamespace interp {
259353942Sdim
260353942Sdimtemplate class ByteCodeStmtGen<ByteCodeEmitter>;
261353942Sdim
262353942Sdim} // namespace interp
263353942Sdim} // namespace clang
264