clang  14.0.0git
ByteCodeStmtGen.cpp
Go to the documentation of this file.
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:
28  virtual ~LabelScope() { }
29 
30 protected:
32  /// ByteCodeStmtGen instance.
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;
41 
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 
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;
65  using CaseMap = typename ByteCodeStmtGen<Emitter>::CaseMap;
66 
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 
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>
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>
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>
135  const CompoundStmt *CompoundStmt) {
137  for (auto *InnerStmt : CompoundStmt->body())
138  if (!visitStmt(InnerStmt))
139  return false;
140  return true;
141 }
142 
143 template <class Emitter>
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>
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>
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>
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  {
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
clang::interp::LabelScope::LabelScope
LabelScope(ByteCodeStmtGen< Emitter > *Ctx)
Definition: ByteCodeStmtGen.cpp:31
clang::interp::SwitchScope::~SwitchScope
~SwitchScope()
Definition: ByteCodeStmtGen.cpp:77
clang::ReturnStmt::getRetValue
Expr * getRetValue()
Definition: Stmt.h:2793
clang::interp::SwitchScope::LabelTy
typename ByteCodeStmtGen< Emitter >::LabelTy LabelTy
Definition: ByteCodeStmtGen.cpp:63
clang::FunctionDecl::getReturnType
QualType getReturnType() const
Definition: Decl.h:2537
clang::interp::SwitchScope::OptLabelTy
typename ByteCodeStmtGen< Emitter >::OptLabelTy OptLabelTy
Definition: ByteCodeStmtGen.cpp:64
clang::interp::ExprScope
Expression scope which tracks potentially lifetime extended temporaries which are hoisted to the pare...
Definition: ByteCodeExprGen.h:320
clang::interp::SwitchScope::CaseMap
typename ByteCodeStmtGen< Emitter >::CaseMap CaseMap
Definition: ByteCodeStmtGen.cpp:65
clang::interp::ByteCodeStmtGen
Compilation context for statements.
Definition: ByteCodeStmtGen.h:40
clang::interp::LoopScope::LabelTy
typename ByteCodeStmtGen< Emitter >::LabelTy LabelTy
Definition: ByteCodeStmtGen.cpp:39
clang::IfStmt
IfStmt - This represents an if/then/else.
Definition: Stmt.h:1904
llvm::Optional< LabelTy >
clang::Type::isVoidType
bool isVoidType() const
Definition: Type.h:6955
clang::interp::LoopScope::LoopScope
LoopScope(ByteCodeStmtGen< Emitter > *Ctx, LabelTy BreakLabel, LabelTy ContinueLabel)
Definition: ByteCodeStmtGen.cpp:42
clang::interp::SwitchScope
Definition: ByteCodeStmtGen.cpp:61
ByteCodeStmtGen.h
clang::interp
Definition: ASTContext.h:158
clang::CompoundStmt
CompoundStmt - This represents a group of statements like { stmt stmt }.
Definition: Stmt.h:1399
clang::Scope
Scope - A scope is a transient data structure that is used while parsing the program.
Definition: Scope.h:40
clang::IfStmt::isNonNegatedConsteval
bool isNonNegatedConsteval() const
Definition: Stmt.h:2086
clang::FunctionDecl::getBody
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
Definition: Decl.cpp:3035
clang::IfStmt::getConditionVariableDeclStmt
DeclStmt * getConditionVariableDeclStmt()
If this IfStmt has a condition variable, return the faux DeclStmt associated with the creation of tha...
Definition: Stmt.h:2039
clang::interp::BlockScope
Scope for storage declared in a compound statement.
Definition: ByteCodeExprGen.h:309
clang::VarDecl
Represents a variable declaration or definition.
Definition: Decl.h:876
PrimType.h
clang::IfStmt::getElse
Stmt * getElse()
Definition: Stmt.h:2004
clang::interp::SourceInfo
Describes the statement/declaration an opcode was generated from.
Definition: Source.h:66
Emitter
clang::interp::LoopScope::OptLabelTy
typename ByteCodeStmtGen< Emitter >::OptLabelTy OptLabelTy
Definition: ByteCodeStmtGen.cpp:40
clang::interp::LabelScope::Ctx
ByteCodeStmtGen< Emitter > * Ctx
ByteCodeStmtGen instance.
Definition: ByteCodeStmtGen.cpp:33
clang::interp::LabelScope
Scope managing label targets.
Definition: ByteCodeStmtGen.cpp:26
clang::interp::LoopScope
Sets the context for break/continue statements.
Definition: ByteCodeStmtGen.cpp:37
clang::interp::LoopScope::~LoopScope
~LoopScope()
Definition: ByteCodeStmtGen.cpp:50
clang::IfStmt::isNegatedConsteval
bool isNegatedConsteval() const
Definition: Stmt.h:2090
clang::interp::ByteCodeStmtGen::visitFunc
bool visitFunc(const FunctionDecl *F) override
Definition: ByteCodeStmtGen.cpp:93
LLVM.h
clang::VarDecl::getInit
const Expr * getInit() const
Definition: Decl.h:1285
clang::IfStmt::getInit
Stmt * getInit()
Definition: Stmt.h:2051
clang::DeclStmt
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Definition: Stmt.h:1292
clang::IfStmt::getCond
Expr * getCond()
Definition: Stmt.h:1983
std
Definition: Format.h:4034
clang
Definition: CalledOnceCheck.h:17
Function.h
clang::Stmt
Stmt - This represents one statement.
Definition: Stmt.h:69
clang::interp::LabelScope::~LabelScope
virtual ~LabelScope()
Definition: ByteCodeStmtGen.cpp:28
clang::DeclStmt::decls
decl_range decls()
Definition: Stmt.h:1340
clang::IfStmt::getThen
Stmt * getThen()
Definition: Stmt.h:1995
ByteCodeEmitter.h
clang::CompoundStmt::body
body_range body()
Definition: Stmt.h:1432
State.h
clang::interp::SwitchScope::SwitchScope
SwitchScope(ByteCodeStmtGen< Emitter > *Ctx, CaseMap &&CaseLabels, LabelTy BreakLabel, OptLabelTy DefaultLabel)
Definition: ByteCodeStmtGen.cpp:67
Program.h
clang::ValueDecl::getType
QualType getType() const
Definition: Decl.h:687
true
#define true
Definition: stdbool.h:16
clang::Expr
This represents one expression.
Definition: Expr.h:109
clang::VarDecl::hasLocalStorage
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
Definition: Decl.h:1101
ByteCodeGenError.h
clang::FunctionDecl
Represents a function declaration or definition.
Definition: Decl.h:1856
Context.h
clang::ReturnStmt
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition: Stmt.h:2760