1//===--- Compiler.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
25namespace clang {
26class QualType;
27
28namespace interp {
29
30template <class Emitter> class LocalScope;
31template <class Emitter> class DestructorScope;
32template <class Emitter> class VariableScope;
33template <class Emitter> class DeclScope;
34template <class Emitter> class InitLinkScope;
35template <class Emitter> class InitStackScope;
36template <class Emitter> class OptionScope;
37template <class Emitter> class ArrayIndexScope;
38template <class Emitter> class SourceLocScope;
39template <class Emitter> class LoopScope;
40template <class Emitter> class LabelScope;
41template <class Emitter> class SwitchScope;
42template <class Emitter> class StmtExprScope;
43template <class Emitter> class LocOverrideScope;
44
45template <class Emitter> class Compiler;
46struct InitLink {
47public:
48 enum {
49 K_This = 0,
50 K_Field = 1,
51 K_Temp = 2,
52 K_Decl = 3,
53 K_Elem = 5,
54 K_RVO = 6,
55 K_InitList = 7,
56 K_DIE = 8,
57 };
58
59 static InitLink This() { return InitLink{K_This}; }
60 static InitLink InitList() { return InitLink{K_InitList}; }
61 static InitLink RVO() { return InitLink{K_RVO}; }
62 static InitLink DIE() { return InitLink{K_DIE}; }
63 static InitLink Field(unsigned Offset) {
64 InitLink IL{K_Field};
65 IL.Offset = Offset;
66 return IL;
67 }
68 static InitLink Temp(unsigned Offset) {
69 InitLink IL{K_Temp};
70 IL.Offset = Offset;
71 return IL;
72 }
73 static InitLink Decl(const ValueDecl *D) {
74 InitLink IL{K_Decl};
75 IL.D = D;
76 return IL;
77 }
78 static InitLink Elem(unsigned Index) {
79 InitLink IL{K_Elem};
80 IL.Offset = Index;
81 return IL;
82 }
83
84 InitLink(uint8_t Kind) : Kind(Kind) {}
85 template <class Emitter>
86 bool emit(Compiler<Emitter> *Ctx, const Expr *E) const;
87
88 uint32_t Kind;
89 union {
90 unsigned Offset;
91 const ValueDecl *D;
92 };
93};
94
95/// State encapsulating if a the variable creation has been successful,
96/// unsuccessful, or no variable has been created at all.
97struct VarCreationState {
98 std::optional<bool> S = std::nullopt;
99 VarCreationState() = default;
100 VarCreationState(bool b) : S(b) {}
101 static VarCreationState NotCreated() { return VarCreationState(); }
102
103 operator bool() const { return S && *S; }
104 bool notCreated() const { return !S; }
105};
106
107enum class ScopeKind { Block, FullExpression, Call };
108
109/// Compilation context for expressions.
110template <class Emitter>
111class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
112 public Emitter {
113protected:
114 // Aliases for types defined in the emitter.
115 using LabelTy = typename Emitter::LabelTy;
116 using AddrTy = typename Emitter::AddrTy;
117 using OptLabelTy = UnsignedOrNone;
118 using CaseMap = llvm::DenseMap<const SwitchCase *, LabelTy>;
119
120 struct LabelInfo {
121 const Stmt *Name;
122 const VariableScope<Emitter> *BreakOrContinueScope;
123 OptLabelTy BreakLabel;
124 OptLabelTy ContinueLabel;
125 OptLabelTy DefaultLabel;
126 LabelInfo(const Stmt *Name, OptLabelTy BreakLabel, OptLabelTy ContinueLabel,
127 OptLabelTy DefaultLabel,
128 const VariableScope<Emitter> *BreakOrContinueScope)
129 : Name(Name), BreakOrContinueScope(BreakOrContinueScope),
130 BreakLabel(BreakLabel), ContinueLabel(ContinueLabel),
131 DefaultLabel(DefaultLabel) {}
132 };
133
134 /// Current compilation context.
135 Context &Ctx;
136 /// Program to link to.
137 Program &P;
138
139public:
140 /// Initializes the compiler and the backend emitter.
141 template <typename... Tys>
142 Compiler(Context &Ctx, Program &P, Tys &&...Args)
143 : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}
144
145 // Expressions.
146 bool VisitCastExpr(const CastExpr *E);
147 bool VisitBuiltinBitCastExpr(const BuiltinBitCastExpr *E);
148 bool VisitIntegerLiteral(const IntegerLiteral *E);
149 bool VisitFloatingLiteral(const FloatingLiteral *E);
150 bool VisitImaginaryLiteral(const ImaginaryLiteral *E);
151 bool VisitFixedPointLiteral(const FixedPointLiteral *E);
152 bool VisitParenExpr(const ParenExpr *E);
153 bool VisitBinaryOperator(const BinaryOperator *E);
154 bool VisitLogicalBinOp(const BinaryOperator *E);
155 bool VisitPointerArithBinOp(const BinaryOperator *E);
156 bool VisitComplexBinOp(const BinaryOperator *E);
157 bool VisitVectorBinOp(const BinaryOperator *E);
158 bool VisitFixedPointBinOp(const BinaryOperator *E);
159 bool VisitFixedPointUnaryOperator(const UnaryOperator *E);
160 bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);
161 bool VisitCallExpr(const CallExpr *E);
162 bool VisitBuiltinCallExpr(const CallExpr *E, unsigned BuiltinID);
163 bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E);
164 bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E);
165 bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);
166 bool VisitGNUNullExpr(const GNUNullExpr *E);
167 bool VisitCXXThisExpr(const CXXThisExpr *E);
168 bool VisitUnaryOperator(const UnaryOperator *E);
169 bool VisitVectorUnaryOperator(const UnaryOperator *E);
170 bool VisitComplexUnaryOperator(const UnaryOperator *E);
171 bool VisitDeclRefExpr(const DeclRefExpr *E);
172 bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
173 bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E);
174 bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
175 bool VisitInitListExpr(const InitListExpr *E);
176 bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
177 bool VisitConstantExpr(const ConstantExpr *E);
178 bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
179 bool VisitMemberExpr(const MemberExpr *E);
180 bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E);
181 bool VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E);
182 bool VisitOpaqueValueExpr(const OpaqueValueExpr *E);
183 bool VisitAbstractConditionalOperator(const AbstractConditionalOperator *E);
184 bool VisitStringLiteral(const StringLiteral *E);
185 bool VisitObjCStringLiteral(const ObjCStringLiteral *E);
186 bool VisitObjCEncodeExpr(const ObjCEncodeExpr *E);
187 bool VisitSYCLUniqueStableNameExpr(const SYCLUniqueStableNameExpr *E);
188 bool VisitCharacterLiteral(const CharacterLiteral *E);
189 bool VisitCompoundAssignOperator(const CompoundAssignOperator *E);
190 bool VisitFloatCompoundAssignOperator(const CompoundAssignOperator *E);
191 bool VisitPointerCompoundAssignOperator(const CompoundAssignOperator *E);
192 bool VisitExprWithCleanups(const ExprWithCleanups *E);
193 bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
194 bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *E);
195 bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
196 bool VisitTypeTraitExpr(const TypeTraitExpr *E);
197 bool VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E);
198 bool VisitLambdaExpr(const LambdaExpr *E);
199 bool VisitPredefinedExpr(const PredefinedExpr *E);
200 bool VisitCXXThrowExpr(const CXXThrowExpr *E);
201 bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E);
202 bool VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *E);
203 bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E);
204 bool VisitCXXConstructExpr(const CXXConstructExpr *E);
205 bool VisitSourceLocExpr(const SourceLocExpr *E);
206 bool VisitOffsetOfExpr(const OffsetOfExpr *E);
207 bool VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E);
208 bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);
209 bool VisitGenericSelectionExpr(const GenericSelectionExpr *E);
210 bool VisitChooseExpr(const ChooseExpr *E);
211 bool VisitEmbedExpr(const EmbedExpr *E);
212 bool VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *E);
213 bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
214 bool VisitExpressionTraitExpr(const ExpressionTraitExpr *E);
215 bool VisitCXXUuidofExpr(const CXXUuidofExpr *E);
216 bool VisitRequiresExpr(const RequiresExpr *E);
217 bool VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E);
218 bool VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *E);
219 bool VisitPseudoObjectExpr(const PseudoObjectExpr *E);
220 bool VisitPackIndexingExpr(const PackIndexingExpr *E);
221 bool VisitRecoveryExpr(const RecoveryExpr *E);
222 bool VisitAddrLabelExpr(const AddrLabelExpr *E);
223 bool VisitConvertVectorExpr(const ConvertVectorExpr *E);
224 bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E);
225 bool VisitExtVectorElementExpr(const ExtVectorElementExpr *E);
226 bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E);
227 bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
228 bool VisitStmtExpr(const StmtExpr *E);
229 bool VisitCXXNewExpr(const CXXNewExpr *E);
230 bool VisitCXXDeleteExpr(const CXXDeleteExpr *E);
231 bool VisitBlockExpr(const BlockExpr *E);
232 bool VisitCXXTypeidExpr(const CXXTypeidExpr *E);
233 bool VisitObjCDictionaryLiteral(const ObjCDictionaryLiteral *E);
234 bool VisitObjCArrayLiteral(const ObjCArrayLiteral *E);
235 bool VisitDesignatedInitUpdateExpr(const DesignatedInitUpdateExpr *E);
236
237 // Statements.
238 bool visitCompoundStmt(const CompoundStmt *S);
239 bool visitDeclStmt(const DeclStmt *DS, bool EvaluateConditionDecl = false);
240 bool visitReturnStmt(const ReturnStmt *RS);
241 bool visitIfStmt(const IfStmt *IS);
242 bool visitWhileStmt(const WhileStmt *S);
243 bool visitDoStmt(const DoStmt *S);
244 bool visitForStmt(const ForStmt *S);
245 bool visitCXXForRangeStmt(const CXXForRangeStmt *S);
246 bool visitBreakStmt(const BreakStmt *S);
247 bool visitContinueStmt(const ContinueStmt *S);
248 bool visitSwitchStmt(const SwitchStmt *S);
249 bool visitCaseStmt(const CaseStmt *S);
250 bool visitDefaultStmt(const DefaultStmt *S);
251 bool visitAttributedStmt(const AttributedStmt *S);
252 bool visitCXXTryStmt(const CXXTryStmt *S);
253
254protected:
255 bool visitStmt(const Stmt *S);
256 bool visitExpr(const Expr *E, bool DestroyToplevelScope) override;
257 bool visitLValueExpr(const Expr *E, bool DestroyToplevelScope) override;
258 bool visitFunc(const FunctionDecl *F) override;
259
260 bool visitDeclAndReturn(const VarDecl *VD, const Expr *Init,
261 bool ConstantContext) override;
262 bool visitDtorCall(const VarDecl *VD, const APValue &Value) override;
263
264protected:
265 /// Emits scope cleanup instructions.
266 bool emitCleanup();
267
268 /// Returns a record type from a record or pointer type.
269 const RecordType *getRecordTy(QualType Ty);
270
271 /// Returns a record from a record or pointer type.
272 Record *getRecord(QualType Ty);
273 Record *getRecord(const RecordDecl *RD);
274
275 /// Returns a function for the given FunctionDecl.
276 /// If the function does not exist yet, it is compiled.
277 const Function *getFunction(const FunctionDecl *FD);
278
279 OptPrimType classify(const Expr *E) const { return Ctx.classify(E); }
280 OptPrimType classify(QualType Ty) const { return Ctx.classify(T: Ty); }
281 bool canClassify(const Expr *E) const { return Ctx.canClassify(E); }
282 bool canClassify(QualType T) const { return Ctx.canClassify(T); }
283
284 /// Classifies a known primitive type.
285 PrimType classifyPrim(QualType Ty) const {
286 if (auto T = classify(Ty)) {
287 return *T;
288 }
289 llvm_unreachable("not a primitive type");
290 }
291 /// Classifies a known primitive expression.
292 PrimType classifyPrim(const Expr *E) const {
293 if (auto T = classify(E))
294 return *T;
295 llvm_unreachable("not a primitive type");
296 }
297
298 /// Evaluates an expression and places the result on the stack. If the
299 /// expression is of composite type, a local variable will be created
300 /// and a pointer to said variable will be placed on the stack.
301 bool visit(const Expr *E) override;
302 /// Compiles an initializer. This is like visit() but it will never
303 /// create a variable and instead rely on a variable already having
304 /// been created. visitInitializer() then relies on a pointer to this
305 /// variable being on top of the stack.
306 bool visitInitializer(const Expr *E);
307 /// Similar, but will also pop the pointer.
308 bool visitInitializerPop(const Expr *E);
309 bool visitAsLValue(const Expr *E);
310 /// Evaluates an expression for side effects and discards the result.
311 bool discard(const Expr *E);
312 /// Just pass evaluation on to \p E. This leaves all the parsing flags
313 /// intact.
314 bool delegate(const Expr *E);
315 /// Creates and initializes a variable from the given decl.
316 VarCreationState visitVarDecl(const VarDecl *VD, const Expr *Init,
317 bool Toplevel = false);
318 VarCreationState visitDecl(const VarDecl *VD);
319 /// Visit an APValue.
320 bool visitAPValue(const APValue &Val, PrimType ValType, SourceInfo Info);
321 bool visitAPValueInitializer(const APValue &Val, SourceInfo Info, QualType T);
322 /// Visit the given decl as if we have a reference to it.
323 bool visitDeclRef(const ValueDecl *D, const Expr *E);
324
325 /// Visits an expression and converts it to a boolean.
326 bool visitBool(const Expr *E);
327
328 bool visitInitList(ArrayRef<const Expr *> Inits, const Expr *ArrayFiller,
329 const Expr *E);
330 bool visitArrayElemInit(unsigned ElemIndex, const Expr *Init,
331 OptPrimType InitT);
332 bool visitCallArgs(ArrayRef<const Expr *> Args, const FunctionDecl *FuncDecl,
333 bool Activate, bool IsOperatorCall);
334
335 /// Creates a local primitive value.
336 unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsConst,
337 bool IsVolatile = false,
338 ScopeKind SC = ScopeKind::Block);
339
340 /// Allocates a space storing a local given its type.
341 UnsignedOrNone allocateLocal(DeclTy &&Decl, QualType Ty = QualType(),
342 ScopeKind = ScopeKind::Block);
343 UnsignedOrNone allocateTemporary(const Expr *E);
344
345private:
346 friend class VariableScope<Emitter>;
347 friend class LocalScope<Emitter>;
348 friend class DestructorScope<Emitter>;
349 friend class DeclScope<Emitter>;
350 friend class InitLinkScope<Emitter>;
351 friend class InitStackScope<Emitter>;
352 friend class OptionScope<Emitter>;
353 friend class ArrayIndexScope<Emitter>;
354 friend class SourceLocScope<Emitter>;
355 friend struct InitLink;
356 friend class LoopScope<Emitter>;
357 friend class LabelScope<Emitter>;
358 friend class SwitchScope<Emitter>;
359 friend class StmtExprScope<Emitter>;
360 friend class LocOverrideScope<Emitter>;
361
362 /// Emits a zero initializer.
363 bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E);
364 bool visitZeroRecordInitializer(const Record *R, const Expr *E);
365 bool visitZeroArrayInitializer(QualType T, const Expr *E);
366 bool visitAssignment(const Expr *LHS, const Expr *RHS, const Expr *E);
367
368 /// Emits an APSInt constant.
369 bool emitConst(const llvm::APSInt &Value, PrimType Ty, SourceInfo Info);
370 bool emitConst(const llvm::APInt &Value, PrimType Ty, SourceInfo Info);
371 bool emitConst(const llvm::APSInt &Value, const Expr *E);
372 bool emitConst(const llvm::APInt &Value, const Expr *E) {
373 return emitConst(Value, classifyPrim(E), E);
374 }
375
376 /// Emits an integer constant.
377 template <typename T> bool emitConst(T Value, PrimType Ty, SourceInfo Info);
378 template <typename T> bool emitConst(T Value, const Expr *E);
379 bool emitBool(bool V, const Expr *E) override {
380 return this->emitConst(V, E);
381 }
382
383 llvm::RoundingMode getRoundingMode(const Expr *E) const {
384 FPOptions FPO = E->getFPFeaturesInEffect(LO: Ctx.getLangOpts());
385
386 if (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic)
387 return llvm::RoundingMode::NearestTiesToEven;
388
389 return FPO.getRoundingMode();
390 }
391
392 uint32_t getFPOptions(const Expr *E) const {
393 return E->getFPFeaturesInEffect(LO: Ctx.getLangOpts()).getAsOpaqueInt();
394 }
395
396 bool emitPrimCast(PrimType FromT, PrimType ToT, QualType ToQT, const Expr *E);
397 bool emitIntegralCast(PrimType FromT, PrimType ToT, QualType ToQT,
398 const Expr *E);
399 PrimType classifyComplexElementType(QualType T) const {
400 assert(T->isAnyComplexType());
401
402 QualType ElemType = T->getAs<ComplexType>()->getElementType();
403
404 return *this->classify(ElemType);
405 }
406
407 PrimType classifyVectorElementType(QualType T) const {
408 assert(T->isVectorType());
409 return *this->classify(T->getAs<VectorType>()->getElementType());
410 }
411
412 PrimType classifyMatrixElementType(QualType T) const {
413 assert(T->isMatrixType());
414 return *this->classify(T->getAs<MatrixType>()->getElementType());
415 }
416
417 bool emitComplexReal(const Expr *SubExpr);
418 bool emitComplexBoolCast(const Expr *E);
419 bool emitComplexComparison(const Expr *LHS, const Expr *RHS,
420 const BinaryOperator *E);
421 bool emitRecordDestructionPop(const Record *R, SourceInfo Loc);
422 bool emitDestructionPop(const Descriptor *Desc, SourceInfo Loc);
423 bool emitDummyPtr(const DeclTy &D, const Expr *E, bool CU = false);
424 bool emitFloat(const APFloat &F, SourceInfo Info);
425 unsigned collectBaseOffset(const QualType BaseType,
426 const QualType DerivedType);
427 bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD);
428 bool emitBuiltinBitCast(const CastExpr *E);
429
430 bool emitHLSLAggregateSplat(PrimType SrcT, unsigned SrcOffset,
431 QualType DestType, const Expr *E);
432 bool emitVectorConversion(const Expr *Src, const Expr *E);
433
434 /// A scalar element extracted during HLSL aggregate flattening.
435 struct HLSLFlatElement {
436 unsigned LocalOffset;
437 PrimType Type;
438 };
439 unsigned countHLSLFlatElements(QualType Ty);
440 bool emitHLSLFlattenAggregate(QualType SrcType, unsigned SrcPtrOffset,
441 SmallVectorImpl<HLSLFlatElement> &Elements,
442 unsigned MaxElements, const Expr *E);
443 bool emitHLSLConstructAggregate(QualType DestType,
444 ArrayRef<HLSLFlatElement> Elements,
445 unsigned &ElemIdx, const Expr *E);
446 bool emitHLSLConstructAggregate(QualType DestType,
447 ArrayRef<HLSLFlatElement> Elements,
448 const Expr *E) {
449 unsigned ElemIdx = 0;
450 return emitHLSLConstructAggregate(DestType, Elements, ElemIdx, E);
451 }
452
453 bool compileConstructor(const CXXConstructorDecl *Ctor);
454 bool compileDestructor(const CXXDestructorDecl *Dtor);
455 bool compileUnionAssignmentOperator(const CXXMethodDecl *MD);
456
457 bool checkLiteralType(const Expr *E);
458 bool maybeEmitDeferredVarInit(const VarDecl *VD);
459
460 bool refersToUnion(const Expr *E);
461
462protected:
463 /// Variable to storage mapping.
464 llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;
465
466 /// OpaqueValueExpr to location mapping.
467 llvm::DenseMap<const OpaqueValueExpr *, unsigned> OpaqueExprs;
468
469 /// Current scope.
470 VariableScope<Emitter> *VarScope = nullptr;
471
472 /// Current argument index. Needed to emit ArrayInitIndexExpr.
473 std::optional<uint64_t> ArrayIndex;
474
475 /// DefaultInit- or DefaultArgExpr, needed for SourceLocExpr.
476 const Expr *SourceLocDefaultExpr = nullptr;
477
478 /// Flag indicating if return value is to be discarded.
479 bool DiscardResult = false;
480
481 bool SwitchInStmtExpr = false;
482 bool InStmtExpr = false;
483 bool ToLValue = false;
484
485 bool VariablesAreConstexprUnknown = false;
486
487 /// Flag inidicating if we're initializing an already created
488 /// variable. This is set in visitInitializer().
489 bool Initializing = false;
490 const ValueDecl *InitializingDecl = nullptr;
491
492 llvm::SmallVector<InitLink> InitStack;
493 bool InitStackActive = false;
494
495 /// Type of the expression returned by the function.
496 OptPrimType ReturnType;
497
498 /// Switch case mapping.
499 CaseMap CaseLabels;
500 /// Stack of label information for loops and switch statements.
501 llvm::SmallVector<LabelInfo> LabelInfoStack;
502
503 const FunctionDecl *CompilingFunction = nullptr;
504};
505
506extern template class Compiler<ByteCodeEmitter>;
507extern template class Compiler<EvalEmitter>;
508
509/// Scope chain managing the variable lifetimes.
510template <class Emitter> class VariableScope {
511public:
512 VariableScope(Compiler<Emitter> *Ctx, ScopeKind Kind = ScopeKind::Block)
513 : Ctx(Ctx), Parent(Ctx->VarScope), Kind(Kind) {
514 if (Parent)
515 this->LocalsAlwaysEnabled = Parent->LocalsAlwaysEnabled;
516 Ctx->VarScope = this;
517 }
518
519 virtual ~VariableScope() { Ctx->VarScope = this->Parent; }
520
521 virtual void addLocal(Scope::Local Local) {
522 llvm_unreachable("Shouldn't be called");
523 }
524 /// Like addExtended, but adds to the nearest scope of the given kind.
525 void addForScopeKind(const Scope::Local &Local, ScopeKind Kind) {
526 VariableScope *P = this;
527 while (P) {
528 // We found the right scope kind.
529 if (P->Kind == Kind) {
530 P->addLocal(Local);
531 return;
532 }
533 // If we reached the root scope and we're looking for a Block scope,
534 // attach it to the root instead of the current scope.
535 if (!P->Parent && Kind == ScopeKind::Block) {
536 P->addLocal(Local);
537 return;
538 }
539 P = P->Parent;
540 if (!P)
541 break;
542 }
543
544 // Add to this scope.
545 this->addLocal(Local);
546 }
547
548 virtual bool emitDestructors(const Expr *E = nullptr) { return true; }
549 virtual bool destroyLocals(const Expr *E = nullptr) { return true; }
550 virtual void forceInit() {}
551 VariableScope *getParent() const { return Parent; }
552 ScopeKind getKind() const { return Kind; }
553
554 /// Whether locals added to this scope are enabled by default.
555 /// This is almost always true, except for the two branches
556 /// of a conditional operator.
557 bool LocalsAlwaysEnabled = true;
558
559protected:
560 /// Compiler instance.
561 Compiler<Emitter> *Ctx;
562 /// Link to the parent scope.
563 VariableScope *Parent;
564 ScopeKind Kind;
565};
566
567/// Generic scope for local variables.
568template <class Emitter> class LocalScope : public VariableScope<Emitter> {
569public:
570 LocalScope(Compiler<Emitter> *Ctx, ScopeKind Kind = ScopeKind::Block)
571 : VariableScope<Emitter>(Ctx, Kind) {}
572
573 /// Emit a Destroy op for this scope.
574 ~LocalScope() override {
575 if (!Idx)
576 return;
577 this->Ctx->emitDestroy(*Idx, SourceInfo{});
578 removeStoredOpaqueValues();
579 }
580 /// Explicit destruction of local variables.
581 bool destroyLocals(const Expr *E = nullptr) override {
582 if (!Idx)
583 return true;
584
585 // NB: We are *not* resetting Idx here as to allow multiple
586 // calls to destroyLocals().
587 bool Success = this->emitDestructors(E);
588 this->Ctx->emitDestroy(*Idx, E);
589 return Success;
590 }
591
592 void addLocal(Scope::Local Local) override {
593 if (!Idx) {
594 Idx = static_cast<unsigned>(this->Ctx->Descriptors.size());
595 this->Ctx->Descriptors.emplace_back();
596 this->Ctx->emitInitScope(*Idx, {});
597 }
598
599 Local.EnabledByDefault = this->LocalsAlwaysEnabled;
600 this->Ctx->Descriptors[*Idx].emplace_back(Local);
601 }
602
603 /// Force-initialize this scope. Usually, scopes are lazily initialized when
604 /// the first local variable is created, but in scenarios with conditonal
605 /// operators, we need to ensure scope is initialized just in case one of the
606 /// arms will create a local and the other won't. In such a case, the
607 /// InitScope() op would be part of the arm that created the local.
608 void forceInit() override {
609 if (!Idx) {
610 Idx = static_cast<unsigned>(this->Ctx->Descriptors.size());
611 this->Ctx->Descriptors.emplace_back();
612 this->Ctx->emitInitScope(*Idx, {});
613 }
614 }
615
616 bool emitDestructors(const Expr *E = nullptr) override {
617 if (!Idx)
618 return true;
619
620 // Emit destructor calls for local variables of record
621 // type with a destructor.
622 for (Scope::Local &Local : llvm::reverse(this->Ctx->Descriptors[*Idx])) {
623 if (Local.Desc->hasTrivialDtor())
624 continue;
625
626 if (!Local.EnabledByDefault) {
627 typename Emitter::LabelTy EndLabel = this->Ctx->getLabel();
628 if (!this->Ctx->emitGetLocalEnabled(Local.Offset, E))
629 return false;
630 if (!this->Ctx->jumpFalse(EndLabel, E))
631 return false;
632
633 if (!this->Ctx->emitGetPtrLocal(Local.Offset, E))
634 return false;
635
636 if (!this->Ctx->emitDestructionPop(Local.Desc, Local.Desc->getLoc()))
637 return false;
638
639 this->Ctx->fallthrough(EndLabel);
640 this->Ctx->emitLabel(EndLabel);
641 } else {
642 if (!this->Ctx->emitGetPtrLocal(Local.Offset, E))
643 return false;
644 if (!this->Ctx->emitDestructionPop(Local.Desc, Local.Desc->getLoc()))
645 return false;
646 }
647
648 removeIfStoredOpaqueValue(Local);
649 }
650 return true;
651 }
652
653 void removeStoredOpaqueValues() {
654 if (!Idx)
655 return;
656
657 for (const Scope::Local &Local : this->Ctx->Descriptors[*Idx]) {
658 removeIfStoredOpaqueValue(Local);
659 }
660 }
661
662 void removeIfStoredOpaqueValue(const Scope::Local &Local) {
663 if (const auto *OVE =
664 llvm::dyn_cast_if_present<OpaqueValueExpr>(Val: Local.Desc->asExpr())) {
665 if (auto It = this->Ctx->OpaqueExprs.find(OVE);
666 It != this->Ctx->OpaqueExprs.end())
667 this->Ctx->OpaqueExprs.erase(It);
668 };
669 }
670
671 /// Index of the scope in the chain.
672 UnsignedOrNone Idx = std::nullopt;
673};
674
675template <class Emitter> class ArrayIndexScope final {
676public:
677 ArrayIndexScope(Compiler<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) {
678 OldArrayIndex = Ctx->ArrayIndex;
679 Ctx->ArrayIndex = Index;
680 }
681
682 ~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; }
683
684private:
685 Compiler<Emitter> *Ctx;
686 std::optional<uint64_t> OldArrayIndex;
687};
688
689template <class Emitter> class SourceLocScope final {
690public:
691 SourceLocScope(Compiler<Emitter> *Ctx, const Expr *DefaultExpr) : Ctx(Ctx) {
692 assert(DefaultExpr);
693 // We only switch if the current SourceLocDefaultExpr is null.
694 if (!Ctx->SourceLocDefaultExpr) {
695 Enabled = true;
696 Ctx->SourceLocDefaultExpr = DefaultExpr;
697 }
698 }
699
700 ~SourceLocScope() {
701 if (Enabled)
702 Ctx->SourceLocDefaultExpr = nullptr;
703 }
704
705private:
706 Compiler<Emitter> *Ctx;
707 bool Enabled = false;
708};
709
710template <class Emitter> class InitLinkScope final {
711public:
712 InitLinkScope(Compiler<Emitter> *Ctx, InitLink &&Link) : Ctx(Ctx) {
713 Ctx->InitStack.push_back(std::move(Link));
714 }
715
716 ~InitLinkScope() { this->Ctx->InitStack.pop_back(); }
717
718public:
719 Compiler<Emitter> *Ctx;
720};
721
722template <class Emitter> class InitStackScope final {
723public:
724 InitStackScope(Compiler<Emitter> *Ctx, bool Active)
725 : Ctx(Ctx), OldValue(Ctx->InitStackActive), Active(Active) {
726 Ctx->InitStackActive = Active;
727 if (Active)
728 Ctx->InitStack.push_back(InitLink::DIE());
729 }
730
731 ~InitStackScope() {
732 this->Ctx->InitStackActive = OldValue;
733 if (Active)
734 Ctx->InitStack.pop_back();
735 }
736
737private:
738 Compiler<Emitter> *Ctx;
739 bool OldValue;
740 bool Active;
741};
742
743} // namespace interp
744} // namespace clang
745
746#endif
747