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
19using namespace clang;
20using namespace clang::interp;
21
22namespace clang {
23namespace interp {
24
25/// Scope managing label targets.
26template <class Emitter> class LabelScope {
27public:
28  virtual ~LabelScope() {  }
29
30protected:
31  LabelScope(ByteCodeStmtGen<Emitter> *Ctx) : Ctx(Ctx) {}
32  /// ByteCodeStmtGen instance.
33  ByteCodeStmtGen<Emitter> *Ctx;
34};
35
36/// Sets the context for break/continue statements.
37template <class Emitter> class LoopScope final : public LabelScope<Emitter> {
38public:
39  using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy;
40  using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy;
41
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
50  ~LoopScope() {
51    this->Ctx->BreakLabel = OldBreakLabel;
52    this->Ctx->ContinueLabel = OldContinueLabel;
53  }
54
55private:
56  OptLabelTy OldBreakLabel;
57  OptLabelTy OldContinueLabel;
58};
59
60// Sets the context for a switch scope, mapping labels.
61template <class Emitter> class SwitchScope final : public LabelScope<Emitter> {
62public:
63  using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy;
64  using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy;
65  using CaseMap = typename ByteCodeStmtGen<Emitter>::CaseMap;
66
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
77  ~SwitchScope() {
78    this->Ctx->BreakLabel = OldBreakLabel;
79    this->Ctx->DefaultLabel = OldDefaultLabel;
80    this->Ctx->CaseLabels = std::move(OldCaseLabels);
81  }
82
83private:
84  OptLabelTy OldBreakLabel;
85  OptLabelTy OldDefaultLabel;
86  CaseMap OldCaseLabels;
87};
88
89} // namespace interp
90} // namespace clang
91
92template <class Emitter>
93bool 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
112template <class Emitter>
113bool 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
133template <class Emitter>
134bool 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
143template <class Emitter>
144bool 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
162template <class Emitter>
163bool 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
188template <class Emitter>
189bool ByteCodeStmtGen<Emitter>::visitIfStmt(const IfStmt *IS) {
190  BlockScope<Emitter> IfScope(this);
191  if (auto *CondInit = IS->getInit())
192    if (!visitStmt(IS->getInit()))
193      return false;
194
195  if (const DeclStmt *CondDecl = IS->getConditionVariableDeclStmt())
196    if (!visitDeclStmt(CondDecl))
197      return false;
198
199  if (!this->visitBool(IS->getCond()))
200    return false;
201
202  if (const Stmt *Else = IS->getElse()) {
203    LabelTy LabelElse = this->getLabel();
204    LabelTy LabelEnd = this->getLabel();
205    if (!this->jumpFalse(LabelElse))
206      return false;
207    if (!visitStmt(IS->getThen()))
208      return false;
209    if (!this->jump(LabelEnd))
210      return false;
211    this->emitLabel(LabelElse);
212    if (!visitStmt(Else))
213      return false;
214    this->emitLabel(LabelEnd);
215  } else {
216    LabelTy LabelEnd = this->getLabel();
217    if (!this->jumpFalse(LabelEnd))
218      return false;
219    if (!visitStmt(IS->getThen()))
220      return false;
221    this->emitLabel(LabelEnd);
222  }
223
224  return true;
225}
226
227template <class Emitter>
228bool ByteCodeStmtGen<Emitter>::visitVarDecl(const VarDecl *VD) {
229  auto DT = VD->getType();
230
231  if (!VD->hasLocalStorage()) {
232    // No code generation required.
233    return true;
234  }
235
236  // Integers, pointers, primitives.
237  if (Optional<PrimType> T = this->classify(DT)) {
238    auto Off = this->allocateLocalPrimitive(VD, *T, DT.isConstQualified());
239    // Compile the initialiser in its own scope.
240    {
241      ExprScope<Emitter> Scope(this);
242      if (!this->visit(VD->getInit()))
243        return false;
244    }
245    // Set the value.
246    return this->emitSetLocal(*T, Off, VD);
247  } else {
248    // Composite types - allocate storage and initialize it.
249    if (auto Off = this->allocateLocal(VD)) {
250      return this->visitLocalInitializer(VD->getInit(), *Off);
251    } else {
252      return this->bail(VD);
253    }
254  }
255}
256
257namespace clang {
258namespace interp {
259
260template class ByteCodeStmtGen<ByteCodeEmitter>;
261
262} // namespace interp
263} // namespace clang
264