1 //===--- ByteCodeExprGen.h - Code generator for expressions -----*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // Defines the constexpr bytecode compiler.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H
14 #define LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H
16 #include "ByteCodeEmitter.h"
17 #include "EvalEmitter.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"
31 template <class Emitter
> class LocalScope
;
32 template <class Emitter
> class DestructorScope
;
33 template <class Emitter
> class RecordScope
;
34 template <class Emitter
> class VariableScope
;
35 template <class Emitter
> class DeclScope
;
36 template <class Emitter
> class OptionScope
;
37 template <class Emitter
> class ArrayIndexScope
;
38 template <class Emitter
> class SourceLocScope
;
40 /// Compilation context for expressions.
41 template <class Emitter
>
42 class ByteCodeExprGen
: public ConstStmtVisitor
<ByteCodeExprGen
<Emitter
>, bool>,
45 // Aliases for types defined in the emitter.
46 using LabelTy
= typename
Emitter::LabelTy
;
47 using AddrTy
= typename
Emitter::AddrTy
;
49 /// Current compilation context.
51 /// Program to link to.
55 /// Initializes the compiler and the backend emitter.
56 template <typename
... Tys
>
57 ByteCodeExprGen(Context
&Ctx
, Program
&P
, Tys
&&... Args
)
58 : Emitter(Ctx
, P
, Args
...), Ctx(Ctx
), P(P
) {}
60 // Expression visitors - result returned on interp stack.
61 bool VisitCastExpr(const CastExpr
*E
);
62 bool VisitIntegerLiteral(const IntegerLiteral
*E
);
63 bool VisitFloatingLiteral(const FloatingLiteral
*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 VisitCXXDefaultArgExpr(const CXXDefaultArgExpr
*E
);
69 bool VisitCallExpr(const CallExpr
*E
);
70 bool VisitBuiltinCallExpr(const CallExpr
*E
);
71 bool VisitCXXMemberCallExpr(const CXXMemberCallExpr
*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 VisitDeclRefExpr(const DeclRefExpr
*E
);
79 bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr
*E
);
80 bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr
*E
);
81 bool VisitArraySubscriptExpr(const ArraySubscriptExpr
*E
);
82 bool VisitInitListExpr(const InitListExpr
*E
);
83 bool VisitCXXParenListInitExpr(const CXXParenListInitExpr
*E
);
84 bool VisitConstantExpr(const ConstantExpr
*E
);
85 bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr
*E
);
86 bool VisitMemberExpr(const MemberExpr
*E
);
87 bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr
*E
);
88 bool VisitArrayInitLoopExpr(const ArrayInitLoopExpr
*E
);
89 bool VisitOpaqueValueExpr(const OpaqueValueExpr
*E
);
90 bool VisitAbstractConditionalOperator(const AbstractConditionalOperator
*E
);
91 bool VisitStringLiteral(const StringLiteral
*E
);
92 bool VisitCharacterLiteral(const CharacterLiteral
*E
);
93 bool VisitCompoundAssignOperator(const CompoundAssignOperator
*E
);
94 bool VisitFloatCompoundAssignOperator(const CompoundAssignOperator
*E
);
95 bool VisitPointerCompoundAssignOperator(const CompoundAssignOperator
*E
);
96 bool VisitExprWithCleanups(const ExprWithCleanups
*E
);
97 bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr
*E
);
98 bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr
*E
);
99 bool VisitCompoundLiteralExpr(const CompoundLiteralExpr
*E
);
100 bool VisitTypeTraitExpr(const TypeTraitExpr
*E
);
101 bool VisitLambdaExpr(const LambdaExpr
*E
);
102 bool VisitPredefinedExpr(const PredefinedExpr
*E
);
103 bool VisitCXXThrowExpr(const CXXThrowExpr
*E
);
104 bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr
*E
);
105 bool VisitCXXNoexceptExpr(const CXXNoexceptExpr
*E
);
106 bool VisitCXXConstructExpr(const CXXConstructExpr
*E
);
107 bool VisitSourceLocExpr(const SourceLocExpr
*E
);
108 bool VisitOffsetOfExpr(const OffsetOfExpr
*E
);
109 bool VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr
*E
);
112 bool visitExpr(const Expr
*E
) override
;
113 bool visitDecl(const VarDecl
*VD
) override
;
116 /// Emits scope cleanup instructions.
119 /// Returns a record type from a record or pointer type.
120 const RecordType
*getRecordTy(QualType Ty
);
122 /// Returns a record from a record or pointer type.
123 Record
*getRecord(QualType Ty
);
124 Record
*getRecord(const RecordDecl
*RD
);
126 // Returns a function for the given FunctionDecl.
127 // If the function does not exist yet, it is compiled.
128 const Function
*getFunction(const FunctionDecl
*FD
);
130 /// Classifies a type.
131 std::optional
<PrimType
> classify(const Expr
*E
) const {
132 return E
->isGLValue() ? PT_Ptr
: classify(E
->getType());
134 std::optional
<PrimType
> classify(QualType Ty
) const {
135 return Ctx
.classify(Ty
);
138 /// Classifies a known primitive type
139 PrimType
classifyPrim(QualType Ty
) const {
140 if (auto T
= classify(Ty
)) {
143 llvm_unreachable("not a primitive type");
145 /// Evaluates an expression and places the result on the stack. If the
146 /// expression is of composite type, a local variable will be created
147 /// and a pointer to said variable will be placed on the stack.
148 bool visit(const Expr
*E
);
149 /// Compiles an initializer. This is like visit() but it will never
150 /// create a variable and instead rely on a variable already having
151 /// been created. visitInitializer() then relies on a pointer to this
152 /// variable being on top of the stack.
153 bool visitInitializer(const Expr
*E
);
154 /// Evaluates an expression for side effects and discards the result.
155 bool discard(const Expr
*E
);
156 /// Just pass evaluation on to \p E. This leaves all the parsing flags
158 bool delegate(const Expr
*E
);
160 /// Creates and initializes a variable from the given decl.
161 bool visitVarDecl(const VarDecl
*VD
);
162 /// Visit an APValue.
163 bool visitAPValue(const APValue
&Val
, PrimType ValType
, const Expr
*E
);
165 /// Visits an expression and converts it to a boolean.
166 bool visitBool(const Expr
*E
);
168 /// Visits an initializer for a local.
169 bool visitLocalInitializer(const Expr
*Init
, unsigned I
) {
170 if (!this->emitGetPtrLocal(I
, Init
))
173 if (!visitInitializer(Init
))
176 return this->emitPopPtr(Init
);
179 /// Visits an initializer for a global.
180 bool visitGlobalInitializer(const Expr
*Init
, unsigned I
) {
181 if (!this->emitGetPtrGlobal(I
, Init
))
184 if (!visitInitializer(Init
))
187 if ((Init
->getType()->isArrayType() || Init
->getType()->isRecordType()) &&
188 !this->emitCheckGlobalCtor(Init
))
191 return this->emitPopPtr(Init
);
194 /// Visits a delegated initializer.
195 bool visitThisInitializer(const Expr
*I
) {
196 if (!this->emitThis(I
))
199 if (!visitInitializer(I
))
202 return this->emitPopPtr(I
);
205 bool visitInitList(ArrayRef
<const Expr
*> Inits
, const Expr
*E
);
207 /// Creates a local primitive value.
208 unsigned allocateLocalPrimitive(DeclTy
&&Decl
, PrimType Ty
, bool IsConst
,
209 bool IsExtended
= false);
211 /// Allocates a space storing a local given its type.
212 std::optional
<unsigned> allocateLocal(DeclTy
&&Decl
, bool IsExtended
= false);
215 friend class VariableScope
<Emitter
>;
216 friend class LocalScope
<Emitter
>;
217 friend class DestructorScope
<Emitter
>;
218 friend class RecordScope
<Emitter
>;
219 friend class DeclScope
<Emitter
>;
220 friend class OptionScope
<Emitter
>;
221 friend class ArrayIndexScope
<Emitter
>;
222 friend class SourceLocScope
<Emitter
>;
224 /// Emits a zero initializer.
225 bool visitZeroInitializer(PrimType T
, QualType QT
, const Expr
*E
);
226 bool visitZeroRecordInitializer(const Record
*R
, const Expr
*E
);
228 enum class DerefKind
{
229 /// Value is read and pushed to stack.
231 /// Direct method generates a value which is written. Returns pointer.
233 /// Direct method receives the value, pushes mutated value. Returns pointer.
237 /// Method to directly load a value. If the value can be fetched directly,
238 /// the direct handler is called. Otherwise, a pointer is left on the stack
239 /// and the indirect handler is expected to operate on that.
240 bool dereference(const Expr
*LV
, DerefKind AK
,
241 llvm::function_ref
<bool(PrimType
)> Direct
,
242 llvm::function_ref
<bool(PrimType
)> Indirect
);
243 bool dereferenceParam(const Expr
*LV
, PrimType T
, const ParmVarDecl
*PD
,
245 llvm::function_ref
<bool(PrimType
)> Direct
,
246 llvm::function_ref
<bool(PrimType
)> Indirect
);
247 bool dereferenceVar(const Expr
*LV
, PrimType T
, const VarDecl
*PD
,
248 DerefKind AK
, llvm::function_ref
<bool(PrimType
)> Direct
,
249 llvm::function_ref
<bool(PrimType
)> Indirect
);
251 /// Emits an APSInt constant.
252 bool emitConst(const llvm::APSInt
&Value
, PrimType Ty
, const Expr
*E
);
253 bool emitConst(const llvm::APSInt
&Value
, const Expr
*E
);
254 bool emitConst(const llvm::APInt
&Value
, const Expr
*E
) {
255 return emitConst(static_cast<llvm::APSInt
>(Value
), E
);
258 /// Emits an integer constant.
259 template <typename T
> bool emitConst(T Value
, PrimType Ty
, const Expr
*E
);
260 template <typename T
> bool emitConst(T Value
, const Expr
*E
);
262 /// Returns the CXXRecordDecl for the type of the given expression,
263 /// or nullptr if no such decl exists.
264 const CXXRecordDecl
*getRecordDecl(const Expr
*E
) const {
265 QualType T
= E
->getType();
266 if (const auto *RD
= T
->getPointeeCXXRecordDecl())
268 return T
->getAsCXXRecordDecl();
271 llvm::RoundingMode
getRoundingMode(const Expr
*E
) const {
272 FPOptions FPO
= E
->getFPFeaturesInEffect(Ctx
.getLangOpts());
274 if (FPO
.getRoundingMode() == llvm::RoundingMode::Dynamic
)
275 return llvm::RoundingMode::NearestTiesToEven
;
277 return FPO
.getRoundingMode();
280 bool emitPrimCast(PrimType FromT
, PrimType ToT
, QualType ToQT
, const Expr
*E
);
281 bool emitRecordDestruction(const Descriptor
*Desc
);
282 unsigned collectBaseOffset(const RecordType
*BaseType
,
283 const RecordType
*DerivedType
);
286 /// Variable to storage mapping.
287 llvm::DenseMap
<const ValueDecl
*, Scope::Local
> Locals
;
289 /// OpaqueValueExpr to location mapping.
290 llvm::DenseMap
<const OpaqueValueExpr
*, unsigned> OpaqueExprs
;
293 VariableScope
<Emitter
> *VarScope
= nullptr;
295 /// Current argument index. Needed to emit ArrayInitIndexExpr.
296 std::optional
<uint64_t> ArrayIndex
;
298 /// DefaultInit- or DefaultArgExpr, needed for SourceLocExpr.
299 const Expr
*SourceLocDefaultExpr
= nullptr;
301 /// Flag indicating if return value is to be discarded.
302 bool DiscardResult
= false;
304 /// Flag inidicating if we're initializing an already created
305 /// variable. This is set in visitInitializer().
306 bool Initializing
= false;
308 /// Flag indicating if we're initializing a global variable.
309 bool GlobalDecl
= false;
312 extern template class ByteCodeExprGen
<ByteCodeEmitter
>;
313 extern template class ByteCodeExprGen
<EvalEmitter
>;
315 /// Scope chain managing the variable lifetimes.
316 template <class Emitter
> class VariableScope
{
318 VariableScope(ByteCodeExprGen
<Emitter
> *Ctx
)
319 : Ctx(Ctx
), Parent(Ctx
->VarScope
) {
320 Ctx
->VarScope
= this;
323 virtual ~VariableScope() { Ctx
->VarScope
= this->Parent
; }
325 void add(const Scope::Local
&Local
, bool IsExtended
) {
327 this->addExtended(Local
);
329 this->addLocal(Local
);
332 virtual void addLocal(const Scope::Local
&Local
) {
334 this->Parent
->addLocal(Local
);
337 virtual void addExtended(const Scope::Local
&Local
) {
339 this->Parent
->addExtended(Local
);
342 virtual void emitDestruction() {}
343 virtual void emitDestructors() {}
344 VariableScope
*getParent() const { return Parent
; }
347 /// ByteCodeExprGen instance.
348 ByteCodeExprGen
<Emitter
> *Ctx
;
349 /// Link to the parent scope.
350 VariableScope
*Parent
;
353 /// Generic scope for local variables.
354 template <class Emitter
> class LocalScope
: public VariableScope
<Emitter
> {
356 LocalScope(ByteCodeExprGen
<Emitter
> *Ctx
) : VariableScope
<Emitter
>(Ctx
) {}
358 /// Emit a Destroy op for this scope.
359 ~LocalScope() override
{
362 this->Ctx
->emitDestroy(*Idx
, SourceInfo
{});
365 /// Overriden to support explicit destruction.
366 void emitDestruction() override
{
369 this->emitDestructors();
370 this->Ctx
->emitDestroy(*Idx
, SourceInfo
{});
371 this->Idx
= std::nullopt
;
374 void addLocal(const Scope::Local
&Local
) override
{
376 Idx
= this->Ctx
->Descriptors
.size();
377 this->Ctx
->Descriptors
.emplace_back();
380 this->Ctx
->Descriptors
[*Idx
].emplace_back(Local
);
383 void emitDestructors() override
{
386 // Emit destructor calls for local variables of record
387 // type with a destructor.
388 for (Scope::Local
&Local
: this->Ctx
->Descriptors
[*Idx
]) {
389 if (!Local
.Desc
->isPrimitive() && !Local
.Desc
->isPrimitiveArray()) {
390 this->Ctx
->emitGetPtrLocal(Local
.Offset
, SourceInfo
{});
391 this->Ctx
->emitRecordDestruction(Local
.Desc
);
396 /// Index of the scope in the chain.
397 std::optional
<unsigned> Idx
;
400 /// Emits the destructors of the variables of \param OtherScope
401 /// when this scope is destroyed. Does not create a Scope in the bytecode at
402 /// all, this is just a RAII object to emit destructors.
403 template <class Emitter
> class DestructorScope final
{
405 DestructorScope(LocalScope
<Emitter
> &OtherScope
) : OtherScope(OtherScope
) {}
407 ~DestructorScope() { OtherScope
.emitDestructors(); }
410 LocalScope
<Emitter
> &OtherScope
;
413 /// Like a regular LocalScope, except that the destructors of all local
414 /// variables are automatically emitted when the AutoScope is destroyed.
415 template <class Emitter
> class AutoScope
: public LocalScope
<Emitter
> {
417 AutoScope(ByteCodeExprGen
<Emitter
> *Ctx
)
418 : LocalScope
<Emitter
>(Ctx
), DS(*this) {}
421 DestructorScope
<Emitter
> DS
;
424 /// Scope for storage declared in a compound statement.
425 template <class Emitter
> class BlockScope final
: public AutoScope
<Emitter
> {
427 BlockScope(ByteCodeExprGen
<Emitter
> *Ctx
) : AutoScope
<Emitter
>(Ctx
) {}
429 void addExtended(const Scope::Local
&Local
) override
{
430 // If we to this point, just add the variable as a normal local
431 // variable. It will be destroyed at the end of the block just
433 this->addLocal(Local
);
437 /// Expression scope which tracks potentially lifetime extended
438 /// temporaries which are hoisted to the parent scope on exit.
439 template <class Emitter
> class ExprScope final
: public AutoScope
<Emitter
> {
441 ExprScope(ByteCodeExprGen
<Emitter
> *Ctx
) : AutoScope
<Emitter
>(Ctx
) {}
443 void addExtended(const Scope::Local
&Local
) override
{
445 this->Parent
->addLocal(Local
);
449 template <class Emitter
> class ArrayIndexScope final
{
451 ArrayIndexScope(ByteCodeExprGen
<Emitter
> *Ctx
, uint64_t Index
) : Ctx(Ctx
) {
452 OldArrayIndex
= Ctx
->ArrayIndex
;
453 Ctx
->ArrayIndex
= Index
;
456 ~ArrayIndexScope() { Ctx
->ArrayIndex
= OldArrayIndex
; }
459 ByteCodeExprGen
<Emitter
> *Ctx
;
460 std::optional
<uint64_t> OldArrayIndex
;
463 template <class Emitter
> class SourceLocScope final
{
465 SourceLocScope(ByteCodeExprGen
<Emitter
> *Ctx
, const Expr
*DefaultExpr
)
468 // We only switch if the current SourceLocDefaultExpr is null.
469 if (!Ctx
->SourceLocDefaultExpr
) {
471 Ctx
->SourceLocDefaultExpr
= DefaultExpr
;
477 Ctx
->SourceLocDefaultExpr
= nullptr;
481 ByteCodeExprGen
<Emitter
> *Ctx
;
482 bool Enabled
= false;
485 } // namespace interp