1//===--- ByteCodeExprGen.h - 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// Defines the constexpr bytecode compiler.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H
14#define LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H
15
16#include "ByteCodeEmitter.h"
17#include "EvalEmitter.h"
18#include "Pointer.h"
19#include "PrimType.h"
20#include "Record.h"
21#include "clang/AST/Decl.h"
22#include "clang/AST/Expr.h"
23#include "clang/AST/StmtVisitor.h"
24#include "clang/Basic/TargetInfo.h"
25
26namespace clang {
27class QualType;
28
29namespace interp {
30
31template <class Emitter> class LocalScope;
32template <class Emitter> class DestructorScope;
33template <class Emitter> class VariableScope;
34template <class Emitter> class DeclScope;
35template <class Emitter> class OptionScope;
36template <class Emitter> class ArrayIndexScope;
37template <class Emitter> class SourceLocScope;
38
39/// Compilation context for expressions.
40template <class Emitter>
41class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
42 public Emitter {
43protected:
44 // Aliases for types defined in the emitter.
45 using LabelTy = typename Emitter::LabelTy;
46 using AddrTy = typename Emitter::AddrTy;
47
48 /// Current compilation context.
49 Context &Ctx;
50 /// Program to link to.
51 Program &P;
52
53public:
54 /// Initializes the compiler and the backend emitter.
55 template <typename... Tys>
56 ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args)
57 : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}
58
59 // Expression visitors - result returned on interp stack.
60 bool VisitCastExpr(const CastExpr *E);
61 bool VisitIntegerLiteral(const IntegerLiteral *E);
62 bool VisitFloatingLiteral(const FloatingLiteral *E);
63 bool VisitImaginaryLiteral(const ImaginaryLiteral *E);
64 bool VisitParenExpr(const ParenExpr *E);
65 bool VisitBinaryOperator(const BinaryOperator *E);
66 bool VisitLogicalBinOp(const BinaryOperator *E);
67 bool VisitPointerArithBinOp(const BinaryOperator *E);
68 bool VisitComplexBinOp(const BinaryOperator *E);
69 bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);
70 bool VisitCallExpr(const CallExpr *E);
71 bool VisitBuiltinCallExpr(const CallExpr *E);
72 bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E);
73 bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E);
74 bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);
75 bool VisitGNUNullExpr(const GNUNullExpr *E);
76 bool VisitCXXThisExpr(const CXXThisExpr *E);
77 bool VisitUnaryOperator(const UnaryOperator *E);
78 bool VisitComplexUnaryOperator(const UnaryOperator *E);
79 bool VisitDeclRefExpr(const DeclRefExpr *E);
80 bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
81 bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E);
82 bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
83 bool VisitInitListExpr(const InitListExpr *E);
84 bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
85 bool VisitConstantExpr(const ConstantExpr *E);
86 bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
87 bool VisitMemberExpr(const MemberExpr *E);
88 bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E);
89 bool VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E);
90 bool VisitOpaqueValueExpr(const OpaqueValueExpr *E);
91 bool VisitAbstractConditionalOperator(const AbstractConditionalOperator *E);
92 bool VisitStringLiteral(const StringLiteral *E);
93 bool VisitCharacterLiteral(const CharacterLiteral *E);
94 bool VisitCompoundAssignOperator(const CompoundAssignOperator *E);
95 bool VisitFloatCompoundAssignOperator(const CompoundAssignOperator *E);
96 bool VisitPointerCompoundAssignOperator(const CompoundAssignOperator *E);
97 bool VisitExprWithCleanups(const ExprWithCleanups *E);
98 bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
99 bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *E);
100 bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
101 bool VisitTypeTraitExpr(const TypeTraitExpr *E);
102 bool VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E);
103 bool VisitLambdaExpr(const LambdaExpr *E);
104 bool VisitPredefinedExpr(const PredefinedExpr *E);
105 bool VisitCXXThrowExpr(const CXXThrowExpr *E);
106 bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E);
107 bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E);
108 bool VisitCXXConstructExpr(const CXXConstructExpr *E);
109 bool VisitSourceLocExpr(const SourceLocExpr *E);
110 bool VisitOffsetOfExpr(const OffsetOfExpr *E);
111 bool VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E);
112 bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);
113 bool VisitGenericSelectionExpr(const GenericSelectionExpr *E);
114 bool VisitChooseExpr(const ChooseExpr *E);
115 bool VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *E);
116 bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
117 bool VisitExpressionTraitExpr(const ExpressionTraitExpr *E);
118 bool VisitCXXUuidofExpr(const CXXUuidofExpr *E);
119 bool VisitRequiresExpr(const RequiresExpr *E);
120 bool VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E);
121 bool VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *E);
122 bool VisitPseudoObjectExpr(const PseudoObjectExpr *E);
123 bool VisitPackIndexingExpr(const PackIndexingExpr *E);
124
125protected:
126 bool visitExpr(const Expr *E) override;
127 bool visitDecl(const VarDecl *VD) override;
128
129protected:
130 /// Emits scope cleanup instructions.
131 void emitCleanup();
132
133 /// Returns a record type from a record or pointer type.
134 const RecordType *getRecordTy(QualType Ty);
135
136 /// Returns a record from a record or pointer type.
137 Record *getRecord(QualType Ty);
138 Record *getRecord(const RecordDecl *RD);
139
140 // Returns a function for the given FunctionDecl.
141 // If the function does not exist yet, it is compiled.
142 const Function *getFunction(const FunctionDecl *FD);
143
144 std::optional<PrimType> classify(const Expr *E) const {
145 return Ctx.classify(E);
146 }
147 std::optional<PrimType> classify(QualType Ty) const {
148 return Ctx.classify(T: Ty);
149 }
150
151 /// Classifies a known primitive type.
152 PrimType classifyPrim(QualType Ty) const {
153 if (auto T = classify(Ty)) {
154 return *T;
155 }
156 llvm_unreachable("not a primitive type");
157 }
158 /// Classifies a known primitive expression.
159 PrimType classifyPrim(const Expr *E) const {
160 if (auto T = classify(E))
161 return *T;
162 llvm_unreachable("not a primitive type");
163 }
164
165 /// Evaluates an expression and places the result on the stack. If the
166 /// expression is of composite type, a local variable will be created
167 /// and a pointer to said variable will be placed on the stack.
168 bool visit(const Expr *E);
169 /// Compiles an initializer. This is like visit() but it will never
170 /// create a variable and instead rely on a variable already having
171 /// been created. visitInitializer() then relies on a pointer to this
172 /// variable being on top of the stack.
173 bool visitInitializer(const Expr *E);
174 /// Evaluates an expression for side effects and discards the result.
175 bool discard(const Expr *E);
176 /// Just pass evaluation on to \p E. This leaves all the parsing flags
177 /// intact.
178 bool delegate(const Expr *E);
179
180 /// Creates and initializes a variable from the given decl.
181 bool visitVarDecl(const VarDecl *VD);
182 /// Visit an APValue.
183 bool visitAPValue(const APValue &Val, PrimType ValType, const Expr *E);
184
185 /// Visits an expression and converts it to a boolean.
186 bool visitBool(const Expr *E);
187
188 /// Visits an initializer for a local.
189 bool visitLocalInitializer(const Expr *Init, unsigned I) {
190 if (!this->emitGetPtrLocal(I, Init))
191 return false;
192
193 if (!visitInitializer(E: Init))
194 return false;
195
196 if (!this->emitFinishInit(Init))
197 return false;
198
199 return this->emitPopPtr(Init);
200 }
201
202 /// Visits an initializer for a global.
203 bool visitGlobalInitializer(const Expr *Init, unsigned I) {
204 if (!this->emitGetPtrGlobal(I, Init))
205 return false;
206
207 if (!visitInitializer(E: Init))
208 return false;
209
210 if (!this->emitFinishInit(Init))
211 return false;
212
213 return this->emitPopPtr(Init);
214 }
215
216 /// Visits a delegated initializer.
217 bool visitThisInitializer(const Expr *I) {
218 if (!this->emitThis(I))
219 return false;
220
221 if (!visitInitializer(E: I))
222 return false;
223
224 return this->emitFinishInitPop(I);
225 }
226
227 bool visitInitList(ArrayRef<const Expr *> Inits, const Expr *E);
228 bool visitArrayElemInit(unsigned ElemIndex, const Expr *Init);
229
230 /// Creates a local primitive value.
231 unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsConst,
232 bool IsExtended = false);
233
234 /// Allocates a space storing a local given its type.
235 std::optional<unsigned> allocateLocal(DeclTy &&Decl, bool IsExtended = false);
236
237private:
238 friend class VariableScope<Emitter>;
239 friend class LocalScope<Emitter>;
240 friend class DestructorScope<Emitter>;
241 friend class DeclScope<Emitter>;
242 friend class OptionScope<Emitter>;
243 friend class ArrayIndexScope<Emitter>;
244 friend class SourceLocScope<Emitter>;
245
246 /// Emits a zero initializer.
247 bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E);
248 bool visitZeroRecordInitializer(const Record *R, const Expr *E);
249
250 /// Emits an APSInt constant.
251 bool emitConst(const llvm::APSInt &Value, PrimType Ty, const Expr *E);
252 bool emitConst(const llvm::APSInt &Value, const Expr *E);
253 bool emitConst(const llvm::APInt &Value, const Expr *E) {
254 return emitConst(static_cast<llvm::APSInt>(Value), E);
255 }
256
257 /// Emits an integer constant.
258 template <typename T> bool emitConst(T Value, PrimType Ty, const Expr *E);
259 template <typename T> bool emitConst(T Value, const Expr *E);
260
261 llvm::RoundingMode getRoundingMode(const Expr *E) const {
262 FPOptions FPO = E->getFPFeaturesInEffect(LO: Ctx.getLangOpts());
263
264 if (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic)
265 return llvm::RoundingMode::NearestTiesToEven;
266
267 return FPO.getRoundingMode();
268 }
269
270 bool emitPrimCast(PrimType FromT, PrimType ToT, QualType ToQT, const Expr *E);
271 PrimType classifyComplexElementType(QualType T) const {
272 assert(T->isAnyComplexType());
273
274 QualType ElemType = T->getAs<ComplexType>()->getElementType();
275
276 return *this->classify(ElemType);
277 }
278
279 bool emitComplexReal(const Expr *SubExpr);
280 bool emitComplexBoolCast(const Expr *E);
281 bool emitComplexComparison(const Expr *LHS, const Expr *RHS,
282 const BinaryOperator *E);
283
284 bool emitRecordDestruction(const Record *R);
285 bool emitDestruction(const Descriptor *Desc);
286 unsigned collectBaseOffset(const RecordType *BaseType,
287 const RecordType *DerivedType);
288
289protected:
290 /// Variable to storage mapping.
291 llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;
292
293 /// OpaqueValueExpr to location mapping.
294 llvm::DenseMap<const OpaqueValueExpr *, unsigned> OpaqueExprs;
295
296 /// Current scope.
297 VariableScope<Emitter> *VarScope = nullptr;
298
299 /// Current argument index. Needed to emit ArrayInitIndexExpr.
300 std::optional<uint64_t> ArrayIndex;
301
302 /// DefaultInit- or DefaultArgExpr, needed for SourceLocExpr.
303 const Expr *SourceLocDefaultExpr = nullptr;
304
305 /// Flag indicating if return value is to be discarded.
306 bool DiscardResult = false;
307
308 /// Flag inidicating if we're initializing an already created
309 /// variable. This is set in visitInitializer().
310 bool Initializing = false;
311
312 /// Flag indicating if we're initializing a global variable.
313 bool GlobalDecl = false;
314};
315
316extern template class ByteCodeExprGen<ByteCodeEmitter>;
317extern template class ByteCodeExprGen<EvalEmitter>;
318
319/// Scope chain managing the variable lifetimes.
320template <class Emitter> class VariableScope {
321public:
322 VariableScope(ByteCodeExprGen<Emitter> *Ctx)
323 : Ctx(Ctx), Parent(Ctx->VarScope) {
324 Ctx->VarScope = this;
325 }
326
327 virtual ~VariableScope() { Ctx->VarScope = this->Parent; }
328
329 void add(const Scope::Local &Local, bool IsExtended) {
330 if (IsExtended)
331 this->addExtended(Local);
332 else
333 this->addLocal(Local);
334 }
335
336 virtual void addLocal(const Scope::Local &Local) {
337 if (this->Parent)
338 this->Parent->addLocal(Local);
339 }
340
341 virtual void addExtended(const Scope::Local &Local) {
342 if (this->Parent)
343 this->Parent->addExtended(Local);
344 }
345
346 virtual void emitDestruction() {}
347 virtual bool emitDestructors() { return true; }
348 VariableScope *getParent() const { return Parent; }
349
350protected:
351 /// ByteCodeExprGen instance.
352 ByteCodeExprGen<Emitter> *Ctx;
353 /// Link to the parent scope.
354 VariableScope *Parent;
355};
356
357/// Generic scope for local variables.
358template <class Emitter> class LocalScope : public VariableScope<Emitter> {
359public:
360 LocalScope(ByteCodeExprGen<Emitter> *Ctx) : VariableScope<Emitter>(Ctx) {}
361
362 /// Emit a Destroy op for this scope.
363 ~LocalScope() override {
364 if (!Idx)
365 return;
366 this->Ctx->emitDestroy(*Idx, SourceInfo{});
367 removeStoredOpaqueValues();
368 }
369
370 /// Overriden to support explicit destruction.
371 void emitDestruction() override { destroyLocals(); }
372
373 /// Explicit destruction of local variables.
374 bool destroyLocals() {
375 if (!Idx)
376 return true;
377
378 bool Success = this->emitDestructors();
379 this->Ctx->emitDestroy(*Idx, SourceInfo{});
380 removeStoredOpaqueValues();
381 this->Idx = std::nullopt;
382 return Success;
383 }
384
385 void addLocal(const Scope::Local &Local) override {
386 if (!Idx) {
387 Idx = this->Ctx->Descriptors.size();
388 this->Ctx->Descriptors.emplace_back();
389 }
390
391 this->Ctx->Descriptors[*Idx].emplace_back(Local);
392 }
393
394 bool emitDestructors() override {
395 if (!Idx)
396 return true;
397 // Emit destructor calls for local variables of record
398 // type with a destructor.
399 for (Scope::Local &Local : this->Ctx->Descriptors[*Idx]) {
400 if (!Local.Desc->isPrimitive() && !Local.Desc->isPrimitiveArray()) {
401 if (!this->Ctx->emitGetPtrLocal(Local.Offset, SourceInfo{}))
402 return false;
403
404 if (!this->Ctx->emitDestruction(Local.Desc))
405 return false;
406
407 if (!this->Ctx->emitPopPtr(SourceInfo{}))
408 return false;
409 removeIfStoredOpaqueValue(Local);
410 }
411 }
412 return true;
413 }
414
415 void removeStoredOpaqueValues() {
416 if (!Idx)
417 return;
418
419 for (const Scope::Local &Local : this->Ctx->Descriptors[*Idx]) {
420 removeIfStoredOpaqueValue(Local);
421 }
422 }
423
424 void removeIfStoredOpaqueValue(const Scope::Local &Local) {
425 if (const auto *OVE =
426 llvm::dyn_cast_if_present<OpaqueValueExpr>(Val: Local.Desc->asExpr())) {
427 if (auto It = this->Ctx->OpaqueExprs.find(OVE);
428 It != this->Ctx->OpaqueExprs.end())
429 this->Ctx->OpaqueExprs.erase(It);
430 };
431 }
432
433 /// Index of the scope in the chain.
434 std::optional<unsigned> Idx;
435};
436
437/// Emits the destructors of the variables of \param OtherScope
438/// when this scope is destroyed. Does not create a Scope in the bytecode at
439/// all, this is just a RAII object to emit destructors.
440template <class Emitter> class DestructorScope final {
441public:
442 DestructorScope(LocalScope<Emitter> &OtherScope) : OtherScope(OtherScope) {}
443
444 ~DestructorScope() { OtherScope.emitDestructors(); }
445
446private:
447 LocalScope<Emitter> &OtherScope;
448};
449
450/// Like a regular LocalScope, except that the destructors of all local
451/// variables are automatically emitted when the AutoScope is destroyed.
452template <class Emitter> class AutoScope : public LocalScope<Emitter> {
453public:
454 AutoScope(ByteCodeExprGen<Emitter> *Ctx)
455 : LocalScope<Emitter>(Ctx), DS(*this) {}
456
457private:
458 DestructorScope<Emitter> DS;
459};
460
461/// Scope for storage declared in a compound statement.
462template <class Emitter> class BlockScope final : public AutoScope<Emitter> {
463public:
464 BlockScope(ByteCodeExprGen<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {}
465
466 void addExtended(const Scope::Local &Local) override {
467 // If we to this point, just add the variable as a normal local
468 // variable. It will be destroyed at the end of the block just
469 // like all others.
470 this->addLocal(Local);
471 }
472};
473
474/// Expression scope which tracks potentially lifetime extended
475/// temporaries which are hoisted to the parent scope on exit.
476template <class Emitter> class ExprScope final : public AutoScope<Emitter> {
477public:
478 ExprScope(ByteCodeExprGen<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {}
479
480 void addExtended(const Scope::Local &Local) override {
481 if (this->Parent)
482 this->Parent->addLocal(Local);
483 }
484};
485
486template <class Emitter> class ArrayIndexScope final {
487public:
488 ArrayIndexScope(ByteCodeExprGen<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) {
489 OldArrayIndex = Ctx->ArrayIndex;
490 Ctx->ArrayIndex = Index;
491 }
492
493 ~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; }
494
495private:
496 ByteCodeExprGen<Emitter> *Ctx;
497 std::optional<uint64_t> OldArrayIndex;
498};
499
500template <class Emitter> class SourceLocScope final {
501public:
502 SourceLocScope(ByteCodeExprGen<Emitter> *Ctx, const Expr *DefaultExpr)
503 : Ctx(Ctx) {
504 assert(DefaultExpr);
505 // We only switch if the current SourceLocDefaultExpr is null.
506 if (!Ctx->SourceLocDefaultExpr) {
507 Enabled = true;
508 Ctx->SourceLocDefaultExpr = DefaultExpr;
509 }
510 }
511
512 ~SourceLocScope() {
513 if (Enabled)
514 Ctx->SourceLocDefaultExpr = nullptr;
515 }
516
517private:
518 ByteCodeExprGen<Emitter> *Ctx;
519 bool Enabled = false;
520};
521
522} // namespace interp
523} // namespace clang
524
525#endif
526

source code of clang/lib/AST/Interp/ByteCodeExprGen.h