xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/AST/Interp/ByteCodeStmtGen.cpp (revision 181254a7b1bdde6873432bffef2d2decc4b5c22f)
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 
18 using namespace clang;
19 using namespace clang::interp;
20 
21 template <typename T> using Expected = llvm::Expected<T>;
22 template <typename T> using Optional = llvm::Optional<T>;
23 
24 namespace clang {
25 namespace interp {
26 
27 /// Scope managing label targets.
28 template <class Emitter> class LabelScope {
29 public:
30   virtual ~LabelScope() {  }
31 
32 protected:
33   LabelScope(ByteCodeStmtGen<Emitter> *Ctx) : Ctx(Ctx) {}
34   /// ByteCodeStmtGen instance.
35   ByteCodeStmtGen<Emitter> *Ctx;
36 };
37 
38 /// Sets the context for break/continue statements.
39 template <class Emitter> class LoopScope final : public LabelScope<Emitter> {
40 public:
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 
57 private:
58   OptLabelTy OldBreakLabel;
59   OptLabelTy OldContinueLabel;
60 };
61 
62 // Sets the context for a switch scope, mapping labels.
63 template <class Emitter> class SwitchScope final : public LabelScope<Emitter> {
64 public:
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 
85 private:
86   OptLabelTy OldBreakLabel;
87   OptLabelTy OldDefaultLabel;
88   CaseMap OldCaseLabels;
89 };
90 
91 } // namespace interp
92 } // namespace clang
93 
94 template <class Emitter>
95 bool 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 
114 template <class Emitter>
115 bool 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 
135 template <class Emitter>
136 bool 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 
145 template <class Emitter>
146 bool 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 
164 template <class Emitter>
165 bool 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 
190 template <class Emitter>
191 bool 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 
229 template <class Emitter>
230 bool 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 
259 namespace clang {
260 namespace interp {
261 
262 template class ByteCodeStmtGen<ByteCodeEmitter>;
263 
264 } // namespace interp
265 } // namespace clang
266