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 | |
26 | namespace clang { |
27 | class QualType; |
28 | |
29 | namespace interp { |
30 | |
31 | template <class Emitter> class LocalScope; |
32 | template <class Emitter> class DestructorScope; |
33 | template <class Emitter> class VariableScope; |
34 | template <class Emitter> class DeclScope; |
35 | template <class Emitter> class OptionScope; |
36 | template <class Emitter> class ArrayIndexScope; |
37 | template <class Emitter> class SourceLocScope; |
38 | |
39 | /// Compilation context for expressions. |
40 | template <class Emitter> |
41 | class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>, |
42 | public Emitter { |
43 | protected: |
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 | |
53 | public: |
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 | |
125 | protected: |
126 | bool visitExpr(const Expr *E) override; |
127 | bool visitDecl(const VarDecl *VD) override; |
128 | |
129 | protected: |
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 | |
237 | private: |
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 | |
289 | protected: |
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 | |
316 | extern template class ByteCodeExprGen<ByteCodeEmitter>; |
317 | extern template class ByteCodeExprGen<EvalEmitter>; |
318 | |
319 | /// Scope chain managing the variable lifetimes. |
320 | template <class Emitter> class VariableScope { |
321 | public: |
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 | |
350 | protected: |
351 | /// ByteCodeExprGen instance. |
352 | ByteCodeExprGen<Emitter> *Ctx; |
353 | /// Link to the parent scope. |
354 | VariableScope *Parent; |
355 | }; |
356 | |
357 | /// Generic scope for local variables. |
358 | template <class Emitter> class LocalScope : public VariableScope<Emitter> { |
359 | public: |
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. |
440 | template <class Emitter> class DestructorScope final { |
441 | public: |
442 | DestructorScope(LocalScope<Emitter> &OtherScope) : OtherScope(OtherScope) {} |
443 | |
444 | ~DestructorScope() { OtherScope.emitDestructors(); } |
445 | |
446 | private: |
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. |
452 | template <class Emitter> class AutoScope : public LocalScope<Emitter> { |
453 | public: |
454 | AutoScope(ByteCodeExprGen<Emitter> *Ctx) |
455 | : LocalScope<Emitter>(Ctx), DS(*this) {} |
456 | |
457 | private: |
458 | DestructorScope<Emitter> DS; |
459 | }; |
460 | |
461 | /// Scope for storage declared in a compound statement. |
462 | template <class Emitter> class BlockScope final : public AutoScope<Emitter> { |
463 | public: |
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. |
476 | template <class Emitter> class ExprScope final : public AutoScope<Emitter> { |
477 | public: |
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 | |
486 | template <class Emitter> class ArrayIndexScope final { |
487 | public: |
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 | |
495 | private: |
496 | ByteCodeExprGen<Emitter> *Ctx; |
497 | std::optional<uint64_t> OldArrayIndex; |
498 | }; |
499 | |
500 | template <class Emitter> class SourceLocScope final { |
501 | public: |
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 | |
517 | private: |
518 | ByteCodeExprGen<Emitter> *Ctx; |
519 | bool Enabled = false; |
520 | }; |
521 | |
522 | } // namespace interp |
523 | } // namespace clang |
524 | |
525 | #endif |
526 | |