Author: Timm Baeder Date: 2026-07-06T07:04:43+02:00 New Revision: aae9f9ed88eda733e46e308351ba5cd68091806f
URL: https://github.com/llvm/llvm-project/commit/aae9f9ed88eda733e46e308351ba5cd68091806f DIFF: https://github.com/llvm/llvm-project/commit/aae9f9ed88eda733e46e308351ba5cd68091806f.diff LOG: [clang][bytecode][NFC] Move Scope classes to source file (#207647) Added: Modified: clang/lib/AST/ByteCode/Compiler.cpp clang/lib/AST/ByteCode/Compiler.h Removed: ################################################################################ diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 090bbf4596413..662944a9bd2ca 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -37,6 +37,240 @@ static std::optional<bool> getBoolValue(const Expr *E) { return std::nullopt; } +/// Scope chain managing the variable lifetimes. +template <class Emitter> class VariableScope { +public: + VariableScope(Compiler<Emitter> *Ctx, ScopeKind Kind = ScopeKind::Block) + : Ctx(Ctx), Parent(Ctx->VarScope), Kind(Kind) { + if (Parent) + this->LocalsAlwaysEnabled = Parent->LocalsAlwaysEnabled; + Ctx->VarScope = this; + } + + virtual ~VariableScope() { Ctx->VarScope = this->Parent; } + + virtual void addLocal(Scope::Local Local) { + llvm_unreachable("Shouldn't be called"); + } + /// Like addExtended, but adds to the nearest scope of the given kind. + void addForScopeKind(const Scope::Local &Local, ScopeKind Kind) { + VariableScope *P = this; + while (P) { + // We found the right scope kind. + if (P->Kind == Kind) { + P->addLocal(Local); + return; + } + // If we reached the root scope and we're looking for a Block scope, + // attach it to the root instead of the current scope. + if (!P->Parent && Kind == ScopeKind::Block) { + P->addLocal(Local); + return; + } + P = P->Parent; + if (!P) + break; + } + + // Add to this scope. + this->addLocal(Local); + } + + virtual bool emitDestructors(const Expr *E = nullptr) { return true; } + virtual bool destroyLocals(const Expr *E = nullptr) { return true; } + virtual void forceInit() {} + VariableScope *getParent() const { return Parent; } + ScopeKind getKind() const { return Kind; } + + /// Whether locals added to this scope are enabled by default. + /// This is almost always true, except for the two branches + /// of a conditional operator. + bool LocalsAlwaysEnabled = true; + +protected: + /// Compiler instance. + Compiler<Emitter> *Ctx; + /// Link to the parent scope. + VariableScope *Parent; + ScopeKind Kind; +}; + +/// Generic scope for local variables. +template <class Emitter> class LocalScope : public VariableScope<Emitter> { +public: + LocalScope(Compiler<Emitter> *Ctx, ScopeKind Kind = ScopeKind::Block) + : VariableScope<Emitter>(Ctx, Kind) {} + + /// Emit a Destroy op for this scope. + ~LocalScope() override { + if (!Idx) + return; + this->Ctx->emitDestroy(*Idx, SourceInfo{}); + removeStoredOpaqueValues(); + } + /// Explicit destruction of local variables. + bool destroyLocals(const Expr *E = nullptr) override { + if (!Idx) + return true; + + // NB: We are *not* resetting Idx here as to allow multiple + // calls to destroyLocals(). + bool Success = this->emitDestructors(E); + this->Ctx->emitDestroy(*Idx, E); + return Success; + } + + void addLocal(Scope::Local Local) override { + if (!Idx) { + Idx = static_cast<unsigned>(this->Ctx->Descriptors.size()); + this->Ctx->Descriptors.emplace_back(); + this->Ctx->emitInitScope(*Idx, {}); + } + + Local.EnabledByDefault = this->LocalsAlwaysEnabled; + this->Ctx->Descriptors[*Idx].emplace_back(Local); + } + + /// Force-initialize this scope. Usually, scopes are lazily initialized when + /// the first local variable is created, but in scenarios with conditonal + /// operators, we need to ensure scope is initialized just in case one of the + /// arms will create a local and the other won't. In such a case, the + /// InitScope() op would be part of the arm that created the local. + void forceInit() override { + if (!Idx) { + Idx = static_cast<unsigned>(this->Ctx->Descriptors.size()); + this->Ctx->Descriptors.emplace_back(); + this->Ctx->emitInitScope(*Idx, {}); + } + } + + bool emitDestructors(const Expr *E = nullptr) override { + if (!Idx) + return true; + + // Emit destructor calls for local variables of record + // type with a destructor. + for (Scope::Local &Local : llvm::reverse(this->Ctx->Descriptors[*Idx])) { + if (Local.Desc->hasTrivialDtor()) + continue; + + if (!Local.EnabledByDefault) { + typename Emitter::LabelTy EndLabel = this->Ctx->getLabel(); + if (!this->Ctx->emitGetLocalEnabled(Local.Offset, E)) + return false; + if (!this->Ctx->jumpFalse(EndLabel, E)) + return false; + + if (!this->Ctx->emitGetPtrLocal(Local.Offset, E)) + return false; + + if (!this->Ctx->emitDestructionPop(Local.Desc, Local.Desc->getLoc())) + return false; + + this->Ctx->fallthrough(EndLabel); + this->Ctx->emitLabel(EndLabel); + } else { + if (!this->Ctx->emitGetPtrLocal(Local.Offset, E)) + return false; + if (!this->Ctx->emitDestructionPop(Local.Desc, Local.Desc->getLoc())) + return false; + } + + removeIfStoredOpaqueValue(Local); + } + return true; + } + + void removeStoredOpaqueValues() { + if (!Idx) + return; + + for (const Scope::Local &Local : this->Ctx->Descriptors[*Idx]) { + removeIfStoredOpaqueValue(Local); + } + } + + void removeIfStoredOpaqueValue(const Scope::Local &Local) { + if (const auto *OVE = + llvm::dyn_cast_if_present<OpaqueValueExpr>(Local.Desc->asExpr())) { + if (auto It = this->Ctx->OpaqueExprs.find(OVE); + It != this->Ctx->OpaqueExprs.end()) + this->Ctx->OpaqueExprs.erase(It); + }; + } + + /// Index of the scope in the chain. + UnsignedOrNone Idx = std::nullopt; +}; + +template <class Emitter> class ArrayIndexScope final { +public: + ArrayIndexScope(Compiler<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) { + OldArrayIndex = Ctx->ArrayIndex; + Ctx->ArrayIndex = Index; + } + + ~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; } + +private: + Compiler<Emitter> *Ctx; + std::optional<uint64_t> OldArrayIndex; +}; + +template <class Emitter> class SourceLocScope final { +public: + SourceLocScope(Compiler<Emitter> *Ctx, const Expr *DefaultExpr) : Ctx(Ctx) { + assert(DefaultExpr); + // We only switch if the current SourceLocDefaultExpr is null. + if (!Ctx->SourceLocDefaultExpr) { + Enabled = true; + Ctx->SourceLocDefaultExpr = DefaultExpr; + } + } + + ~SourceLocScope() { + if (Enabled) + Ctx->SourceLocDefaultExpr = nullptr; + } + +private: + Compiler<Emitter> *Ctx; + bool Enabled = false; +}; + +template <class Emitter> class InitLinkScope final { +public: + InitLinkScope(Compiler<Emitter> *Ctx, InitLink &&Link) : Ctx(Ctx) { + Ctx->InitStack.push_back(std::move(Link)); + } + + ~InitLinkScope() { this->Ctx->InitStack.pop_back(); } + +public: + Compiler<Emitter> *Ctx; +}; + +template <class Emitter> class InitStackScope final { +public: + InitStackScope(Compiler<Emitter> *Ctx, bool Active) + : Ctx(Ctx), OldValue(Ctx->InitStackActive), Active(Active) { + Ctx->InitStackActive = Active; + if (Active) + Ctx->InitStack.push_back(InitLink::DIE()); + } + + ~InitStackScope() { + this->Ctx->InitStackActive = OldValue; + if (Active) + Ctx->InitStack.pop_back(); + } + +private: + Compiler<Emitter> *Ctx; + bool OldValue; + bool Active; +}; + /// Scope used to handle temporaries in toplevel variable declarations. template <class Emitter> class DeclScope final : public LocalScope<Emitter> { public: diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h index 0a2e75887711d..a93fdd20b712f 100644 --- a/clang/lib/AST/ByteCode/Compiler.h +++ b/clang/lib/AST/ByteCode/Compiler.h @@ -509,240 +509,6 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>, extern template class Compiler<ByteCodeEmitter>; extern template class Compiler<EvalEmitter>; -/// Scope chain managing the variable lifetimes. -template <class Emitter> class VariableScope { -public: - VariableScope(Compiler<Emitter> *Ctx, ScopeKind Kind = ScopeKind::Block) - : Ctx(Ctx), Parent(Ctx->VarScope), Kind(Kind) { - if (Parent) - this->LocalsAlwaysEnabled = Parent->LocalsAlwaysEnabled; - Ctx->VarScope = this; - } - - virtual ~VariableScope() { Ctx->VarScope = this->Parent; } - - virtual void addLocal(Scope::Local Local) { - llvm_unreachable("Shouldn't be called"); - } - /// Like addExtended, but adds to the nearest scope of the given kind. - void addForScopeKind(const Scope::Local &Local, ScopeKind Kind) { - VariableScope *P = this; - while (P) { - // We found the right scope kind. - if (P->Kind == Kind) { - P->addLocal(Local); - return; - } - // If we reached the root scope and we're looking for a Block scope, - // attach it to the root instead of the current scope. - if (!P->Parent && Kind == ScopeKind::Block) { - P->addLocal(Local); - return; - } - P = P->Parent; - if (!P) - break; - } - - // Add to this scope. - this->addLocal(Local); - } - - virtual bool emitDestructors(const Expr *E = nullptr) { return true; } - virtual bool destroyLocals(const Expr *E = nullptr) { return true; } - virtual void forceInit() {} - VariableScope *getParent() const { return Parent; } - ScopeKind getKind() const { return Kind; } - - /// Whether locals added to this scope are enabled by default. - /// This is almost always true, except for the two branches - /// of a conditional operator. - bool LocalsAlwaysEnabled = true; - -protected: - /// Compiler instance. - Compiler<Emitter> *Ctx; - /// Link to the parent scope. - VariableScope *Parent; - ScopeKind Kind; -}; - -/// Generic scope for local variables. -template <class Emitter> class LocalScope : public VariableScope<Emitter> { -public: - LocalScope(Compiler<Emitter> *Ctx, ScopeKind Kind = ScopeKind::Block) - : VariableScope<Emitter>(Ctx, Kind) {} - - /// Emit a Destroy op for this scope. - ~LocalScope() override { - if (!Idx) - return; - this->Ctx->emitDestroy(*Idx, SourceInfo{}); - removeStoredOpaqueValues(); - } - /// Explicit destruction of local variables. - bool destroyLocals(const Expr *E = nullptr) override { - if (!Idx) - return true; - - // NB: We are *not* resetting Idx here as to allow multiple - // calls to destroyLocals(). - bool Success = this->emitDestructors(E); - this->Ctx->emitDestroy(*Idx, E); - return Success; - } - - void addLocal(Scope::Local Local) override { - if (!Idx) { - Idx = static_cast<unsigned>(this->Ctx->Descriptors.size()); - this->Ctx->Descriptors.emplace_back(); - this->Ctx->emitInitScope(*Idx, {}); - } - - Local.EnabledByDefault = this->LocalsAlwaysEnabled; - this->Ctx->Descriptors[*Idx].emplace_back(Local); - } - - /// Force-initialize this scope. Usually, scopes are lazily initialized when - /// the first local variable is created, but in scenarios with conditonal - /// operators, we need to ensure scope is initialized just in case one of the - /// arms will create a local and the other won't. In such a case, the - /// InitScope() op would be part of the arm that created the local. - void forceInit() override { - if (!Idx) { - Idx = static_cast<unsigned>(this->Ctx->Descriptors.size()); - this->Ctx->Descriptors.emplace_back(); - this->Ctx->emitInitScope(*Idx, {}); - } - } - - bool emitDestructors(const Expr *E = nullptr) override { - if (!Idx) - return true; - - // Emit destructor calls for local variables of record - // type with a destructor. - for (Scope::Local &Local : llvm::reverse(this->Ctx->Descriptors[*Idx])) { - if (Local.Desc->hasTrivialDtor()) - continue; - - if (!Local.EnabledByDefault) { - typename Emitter::LabelTy EndLabel = this->Ctx->getLabel(); - if (!this->Ctx->emitGetLocalEnabled(Local.Offset, E)) - return false; - if (!this->Ctx->jumpFalse(EndLabel, E)) - return false; - - if (!this->Ctx->emitGetPtrLocal(Local.Offset, E)) - return false; - - if (!this->Ctx->emitDestructionPop(Local.Desc, Local.Desc->getLoc())) - return false; - - this->Ctx->fallthrough(EndLabel); - this->Ctx->emitLabel(EndLabel); - } else { - if (!this->Ctx->emitGetPtrLocal(Local.Offset, E)) - return false; - if (!this->Ctx->emitDestructionPop(Local.Desc, Local.Desc->getLoc())) - return false; - } - - removeIfStoredOpaqueValue(Local); - } - return true; - } - - void removeStoredOpaqueValues() { - if (!Idx) - return; - - for (const Scope::Local &Local : this->Ctx->Descriptors[*Idx]) { - removeIfStoredOpaqueValue(Local); - } - } - - void removeIfStoredOpaqueValue(const Scope::Local &Local) { - if (const auto *OVE = - llvm::dyn_cast_if_present<OpaqueValueExpr>(Local.Desc->asExpr())) { - if (auto It = this->Ctx->OpaqueExprs.find(OVE); - It != this->Ctx->OpaqueExprs.end()) - this->Ctx->OpaqueExprs.erase(It); - }; - } - - /// Index of the scope in the chain. - UnsignedOrNone Idx = std::nullopt; -}; - -template <class Emitter> class ArrayIndexScope final { -public: - ArrayIndexScope(Compiler<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) { - OldArrayIndex = Ctx->ArrayIndex; - Ctx->ArrayIndex = Index; - } - - ~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; } - -private: - Compiler<Emitter> *Ctx; - std::optional<uint64_t> OldArrayIndex; -}; - -template <class Emitter> class SourceLocScope final { -public: - SourceLocScope(Compiler<Emitter> *Ctx, const Expr *DefaultExpr) : Ctx(Ctx) { - assert(DefaultExpr); - // We only switch if the current SourceLocDefaultExpr is null. - if (!Ctx->SourceLocDefaultExpr) { - Enabled = true; - Ctx->SourceLocDefaultExpr = DefaultExpr; - } - } - - ~SourceLocScope() { - if (Enabled) - Ctx->SourceLocDefaultExpr = nullptr; - } - -private: - Compiler<Emitter> *Ctx; - bool Enabled = false; -}; - -template <class Emitter> class InitLinkScope final { -public: - InitLinkScope(Compiler<Emitter> *Ctx, InitLink &&Link) : Ctx(Ctx) { - Ctx->InitStack.push_back(std::move(Link)); - } - - ~InitLinkScope() { this->Ctx->InitStack.pop_back(); } - -public: - Compiler<Emitter> *Ctx; -}; - -template <class Emitter> class InitStackScope final { -public: - InitStackScope(Compiler<Emitter> *Ctx, bool Active) - : Ctx(Ctx), OldValue(Ctx->InitStackActive), Active(Active) { - Ctx->InitStackActive = Active; - if (Active) - Ctx->InitStack.push_back(InitLink::DIE()); - } - - ~InitStackScope() { - this->Ctx->InitStackActive = OldValue; - if (Active) - Ctx->InitStack.pop_back(); - } - -private: - Compiler<Emitter> *Ctx; - bool OldValue; - bool Active; -}; - } // namespace interp } // namespace clang _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
