Author: Timm Baeder Date: 2024-06-27T14:43:39+02:00 New Revision: 468d668c5c4031366ae38804927b450f9faf409c
URL: https://github.com/llvm/llvm-project/commit/468d668c5c4031366ae38804927b450f9faf409c DIFF: https://github.com/llvm/llvm-project/commit/468d668c5c4031366ae38804927b450f9faf409c.diff LOG: [clang][Interp] Merge ByteCodeExprGen and ByteCodeStmtGen (#83683) We currently cannot generate bytecode for statements once we've decided we want to generate bytecode for expressions. This is a problem for `StmtExpr`, which is an expression that requires us to evaluate a statement. Merge ByteCodeExprGen and ByteCodeStmtGen, so we don't do that distinction anymore. Rename them to Compiler at the same time. Added: clang/lib/AST/Interp/Compiler.cpp clang/lib/AST/Interp/Compiler.h Modified: clang/lib/AST/CMakeLists.txt clang/lib/AST/Interp/Context.cpp clang/lib/AST/Interp/EvalEmitter.h clang/lib/AST/Interp/Program.cpp Removed: clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/lib/AST/Interp/ByteCodeExprGen.h clang/lib/AST/Interp/ByteCodeStmtGen.cpp clang/lib/AST/Interp/ByteCodeStmtGen.h ################################################################################ diff --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt index 0328666d59b1f..ceaad8d3c5a86 100644 --- a/clang/lib/AST/CMakeLists.txt +++ b/clang/lib/AST/CMakeLists.txt @@ -65,8 +65,7 @@ add_clang_library(clangAST FormatString.cpp InheritViz.cpp Interp/ByteCodeEmitter.cpp - Interp/ByteCodeExprGen.cpp - Interp/ByteCodeStmtGen.cpp + Interp/Compiler.cpp Interp/Context.cpp Interp/Descriptor.cpp Interp/Disasm.cpp diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp deleted file mode 100644 index 0618ec1aa8f58..0000000000000 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ /dev/null @@ -1,734 +0,0 @@ -//===--- ByteCodeStmtGen.cpp - Code generator for expressions ---*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "ByteCodeStmtGen.h" -#include "ByteCodeEmitter.h" -#include "Context.h" -#include "Function.h" -#include "PrimType.h" - -using namespace clang; -using namespace clang::interp; - -namespace clang { -namespace interp { - -/// Scope managing label targets. -template <class Emitter> class LabelScope { -public: - virtual ~LabelScope() { } - -protected: - LabelScope(ByteCodeStmtGen<Emitter> *Ctx) : Ctx(Ctx) {} - /// ByteCodeStmtGen instance. - ByteCodeStmtGen<Emitter> *Ctx; -}; - -/// Sets the context for break/continue statements. -template <class Emitter> class LoopScope final : public LabelScope<Emitter> { -public: - using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy; - using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy; - - LoopScope(ByteCodeStmtGen<Emitter> *Ctx, LabelTy BreakLabel, - LabelTy ContinueLabel) - : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel), - OldContinueLabel(Ctx->ContinueLabel) { - this->Ctx->BreakLabel = BreakLabel; - this->Ctx->ContinueLabel = ContinueLabel; - } - - ~LoopScope() { - this->Ctx->BreakLabel = OldBreakLabel; - this->Ctx->ContinueLabel = OldContinueLabel; - } - -private: - OptLabelTy OldBreakLabel; - OptLabelTy OldContinueLabel; -}; - -// Sets the context for a switch scope, mapping labels. -template <class Emitter> class SwitchScope final : public LabelScope<Emitter> { -public: - using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy; - using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy; - using CaseMap = typename ByteCodeStmtGen<Emitter>::CaseMap; - - SwitchScope(ByteCodeStmtGen<Emitter> *Ctx, CaseMap &&CaseLabels, - LabelTy BreakLabel, OptLabelTy DefaultLabel) - : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel), - OldDefaultLabel(this->Ctx->DefaultLabel), - OldCaseLabels(std::move(this->Ctx->CaseLabels)) { - this->Ctx->BreakLabel = BreakLabel; - this->Ctx->DefaultLabel = DefaultLabel; - this->Ctx->CaseLabels = std::move(CaseLabels); - } - - ~SwitchScope() { - this->Ctx->BreakLabel = OldBreakLabel; - this->Ctx->DefaultLabel = OldDefaultLabel; - this->Ctx->CaseLabels = std::move(OldCaseLabels); - } - -private: - OptLabelTy OldBreakLabel; - OptLabelTy OldDefaultLabel; - CaseMap OldCaseLabels; -}; - -} // namespace interp -} // namespace clang - -template <class Emitter> -bool ByteCodeStmtGen<Emitter>::emitLambdaStaticInvokerBody( - const CXXMethodDecl *MD) { - assert(MD->isLambdaStaticInvoker()); - assert(MD->hasBody()); - assert(cast<CompoundStmt>(MD->getBody())->body_empty()); - - const CXXRecordDecl *ClosureClass = MD->getParent(); - const CXXMethodDecl *LambdaCallOp = ClosureClass->getLambdaCallOperator(); - assert(ClosureClass->captures_begin() == ClosureClass->captures_end()); - const Function *Func = this->getFunction(LambdaCallOp); - if (!Func) - return false; - assert(Func->hasThisPointer()); - assert(Func->getNumParams() == (MD->getNumParams() + 1 + Func->hasRVO())); - - if (Func->hasRVO()) { - if (!this->emitRVOPtr(MD)) - return false; - } - - // The lambda call operator needs an instance pointer, but we don't have - // one here, and we don't need one either because the lambda cannot have - // any captures, as verified above. Emit a null pointer. This is then - // special-cased when interpreting to not emit any misleading diagnostics. - if (!this->emitNullPtr(nullptr, MD)) - return false; - - // Forward all arguments from the static invoker to the lambda call operator. - for (const ParmVarDecl *PVD : MD->parameters()) { - auto It = this->Params.find(PVD); - assert(It != this->Params.end()); - - // We do the lvalue-to-rvalue conversion manually here, so no need - // to care about references. - PrimType ParamType = this->classify(PVD->getType()).value_or(PT_Ptr); - if (!this->emitGetParam(ParamType, It->second.Offset, MD)) - return false; - } - - if (!this->emitCall(Func, 0, LambdaCallOp)) - return false; - - this->emitCleanup(); - if (ReturnType) - return this->emitRet(*ReturnType, MD); - - // Nothing to do, since we emitted the RVO pointer above. - return this->emitRetVoid(MD); -} - -template <class Emitter> -bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) { - // Classify the return type. - ReturnType = this->classify(F->getReturnType()); - - auto emitFieldInitializer = [&](const Record::Field *F, unsigned FieldOffset, - const Expr *InitExpr) -> bool { - // We don't know what to do with these, so just return false. - if (InitExpr->getType().isNull()) - return false; - - if (std::optional<PrimType> T = this->classify(InitExpr)) { - if (!this->visit(InitExpr)) - return false; - - if (F->isBitField()) - return this->emitInitThisBitField(*T, F, FieldOffset, InitExpr); - return this->emitInitThisField(*T, FieldOffset, InitExpr); - } - - // Non-primitive case. Get a pointer to the field-to-initialize - // on the stack and call visitInitialzer() for it. - InitLinkScope<Emitter> FieldScope(this, InitLink::Field(F->Offset)); - if (!this->emitGetPtrThisField(FieldOffset, InitExpr)) - return false; - - if (!this->visitInitializer(InitExpr)) - return false; - - return this->emitPopPtr(InitExpr); - }; - - // Emit custom code if this is a lambda static invoker. - if (const auto *MD = dyn_cast<CXXMethodDecl>(F); - MD && MD->isLambdaStaticInvoker()) - return this->emitLambdaStaticInvokerBody(MD); - - // Constructor. Set up field initializers. - if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(F)) { - const RecordDecl *RD = Ctor->getParent(); - const Record *R = this->getRecord(RD); - if (!R) - return false; - - InitLinkScope<Emitter> InitScope(this, InitLink::This()); - for (const auto *Init : Ctor->inits()) { - // Scope needed for the initializers. - BlockScope<Emitter> Scope(this); - - const Expr *InitExpr = Init->getInit(); - if (const FieldDecl *Member = Init->getMember()) { - const Record::Field *F = R->getField(Member); - - if (!emitFieldInitializer(F, F->Offset, InitExpr)) - return false; - } else if (const Type *Base = Init->getBaseClass()) { - const auto *BaseDecl = Base->getAsCXXRecordDecl(); - assert(BaseDecl); - - if (Init->isBaseVirtual()) { - assert(R->getVirtualBase(BaseDecl)); - if (!this->emitGetPtrThisVirtBase(BaseDecl, InitExpr)) - return false; - - } else { - // Base class initializer. - // Get This Base and call initializer on it. - const Record::Base *B = R->getBase(BaseDecl); - assert(B); - if (!this->emitGetPtrThisBase(B->Offset, InitExpr)) - return false; - } - - if (!this->visitInitializer(InitExpr)) - return false; - if (!this->emitFinishInitPop(InitExpr)) - return false; - } else if (const IndirectFieldDecl *IFD = Init->getIndirectMember()) { - assert(IFD->getChainingSize() >= 2); - - unsigned NestedFieldOffset = 0; - const Record::Field *NestedField = nullptr; - for (const NamedDecl *ND : IFD->chain()) { - const auto *FD = cast<FieldDecl>(ND); - const Record *FieldRecord = - this->P.getOrCreateRecord(FD->getParent()); - assert(FieldRecord); - - NestedField = FieldRecord->getField(FD); - assert(NestedField); - - NestedFieldOffset += NestedField->Offset; - } - assert(NestedField); - - if (!emitFieldInitializer(NestedField, NestedFieldOffset, InitExpr)) - return false; - } else { - assert(Init->isDelegatingInitializer()); - if (!this->emitThis(InitExpr)) - return false; - if (!this->visitInitializer(Init->getInit())) - return false; - if (!this->emitPopPtr(InitExpr)) - return false; - } - } - } - - if (const auto *Body = F->getBody()) - if (!visitStmt(Body)) - return false; - - // Emit a guard return to protect against a code path missing one. - if (F->getReturnType()->isVoidType()) - return this->emitRetVoid(SourceInfo{}); - else - return this->emitNoRet(SourceInfo{}); -} - -template <class Emitter> -bool ByteCodeStmtGen<Emitter>::visitStmt(const Stmt *S) { - switch (S->getStmtClass()) { - case Stmt::CompoundStmtClass: - return visitCompoundStmt(cast<CompoundStmt>(S)); - case Stmt::DeclStmtClass: - return visitDeclStmt(cast<DeclStmt>(S)); - case Stmt::ReturnStmtClass: - return visitReturnStmt(cast<ReturnStmt>(S)); - case Stmt::IfStmtClass: - return visitIfStmt(cast<IfStmt>(S)); - case Stmt::WhileStmtClass: - return visitWhileStmt(cast<WhileStmt>(S)); - case Stmt::DoStmtClass: - return visitDoStmt(cast<DoStmt>(S)); - case Stmt::ForStmtClass: - return visitForStmt(cast<ForStmt>(S)); - case Stmt::CXXForRangeStmtClass: - return visitCXXForRangeStmt(cast<CXXForRangeStmt>(S)); - case Stmt::BreakStmtClass: - return visitBreakStmt(cast<BreakStmt>(S)); - case Stmt::ContinueStmtClass: - return visitContinueStmt(cast<ContinueStmt>(S)); - case Stmt::SwitchStmtClass: - return visitSwitchStmt(cast<SwitchStmt>(S)); - case Stmt::CaseStmtClass: - return visitCaseStmt(cast<CaseStmt>(S)); - case Stmt::DefaultStmtClass: - return visitDefaultStmt(cast<DefaultStmt>(S)); - case Stmt::AttributedStmtClass: - return visitAttributedStmt(cast<AttributedStmt>(S)); - case Stmt::CXXTryStmtClass: - return visitCXXTryStmt(cast<CXXTryStmt>(S)); - case Stmt::NullStmtClass: - return true; - // Always invalid statements. - case Stmt::GCCAsmStmtClass: - case Stmt::MSAsmStmtClass: - case Stmt::GotoStmtClass: - return this->emitInvalid(S); - case Stmt::LabelStmtClass: - return this->visitStmt(cast<LabelStmt>(S)->getSubStmt()); - default: { - if (auto *Exp = dyn_cast<Expr>(S)) - return this->discard(Exp); - return false; - } - } -} - -/// Visits the given statment without creating a variable -/// scope for it in case it is a compound statement. -template <class Emitter> -bool ByteCodeStmtGen<Emitter>::visitLoopBody(const Stmt *S) { - if (isa<NullStmt>(S)) - return true; - - if (const auto *CS = dyn_cast<CompoundStmt>(S)) { - for (auto *InnerStmt : CS->body()) - if (!visitStmt(InnerStmt)) - return false; - return true; - } - - return this->visitStmt(S); -} - -template <class Emitter> -bool ByteCodeStmtGen<Emitter>::visitCompoundStmt( - const CompoundStmt *CompoundStmt) { - BlockScope<Emitter> Scope(this); - for (auto *InnerStmt : CompoundStmt->body()) - if (!visitStmt(InnerStmt)) - return false; - return true; -} - -template <class Emitter> -bool ByteCodeStmtGen<Emitter>::visitDeclStmt(const DeclStmt *DS) { - for (auto *D : DS->decls()) { - if (isa<StaticAssertDecl, TagDecl, TypedefNameDecl, UsingEnumDecl, - FunctionDecl>(D)) - continue; - - const auto *VD = dyn_cast<VarDecl>(D); - if (!VD) - return false; - if (!this->visitVarDecl(VD)) - return false; - } - - return true; -} - -template <class Emitter> -bool ByteCodeStmtGen<Emitter>::visitReturnStmt(const ReturnStmt *RS) { - if (const Expr *RE = RS->getRetValue()) { - ExprScope<Emitter> RetScope(this); - if (ReturnType) { - // Primitive types are simply returned. - if (!this->visit(RE)) - return false; - this->emitCleanup(); - return this->emitRet(*ReturnType, RS); - } else if (RE->getType()->isVoidType()) { - if (!this->visit(RE)) - return false; - } else { - // RVO - construct the value in the return location. - if (!this->emitRVOPtr(RE)) - return false; - if (!this->visitInitializer(RE)) - return false; - if (!this->emitPopPtr(RE)) - return false; - - this->emitCleanup(); - return this->emitRetVoid(RS); - } - } - - // Void return. - this->emitCleanup(); - return this->emitRetVoid(RS); -} - -template <class Emitter> -bool ByteCodeStmtGen<Emitter>::visitIfStmt(const IfStmt *IS) { - BlockScope<Emitter> IfScope(this); - - if (IS->isNonNegatedConsteval()) - return visitStmt(IS->getThen()); - if (IS->isNegatedConsteval()) - return IS->getElse() ? visitStmt(IS->getElse()) : true; - - if (auto *CondInit = IS->getInit()) - if (!visitStmt(CondInit)) - return false; - - if (const DeclStmt *CondDecl = IS->getConditionVariableDeclStmt()) - if (!visitDeclStmt(CondDecl)) - return false; - - if (!this->visitBool(IS->getCond())) - return false; - - if (const Stmt *Else = IS->getElse()) { - LabelTy LabelElse = this->getLabel(); - LabelTy LabelEnd = this->getLabel(); - if (!this->jumpFalse(LabelElse)) - return false; - if (!visitStmt(IS->getThen())) - return false; - if (!this->jump(LabelEnd)) - return false; - this->emitLabel(LabelElse); - if (!visitStmt(Else)) - return false; - this->emitLabel(LabelEnd); - } else { - LabelTy LabelEnd = this->getLabel(); - if (!this->jumpFalse(LabelEnd)) - return false; - if (!visitStmt(IS->getThen())) - return false; - this->emitLabel(LabelEnd); - } - - return true; -} - -template <class Emitter> -bool ByteCodeStmtGen<Emitter>::visitWhileStmt(const WhileStmt *S) { - const Expr *Cond = S->getCond(); - const Stmt *Body = S->getBody(); - - LabelTy CondLabel = this->getLabel(); // Label before the condition. - LabelTy EndLabel = this->getLabel(); // Label after the loop. - LoopScope<Emitter> LS(this, EndLabel, CondLabel); - - this->emitLabel(CondLabel); - - if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt()) - if (!visitDeclStmt(CondDecl)) - return false; - - if (!this->visitBool(Cond)) - return false; - if (!this->jumpFalse(EndLabel)) - return false; - - LocalScope<Emitter> Scope(this); - { - DestructorScope<Emitter> DS(Scope); - if (!this->visitLoopBody(Body)) - return false; - } - - if (!this->jump(CondLabel)) - return false; - this->emitLabel(EndLabel); - - return true; -} - -template <class Emitter> -bool ByteCodeStmtGen<Emitter>::visitDoStmt(const DoStmt *S) { - const Expr *Cond = S->getCond(); - const Stmt *Body = S->getBody(); - - LabelTy StartLabel = this->getLabel(); - LabelTy EndLabel = this->getLabel(); - LabelTy CondLabel = this->getLabel(); - LoopScope<Emitter> LS(this, EndLabel, CondLabel); - LocalScope<Emitter> Scope(this); - - this->emitLabel(StartLabel); - { - DestructorScope<Emitter> DS(Scope); - - if (!this->visitLoopBody(Body)) - return false; - this->emitLabel(CondLabel); - if (!this->visitBool(Cond)) - return false; - } - if (!this->jumpTrue(StartLabel)) - return false; - - this->emitLabel(EndLabel); - return true; -} - -template <class Emitter> -bool ByteCodeStmtGen<Emitter>::visitForStmt(const ForStmt *S) { - // for (Init; Cond; Inc) { Body } - const Stmt *Init = S->getInit(); - const Expr *Cond = S->getCond(); - const Expr *Inc = S->getInc(); - const Stmt *Body = S->getBody(); - - LabelTy EndLabel = this->getLabel(); - LabelTy CondLabel = this->getLabel(); - LabelTy IncLabel = this->getLabel(); - LoopScope<Emitter> LS(this, EndLabel, IncLabel); - LocalScope<Emitter> Scope(this); - - if (Init && !this->visitStmt(Init)) - return false; - this->emitLabel(CondLabel); - - if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt()) - if (!visitDeclStmt(CondDecl)) - return false; - if (Cond) { - if (!this->visitBool(Cond)) - return false; - if (!this->jumpFalse(EndLabel)) - return false; - } - - { - DestructorScope<Emitter> DS(Scope); - - if (Body && !this->visitLoopBody(Body)) - return false; - this->emitLabel(IncLabel); - if (Inc && !this->discard(Inc)) - return false; - } - - if (!this->jump(CondLabel)) - return false; - this->emitLabel(EndLabel); - return true; -} - -template <class Emitter> -bool ByteCodeStmtGen<Emitter>::visitCXXForRangeStmt(const CXXForRangeStmt *S) { - const Stmt *Init = S->getInit(); - const Expr *Cond = S->getCond(); - const Expr *Inc = S->getInc(); - const Stmt *Body = S->getBody(); - const Stmt *BeginStmt = S->getBeginStmt(); - const Stmt *RangeStmt = S->getRangeStmt(); - const Stmt *EndStmt = S->getEndStmt(); - const VarDecl *LoopVar = S->getLoopVariable(); - - LabelTy EndLabel = this->getLabel(); - LabelTy CondLabel = this->getLabel(); - LabelTy IncLabel = this->getLabel(); - LoopScope<Emitter> LS(this, EndLabel, IncLabel); - - // Emit declarations needed in the loop. - if (Init && !this->visitStmt(Init)) - return false; - if (!this->visitStmt(RangeStmt)) - return false; - if (!this->visitStmt(BeginStmt)) - return false; - if (!this->visitStmt(EndStmt)) - return false; - - // Now the condition as well as the loop variable assignment. - this->emitLabel(CondLabel); - if (!this->visitBool(Cond)) - return false; - if (!this->jumpFalse(EndLabel)) - return false; - - if (!this->visitVarDecl(LoopVar)) - return false; - - // Body. - LocalScope<Emitter> Scope(this); - { - DestructorScope<Emitter> DS(Scope); - - if (!this->visitLoopBody(Body)) - return false; - this->emitLabel(IncLabel); - if (!this->discard(Inc)) - return false; - } - if (!this->jump(CondLabel)) - return false; - - this->emitLabel(EndLabel); - return true; -} - -template <class Emitter> -bool ByteCodeStmtGen<Emitter>::visitBreakStmt(const BreakStmt *S) { - if (!BreakLabel) - return false; - - this->VarScope->emitDestructors(); - return this->jump(*BreakLabel); -} - -template <class Emitter> -bool ByteCodeStmtGen<Emitter>::visitContinueStmt(const ContinueStmt *S) { - if (!ContinueLabel) - return false; - - this->VarScope->emitDestructors(); - return this->jump(*ContinueLabel); -} - -template <class Emitter> -bool ByteCodeStmtGen<Emitter>::visitSwitchStmt(const SwitchStmt *S) { - const Expr *Cond = S->getCond(); - - LabelTy EndLabel = this->getLabel(); - OptLabelTy DefaultLabel = std::nullopt; - - if (const auto *CondInit = S->getInit()) - if (!visitStmt(CondInit)) - return false; - - if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt()) - if (!visitDeclStmt(CondDecl)) - return false; - - // Initialize condition variable. - PrimType CondT = this->classifyPrim(Cond->getType()); - unsigned CondVar = this->allocateLocalPrimitive(Cond, CondT, true, false); - if (!this->visit(Cond)) - return false; - if (!this->emitSetLocal(CondT, CondVar, S)) - return false; - - CaseMap CaseLabels; - // Create labels and comparison ops for all case statements. - for (const SwitchCase *SC = S->getSwitchCaseList(); SC; - SC = SC->getNextSwitchCase()) { - if (const auto *CS = dyn_cast<CaseStmt>(SC)) { - // FIXME: Implement ranges. - if (CS->caseStmtIsGNURange()) - return false; - CaseLabels[SC] = this->getLabel(); - - const Expr *Value = CS->getLHS(); - PrimType ValueT = this->classifyPrim(Value->getType()); - - // Compare the case statement's value to the switch condition. - if (!this->emitGetLocal(CondT, CondVar, CS)) - return false; - if (!this->visit(Value)) - return false; - - // Compare and jump to the case label. - if (!this->emitEQ(ValueT, S)) - return false; - if (!this->jumpTrue(CaseLabels[CS])) - return false; - } else { - assert(!DefaultLabel); - DefaultLabel = this->getLabel(); - } - } - - // If none of the conditions above were true, fall through to the default - // statement or jump after the switch statement. - if (DefaultLabel) { - if (!this->jump(*DefaultLabel)) - return false; - } else { - if (!this->jump(EndLabel)) - return false; - } - - SwitchScope<Emitter> SS(this, std::move(CaseLabels), EndLabel, DefaultLabel); - if (!this->visitStmt(S->getBody())) - return false; - this->emitLabel(EndLabel); - return true; -} - -template <class Emitter> -bool ByteCodeStmtGen<Emitter>::visitCaseStmt(const CaseStmt *S) { - this->emitLabel(CaseLabels[S]); - return this->visitStmt(S->getSubStmt()); -} - -template <class Emitter> -bool ByteCodeStmtGen<Emitter>::visitDefaultStmt(const DefaultStmt *S) { - this->emitLabel(*DefaultLabel); - return this->visitStmt(S->getSubStmt()); -} - -template <class Emitter> -bool ByteCodeStmtGen<Emitter>::visitAttributedStmt(const AttributedStmt *S) { - - if (this->Ctx.getLangOpts().CXXAssumptions && - !this->Ctx.getLangOpts().MSVCCompat) { - for (const Attr *A : S->getAttrs()) { - auto *AA = dyn_cast<CXXAssumeAttr>(A); - if (!AA) - continue; - - assert(isa<NullStmt>(S->getSubStmt())); - - const Expr *Assumption = AA->getAssumption(); - if (Assumption->isValueDependent()) - return false; - - if (Assumption->HasSideEffects(this->Ctx.getASTContext())) - continue; - - // Evaluate assumption. - if (!this->visitBool(Assumption)) - return false; - - if (!this->emitAssume(Assumption)) - return false; - } - } - - // Ignore other attributes. - return this->visitStmt(S->getSubStmt()); -} - -template <class Emitter> -bool ByteCodeStmtGen<Emitter>::visitCXXTryStmt(const CXXTryStmt *S) { - // Ignore all handlers. - return this->visitStmt(S->getTryBlock()); -} - -namespace clang { -namespace interp { - -template class ByteCodeStmtGen<ByteCodeEmitter>; - -} // namespace interp -} // namespace clang diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.h b/clang/lib/AST/Interp/ByteCodeStmtGen.h deleted file mode 100644 index d7e6e5042c274..0000000000000 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.h +++ /dev/null @@ -1,91 +0,0 @@ -//===--- ByteCodeStmtGen.h - Code generator for expressions -----*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Defines the constexpr bytecode compiler. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_AST_INTERP_BYTECODESTMTGEN_H -#define LLVM_CLANG_AST_INTERP_BYTECODESTMTGEN_H - -#include "ByteCodeEmitter.h" -#include "ByteCodeExprGen.h" -#include "EvalEmitter.h" -#include "PrimType.h" -#include "clang/AST/StmtVisitor.h" - -namespace clang { -namespace interp { - -template <class Emitter> class LoopScope; -template <class Emitter> class SwitchScope; -template <class Emitter> class LabelScope; - -/// Compilation context for statements. -template <class Emitter> -class ByteCodeStmtGen final : public ByteCodeExprGen<Emitter> { - using LabelTy = typename Emitter::LabelTy; - using AddrTy = typename Emitter::AddrTy; - using OptLabelTy = std::optional<LabelTy>; - using CaseMap = llvm::DenseMap<const SwitchCase *, LabelTy>; - -public: - template<typename... Tys> - ByteCodeStmtGen(Tys&&... Args) - : ByteCodeExprGen<Emitter>(std::forward<Tys>(Args)...) {} - -protected: - bool visitFunc(const FunctionDecl *F) override; - -private: - friend class LabelScope<Emitter>; - friend class LoopScope<Emitter>; - friend class SwitchScope<Emitter>; - - // Statement visitors. - bool visitStmt(const Stmt *S); - bool visitCompoundStmt(const CompoundStmt *S); - bool visitLoopBody(const Stmt *S); - bool visitDeclStmt(const DeclStmt *DS); - bool visitReturnStmt(const ReturnStmt *RS); - bool visitIfStmt(const IfStmt *IS); - bool visitWhileStmt(const WhileStmt *S); - bool visitDoStmt(const DoStmt *S); - bool visitForStmt(const ForStmt *S); - bool visitCXXForRangeStmt(const CXXForRangeStmt *S); - bool visitBreakStmt(const BreakStmt *S); - bool visitContinueStmt(const ContinueStmt *S); - bool visitSwitchStmt(const SwitchStmt *S); - bool visitCaseStmt(const CaseStmt *S); - bool visitDefaultStmt(const DefaultStmt *S); - bool visitAttributedStmt(const AttributedStmt *S); - bool visitCXXTryStmt(const CXXTryStmt *S); - - bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD); - - /// Type of the expression returned by the function. - std::optional<PrimType> ReturnType; - - /// Switch case mapping. - CaseMap CaseLabels; - - /// Point to break to. - OptLabelTy BreakLabel; - /// Point to continue to. - OptLabelTy ContinueLabel; - /// Default case label. - OptLabelTy DefaultLabel; -}; - -extern template class ByteCodeStmtGen<ByteCodeEmitter>; -extern template class ByteCodeExprGen<EvalEmitter>; - -} // namespace interp -} // namespace clang - -#endif diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/Compiler.cpp similarity index 81% rename from clang/lib/AST/Interp/ByteCodeExprGen.cpp rename to clang/lib/AST/Interp/Compiler.cpp index 5b06f0e0f2f05..e21e2c0eb8b6a 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -1,4 +1,4 @@ -//===--- ByteCodeExprGen.cpp - Code generator for expressions ---*- C++ -*-===// +//===--- Compiler.cpp - Code generator for expressions ---*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,9 +6,8 @@ // //===----------------------------------------------------------------------===// -#include "ByteCodeExprGen.h" +#include "Compiler.h" #include "ByteCodeEmitter.h" -#include "ByteCodeStmtGen.h" #include "Context.h" #include "Floating.h" #include "Function.h" @@ -28,7 +27,7 @@ namespace interp { /// Scope used to handle temporaries in toplevel variable declarations. template <class Emitter> class DeclScope final : public VariableScope<Emitter> { public: - DeclScope(ByteCodeExprGen<Emitter> *Ctx, const ValueDecl *VD) + DeclScope(Compiler<Emitter> *Ctx, const ValueDecl *VD) : VariableScope<Emitter>(Ctx, nullptr), Scope(Ctx->P, VD), OldGlobalDecl(Ctx->GlobalDecl), OldInitializingDecl(Ctx->InitializingDecl) { @@ -37,6 +36,10 @@ template <class Emitter> class DeclScope final : public VariableScope<Emitter> { Ctx->InitStack.push_back(InitLink::Decl(VD)); } + void addExtended(const Scope::Local &Local) override { + return this->addLocal(Local); + } + ~DeclScope() { this->Ctx->GlobalDecl = OldGlobalDecl; this->Ctx->InitializingDecl = OldInitializingDecl; @@ -53,7 +56,7 @@ template <class Emitter> class DeclScope final : public VariableScope<Emitter> { template <class Emitter> class OptionScope final { public: /// Root constructor, compiling or discarding primitives. - OptionScope(ByteCodeExprGen<Emitter> *Ctx, bool NewDiscardResult, + OptionScope(Compiler<Emitter> *Ctx, bool NewDiscardResult, bool NewInitializing) : Ctx(Ctx), OldDiscardResult(Ctx->DiscardResult), OldInitializing(Ctx->Initializing) { @@ -68,14 +71,14 @@ template <class Emitter> class OptionScope final { private: /// Parent context. - ByteCodeExprGen<Emitter> *Ctx; + Compiler<Emitter> *Ctx; /// Old discard flag to restore. bool OldDiscardResult; bool OldInitializing; }; template <class Emitter> -bool InitLink::emit(ByteCodeExprGen<Emitter> *Ctx, const Expr *E) const { +bool InitLink::emit(Compiler<Emitter> *Ctx, const Expr *E) const { switch (Kind) { case K_This: return Ctx->emitThis(E); @@ -88,11 +91,74 @@ bool InitLink::emit(ByteCodeExprGen<Emitter> *Ctx, const Expr *E) const { return true; } +/// Scope managing label targets. +template <class Emitter> class LabelScope { +public: + virtual ~LabelScope() {} + +protected: + LabelScope(Compiler<Emitter> *Ctx) : Ctx(Ctx) {} + /// Compiler instance. + Compiler<Emitter> *Ctx; +}; + +/// Sets the context for break/continue statements. +template <class Emitter> class LoopScope final : public LabelScope<Emitter> { +public: + using LabelTy = typename Compiler<Emitter>::LabelTy; + using OptLabelTy = typename Compiler<Emitter>::OptLabelTy; + + LoopScope(Compiler<Emitter> *Ctx, LabelTy BreakLabel, LabelTy ContinueLabel) + : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel), + OldContinueLabel(Ctx->ContinueLabel) { + this->Ctx->BreakLabel = BreakLabel; + this->Ctx->ContinueLabel = ContinueLabel; + } + + ~LoopScope() { + this->Ctx->BreakLabel = OldBreakLabel; + this->Ctx->ContinueLabel = OldContinueLabel; + } + +private: + OptLabelTy OldBreakLabel; + OptLabelTy OldContinueLabel; +}; + +// Sets the context for a switch scope, mapping labels. +template <class Emitter> class SwitchScope final : public LabelScope<Emitter> { +public: + using LabelTy = typename Compiler<Emitter>::LabelTy; + using OptLabelTy = typename Compiler<Emitter>::OptLabelTy; + using CaseMap = typename Compiler<Emitter>::CaseMap; + + SwitchScope(Compiler<Emitter> *Ctx, CaseMap &&CaseLabels, LabelTy BreakLabel, + OptLabelTy DefaultLabel) + : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel), + OldDefaultLabel(this->Ctx->DefaultLabel), + OldCaseLabels(std::move(this->Ctx->CaseLabels)) { + this->Ctx->BreakLabel = BreakLabel; + this->Ctx->DefaultLabel = DefaultLabel; + this->Ctx->CaseLabels = std::move(CaseLabels); + } + + ~SwitchScope() { + this->Ctx->BreakLabel = OldBreakLabel; + this->Ctx->DefaultLabel = OldDefaultLabel; + this->Ctx->CaseLabels = std::move(OldCaseLabels); + } + +private: + OptLabelTy OldBreakLabel; + OptLabelTy OldDefaultLabel; + CaseMap OldCaseLabels; +}; + } // namespace interp } // namespace clang template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) { +bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { const Expr *SubExpr = CE->getSubExpr(); switch (CE->getCastKind()) { @@ -546,7 +612,7 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitIntegerLiteral(const IntegerLiteral *LE) { +bool Compiler<Emitter>::VisitIntegerLiteral(const IntegerLiteral *LE) { if (DiscardResult) return true; @@ -554,7 +620,7 @@ bool ByteCodeExprGen<Emitter>::VisitIntegerLiteral(const IntegerLiteral *LE) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitFloatingLiteral(const FloatingLiteral *E) { +bool Compiler<Emitter>::VisitFloatingLiteral(const FloatingLiteral *E) { if (DiscardResult) return true; @@ -562,8 +628,7 @@ bool ByteCodeExprGen<Emitter>::VisitFloatingLiteral(const FloatingLiteral *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitImaginaryLiteral( - const ImaginaryLiteral *E) { +bool Compiler<Emitter>::VisitImaginaryLiteral(const ImaginaryLiteral *E) { assert(E->getType()->isAnyComplexType()); if (DiscardResult) return true; @@ -587,12 +652,12 @@ bool ByteCodeExprGen<Emitter>::VisitImaginaryLiteral( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitParenExpr(const ParenExpr *E) { +bool Compiler<Emitter>::VisitParenExpr(const ParenExpr *E) { return this->delegate(E->getSubExpr()); } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) { +bool Compiler<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) { // Need short-circuiting for these. if (BO->isLogicalOp()) return this->VisitLogicalBinOp(BO); @@ -764,7 +829,7 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) { /// Perform addition/subtraction of a pointer and an integer or /// subtraction of two pointers. template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitPointerArithBinOp(const BinaryOperator *E) { +bool Compiler<Emitter>::VisitPointerArithBinOp(const BinaryOperator *E) { BinaryOperatorKind Op = E->getOpcode(); const Expr *LHS = E->getLHS(); const Expr *RHS = E->getRHS(); @@ -812,7 +877,7 @@ bool ByteCodeExprGen<Emitter>::VisitPointerArithBinOp(const BinaryOperator *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitLogicalBinOp(const BinaryOperator *E) { +bool Compiler<Emitter>::VisitLogicalBinOp(const BinaryOperator *E) { assert(E->isLogicalOp()); BinaryOperatorKind Op = E->getOpcode(); const Expr *LHS = E->getLHS(); @@ -873,7 +938,7 @@ bool ByteCodeExprGen<Emitter>::VisitLogicalBinOp(const BinaryOperator *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) { +bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) { // Prepare storage for result. if (!Initializing) { std::optional<unsigned> LocalIndex = allocateLocal(E); @@ -1101,7 +1166,8 @@ bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) { +bool Compiler<Emitter>::VisitImplicitValueInitExpr( + const ImplicitValueInitExpr *E) { QualType QT = E->getType(); if (std::optional<PrimType> T = classify(QT)) @@ -1184,8 +1250,7 @@ bool ByteCodeExprGen<Emitter>::VisitImplicitValueInitExpr(const ImplicitValueIni } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitArraySubscriptExpr( - const ArraySubscriptExpr *E) { +bool Compiler<Emitter>::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { const Expr *Base = E->getBase(); const Expr *Index = E->getIdx(); @@ -1205,9 +1270,8 @@ bool ByteCodeExprGen<Emitter>::VisitArraySubscriptExpr( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, - const Expr *ArrayFiller, - const Expr *E) { +bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, + const Expr *ArrayFiller, const Expr *E) { if (E->getType()->isVoidType()) return this->emitInvalid(E); @@ -1419,7 +1483,8 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, // If the initializer is of vector type itself, we have to deconstruct // that and initialize all the target fields from the initializer fields. if (const auto *InitVecT = Init->getType()->getAs<VectorType>()) { - if (!this->emitCopyArray(ElemT, 0, InitIndex, InitVecT->getNumElements(), E)) + if (!this->emitCopyArray(ElemT, 0, InitIndex, + InitVecT->getNumElements(), E)) return false; InitIndex += InitVecT->getNumElements(); } else { @@ -1447,8 +1512,8 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, /// Pointer to the array(not the element!) must be on the stack when calling /// this. template <class Emitter> -bool ByteCodeExprGen<Emitter>::visitArrayElemInit(unsigned ElemIndex, - const Expr *Init) { +bool Compiler<Emitter>::visitArrayElemInit(unsigned ElemIndex, + const Expr *Init) { if (std::optional<PrimType> T = classify(Init->getType())) { // Visit the primitive element like normal. if (!this->visit(Init)) @@ -1468,24 +1533,24 @@ bool ByteCodeExprGen<Emitter>::visitArrayElemInit(unsigned ElemIndex, } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitInitListExpr(const InitListExpr *E) { +bool Compiler<Emitter>::VisitInitListExpr(const InitListExpr *E) { return this->visitInitList(E->inits(), E->getArrayFiller(), E); } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitCXXParenListInitExpr( +bool Compiler<Emitter>::VisitCXXParenListInitExpr( const CXXParenListInitExpr *E) { return this->visitInitList(E->getInitExprs(), E->getArrayFiller(), E); } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitSubstNonTypeTemplateParmExpr( +bool Compiler<Emitter>::VisitSubstNonTypeTemplateParmExpr( const SubstNonTypeTemplateParmExpr *E) { return this->delegate(E->getReplacement()); } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitConstantExpr(const ConstantExpr *E) { +bool Compiler<Emitter>::VisitConstantExpr(const ConstantExpr *E) { std::optional<PrimType> T = classify(E->getType()); if (T && E->hasAPValueResult()) { // Try to emit the APValue directly, without visiting the subexpr. @@ -1501,7 +1566,7 @@ bool ByteCodeExprGen<Emitter>::VisitConstantExpr(const ConstantExpr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitEmbedExpr(const EmbedExpr *E) { +bool Compiler<Emitter>::VisitEmbedExpr(const EmbedExpr *E) { auto It = E->begin(); return this->visit(*It); } @@ -1530,7 +1595,7 @@ static CharUnits AlignOfType(QualType T, const ASTContext &ASTCtx, } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitUnaryExprOrTypeTraitExpr( +bool Compiler<Emitter>::VisitUnaryExprOrTypeTraitExpr( const UnaryExprOrTypeTraitExpr *E) { UnaryExprOrTypeTrait Kind = E->getKind(); const ASTContext &ASTCtx = Ctx.getASTContext(); @@ -1622,7 +1687,7 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryExprOrTypeTraitExpr( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitMemberExpr(const MemberExpr *E) { +bool Compiler<Emitter>::VisitMemberExpr(const MemberExpr *E) { // 'Base.Member' const Expr *Base = E->getBase(); const ValueDecl *Member = E->getMemberDecl(); @@ -1674,8 +1739,7 @@ bool ByteCodeExprGen<Emitter>::VisitMemberExpr(const MemberExpr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitArrayInitIndexExpr( - const ArrayInitIndexExpr *E) { +bool Compiler<Emitter>::VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E) { // ArrayIndex might not be set if a ArrayInitIndexExpr is being evaluated // stand-alone, e.g. via EvaluateAsInt(). if (!ArrayIndex) @@ -1684,8 +1748,7 @@ bool ByteCodeExprGen<Emitter>::VisitArrayInitIndexExpr( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitArrayInitLoopExpr( - const ArrayInitLoopExpr *E) { +bool Compiler<Emitter>::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) { assert(Initializing); assert(!DiscardResult); @@ -1713,7 +1776,7 @@ bool ByteCodeExprGen<Emitter>::VisitArrayInitLoopExpr( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitOpaqueValueExpr(const OpaqueValueExpr *E) { +bool Compiler<Emitter>::VisitOpaqueValueExpr(const OpaqueValueExpr *E) { const Expr *SourceExpr = E->getSourceExpr(); if (!SourceExpr) return false; @@ -1749,7 +1812,7 @@ bool ByteCodeExprGen<Emitter>::VisitOpaqueValueExpr(const OpaqueValueExpr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitAbstractConditionalOperator( +bool Compiler<Emitter>::VisitAbstractConditionalOperator( const AbstractConditionalOperator *E) { const Expr *Condition = E->getCond(); const Expr *TrueExpr = E->getTrueExpr(); @@ -1781,7 +1844,7 @@ bool ByteCodeExprGen<Emitter>::VisitAbstractConditionalOperator( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitStringLiteral(const StringLiteral *E) { +bool Compiler<Emitter>::VisitStringLiteral(const StringLiteral *E) { if (DiscardResult) return true; @@ -1838,13 +1901,12 @@ bool ByteCodeExprGen<Emitter>::VisitStringLiteral(const StringLiteral *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitObjCStringLiteral( - const ObjCStringLiteral *E) { +bool Compiler<Emitter>::VisitObjCStringLiteral(const ObjCStringLiteral *E) { return this->delegate(E->getString()); } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { +bool Compiler<Emitter>::VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { auto &A = Ctx.getASTContext(); std::string Str; A.getObjCEncodingForType(E->getEncodedType(), Str); @@ -1855,7 +1917,7 @@ bool ByteCodeExprGen<Emitter>::VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitSYCLUniqueStableNameExpr( +bool Compiler<Emitter>::VisitSYCLUniqueStableNameExpr( const SYCLUniqueStableNameExpr *E) { if (DiscardResult) return true; @@ -1879,15 +1941,14 @@ bool ByteCodeExprGen<Emitter>::VisitSYCLUniqueStableNameExpr( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitCharacterLiteral( - const CharacterLiteral *E) { +bool Compiler<Emitter>::VisitCharacterLiteral(const CharacterLiteral *E) { if (DiscardResult) return true; return this->emitConst(E->getValue(), E); } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitFloatCompoundAssignOperator( +bool Compiler<Emitter>::VisitFloatCompoundAssignOperator( const CompoundAssignOperator *E) { const Expr *LHS = E->getLHS(); @@ -1961,7 +2022,7 @@ bool ByteCodeExprGen<Emitter>::VisitFloatCompoundAssignOperator( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitPointerCompoundAssignOperator( +bool Compiler<Emitter>::VisitPointerCompoundAssignOperator( const CompoundAssignOperator *E) { BinaryOperatorKind Op = E->getOpcode(); const Expr *LHS = E->getLHS(); @@ -1998,7 +2059,7 @@ bool ByteCodeExprGen<Emitter>::VisitPointerCompoundAssignOperator( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitCompoundAssignOperator( +bool Compiler<Emitter>::VisitCompoundAssignOperator( const CompoundAssignOperator *E) { const Expr *LHS = E->getLHS(); @@ -2119,8 +2180,7 @@ bool ByteCodeExprGen<Emitter>::VisitCompoundAssignOperator( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitExprWithCleanups( - const ExprWithCleanups *E) { +bool Compiler<Emitter>::VisitExprWithCleanups(const ExprWithCleanups *E) { ExprScope<Emitter> ES(this); const Expr *SubExpr = E->getSubExpr(); @@ -2130,7 +2190,7 @@ bool ByteCodeExprGen<Emitter>::VisitExprWithCleanups( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitMaterializeTemporaryExpr( +bool Compiler<Emitter>::VisitMaterializeTemporaryExpr( const MaterializeTemporaryExpr *E) { const Expr *SubExpr = E->getSubExpr(); @@ -2202,14 +2262,13 @@ bool ByteCodeExprGen<Emitter>::VisitMaterializeTemporaryExpr( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitCXXBindTemporaryExpr( +bool Compiler<Emitter>::VisitCXXBindTemporaryExpr( const CXXBindTemporaryExpr *E) { return this->delegate(E->getSubExpr()); } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitCompoundLiteralExpr( - const CompoundLiteralExpr *E) { +bool Compiler<Emitter>::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { const Expr *Init = E->getInitializer(); if (Initializing) { // We already have a value, just initialize that. @@ -2274,7 +2333,7 @@ bool ByteCodeExprGen<Emitter>::VisitCompoundLiteralExpr( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitTypeTraitExpr(const TypeTraitExpr *E) { +bool Compiler<Emitter>::VisitTypeTraitExpr(const TypeTraitExpr *E) { if (DiscardResult) return true; if (E->getType()->isBooleanType()) @@ -2283,15 +2342,14 @@ bool ByteCodeExprGen<Emitter>::VisitTypeTraitExpr(const TypeTraitExpr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitArrayTypeTraitExpr( - const ArrayTypeTraitExpr *E) { +bool Compiler<Emitter>::VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) { if (DiscardResult) return true; return this->emitConst(E->getValue(), E); } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitLambdaExpr(const LambdaExpr *E) { +bool Compiler<Emitter>::VisitLambdaExpr(const LambdaExpr *E) { if (DiscardResult) return true; @@ -2330,7 +2388,7 @@ bool ByteCodeExprGen<Emitter>::VisitLambdaExpr(const LambdaExpr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitPredefinedExpr(const PredefinedExpr *E) { +bool Compiler<Emitter>::VisitPredefinedExpr(const PredefinedExpr *E) { if (DiscardResult) return true; @@ -2338,7 +2396,7 @@ bool ByteCodeExprGen<Emitter>::VisitPredefinedExpr(const PredefinedExpr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitCXXThrowExpr(const CXXThrowExpr *E) { +bool Compiler<Emitter>::VisitCXXThrowExpr(const CXXThrowExpr *E) { if (E->getSubExpr() && !this->discard(E->getSubExpr())) return false; @@ -2346,7 +2404,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXThrowExpr(const CXXThrowExpr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitCXXReinterpretCastExpr( +bool Compiler<Emitter>::VisitCXXReinterpretCastExpr( const CXXReinterpretCastExpr *E) { if (!this->discard(E->getSubExpr())) return false; @@ -2355,7 +2413,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXReinterpretCastExpr( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) { +bool Compiler<Emitter>::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) { assert(E->getType()->isBooleanType()); if (DiscardResult) @@ -2364,8 +2422,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitCXXConstructExpr( - const CXXConstructExpr *E) { +bool Compiler<Emitter>::VisitCXXConstructExpr(const CXXConstructExpr *E) { QualType T = E->getType(); assert(!classify(T)); @@ -2477,7 +2534,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXConstructExpr( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitSourceLocExpr(const SourceLocExpr *E) { +bool Compiler<Emitter>::VisitSourceLocExpr(const SourceLocExpr *E) { if (DiscardResult) return true; @@ -2533,7 +2590,7 @@ bool ByteCodeExprGen<Emitter>::VisitSourceLocExpr(const SourceLocExpr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitOffsetOfExpr(const OffsetOfExpr *E) { +bool Compiler<Emitter>::VisitOffsetOfExpr(const OffsetOfExpr *E) { unsigned N = E->getNumComponents(); if (N == 0) return false; @@ -2568,7 +2625,7 @@ bool ByteCodeExprGen<Emitter>::VisitOffsetOfExpr(const OffsetOfExpr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitCXXScalarValueInitExpr( +bool Compiler<Emitter>::VisitCXXScalarValueInitExpr( const CXXScalarValueInitExpr *E) { QualType Ty = E->getType(); @@ -2627,24 +2684,23 @@ bool ByteCodeExprGen<Emitter>::VisitCXXScalarValueInitExpr( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitSizeOfPackExpr(const SizeOfPackExpr *E) { +bool Compiler<Emitter>::VisitSizeOfPackExpr(const SizeOfPackExpr *E) { return this->emitConst(E->getPackLength(), E); } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitGenericSelectionExpr( +bool Compiler<Emitter>::VisitGenericSelectionExpr( const GenericSelectionExpr *E) { return this->delegate(E->getResultExpr()); } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitChooseExpr(const ChooseExpr *E) { +bool Compiler<Emitter>::VisitChooseExpr(const ChooseExpr *E) { return this->delegate(E->getChosenSubExpr()); } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitObjCBoolLiteralExpr( - const ObjCBoolLiteralExpr *E) { +bool Compiler<Emitter>::VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *E) { if (DiscardResult) return true; @@ -2652,7 +2708,7 @@ bool ByteCodeExprGen<Emitter>::VisitObjCBoolLiteralExpr( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitCXXInheritedCtorInitExpr( +bool Compiler<Emitter>::VisitCXXInheritedCtorInitExpr( const CXXInheritedCtorInitExpr *E) { const CXXConstructorDecl *Ctor = E->getConstructor(); assert(!Ctor->isTrivial() && @@ -2683,14 +2739,13 @@ bool ByteCodeExprGen<Emitter>::VisitCXXInheritedCtorInitExpr( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitExpressionTraitExpr( - const ExpressionTraitExpr *E) { +bool Compiler<Emitter>::VisitExpressionTraitExpr(const ExpressionTraitExpr *E) { assert(Ctx.getLangOpts().CPlusPlus); return this->emitConstBool(E->getValue(), E); } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { +bool Compiler<Emitter>::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { if (DiscardResult) return true; assert(!Initializing); @@ -2727,7 +2782,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitRequiresExpr(const RequiresExpr *E) { +bool Compiler<Emitter>::VisitRequiresExpr(const RequiresExpr *E) { assert(classifyPrim(E->getType()) == PT_Bool); if (DiscardResult) return true; @@ -2735,7 +2790,7 @@ bool ByteCodeExprGen<Emitter>::VisitRequiresExpr(const RequiresExpr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitConceptSpecializationExpr( +bool Compiler<Emitter>::VisitConceptSpecializationExpr( const ConceptSpecializationExpr *E) { assert(classifyPrim(E->getType()) == PT_Bool); if (DiscardResult) @@ -2744,14 +2799,13 @@ bool ByteCodeExprGen<Emitter>::VisitConceptSpecializationExpr( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitCXXRewrittenBinaryOperator( +bool Compiler<Emitter>::VisitCXXRewrittenBinaryOperator( const CXXRewrittenBinaryOperator *E) { return this->delegate(E->getSemanticForm()); } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitPseudoObjectExpr( - const PseudoObjectExpr *E) { +bool Compiler<Emitter>::VisitPseudoObjectExpr(const PseudoObjectExpr *E) { for (const Expr *SemE : E->semantics()) { if (auto *OVE = dyn_cast<OpaqueValueExpr>(SemE)) { @@ -2775,18 +2829,17 @@ bool ByteCodeExprGen<Emitter>::VisitPseudoObjectExpr( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitPackIndexingExpr( - const PackIndexingExpr *E) { +bool Compiler<Emitter>::VisitPackIndexingExpr(const PackIndexingExpr *E) { return this->delegate(E->getSelectedExpr()); } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitRecoveryExpr(const RecoveryExpr *E) { +bool Compiler<Emitter>::VisitRecoveryExpr(const RecoveryExpr *E) { return this->emitError(E); } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitAddrLabelExpr(const AddrLabelExpr *E) { +bool Compiler<Emitter>::VisitAddrLabelExpr(const AddrLabelExpr *E) { assert(E->getType()->isVoidPointerType()); unsigned Offset = allocateLocalPrimitive( @@ -2796,8 +2849,7 @@ bool ByteCodeExprGen<Emitter>::VisitAddrLabelExpr(const AddrLabelExpr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitConvertVectorExpr( - const ConvertVectorExpr *E) { +bool Compiler<Emitter>::VisitConvertVectorExpr(const ConvertVectorExpr *E) { assert(Initializing); const auto *VT = E->getType()->castAs<VectorType>(); QualType ElemType = VT->getElementType(); @@ -2829,8 +2881,7 @@ bool ByteCodeExprGen<Emitter>::VisitConvertVectorExpr( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitShuffleVectorExpr( - const ShuffleVectorExpr *E) { +bool Compiler<Emitter>::VisitShuffleVectorExpr(const ShuffleVectorExpr *E) { assert(Initializing); assert(E->getNumSubExprs() > 2); @@ -2872,7 +2923,7 @@ bool ByteCodeExprGen<Emitter>::VisitShuffleVectorExpr( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitExtVectorElementExpr( +bool Compiler<Emitter>::VisitExtVectorElementExpr( const ExtVectorElementExpr *E) { const Expr *Base = E->getBase(); assert( @@ -2934,7 +2985,7 @@ bool ByteCodeExprGen<Emitter>::VisitExtVectorElementExpr( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitObjCBoxedExpr(const ObjCBoxedExpr *E) { +bool Compiler<Emitter>::VisitObjCBoxedExpr(const ObjCBoxedExpr *E) { if (!E->isExpressibleAsConstantInitializer()) return this->emitInvalid(E); @@ -2942,7 +2993,7 @@ bool ByteCodeExprGen<Emitter>::VisitObjCBoxedExpr(const ObjCBoxedExpr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitCXXStdInitializerListExpr( +bool Compiler<Emitter>::VisitCXXStdInitializerListExpr( const CXXStdInitializerListExpr *E) { const Expr *SubExpr = E->getSubExpr(); const ConstantArrayType *ArrayType = @@ -2974,21 +3025,23 @@ bool ByteCodeExprGen<Emitter>::VisitCXXStdInitializerListExpr( return this->emitInitFieldPtr(R->getField(1u)->Offset, E); } -template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) { +template <class Emitter> bool Compiler<Emitter>::discard(const Expr *E) { OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/true, /*NewInitializing=*/false); return this->Visit(E); } -template <class Emitter> -bool ByteCodeExprGen<Emitter>::delegate(const Expr *E) { +template <class Emitter> bool Compiler<Emitter>::delegate(const Expr *E) { + if (E->containsErrors()) + return this->emitError(E); + // We're basically doing: // OptionScope<Emitter> Scope(this, DicardResult, Initializing); // but that's unnecessary of course. return this->Visit(E); } -template <class Emitter> bool ByteCodeExprGen<Emitter>::visit(const Expr *E) { +template <class Emitter> bool Compiler<Emitter>::visit(const Expr *E) { if (E->getType().isNull()) return false; @@ -3015,7 +3068,7 @@ template <class Emitter> bool ByteCodeExprGen<Emitter>::visit(const Expr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::visitInitializer(const Expr *E) { +bool Compiler<Emitter>::visitInitializer(const Expr *E) { assert(!classify(E->getType())); if (E->containsErrors()) @@ -3026,8 +3079,7 @@ bool ByteCodeExprGen<Emitter>::visitInitializer(const Expr *E) { return this->Visit(E); } -template <class Emitter> -bool ByteCodeExprGen<Emitter>::visitBool(const Expr *E) { +template <class Emitter> bool Compiler<Emitter>::visitBool(const Expr *E) { std::optional<PrimType> T = classify(E->getType()); if (!T) { // Convert complex values to bool. @@ -3061,8 +3113,8 @@ bool ByteCodeExprGen<Emitter>::visitBool(const Expr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::visitZeroInitializer(PrimType T, QualType QT, - const Expr *E) { +bool Compiler<Emitter>::visitZeroInitializer(PrimType T, QualType QT, + const Expr *E) { switch (T) { case PT_Bool: return this->emitZeroBool(E); @@ -3100,8 +3152,8 @@ bool ByteCodeExprGen<Emitter>::visitZeroInitializer(PrimType T, QualType QT, } template <class Emitter> -bool ByteCodeExprGen<Emitter>::visitZeroRecordInitializer(const Record *R, - const Expr *E) { +bool Compiler<Emitter>::visitZeroRecordInitializer(const Record *R, + const Expr *E) { assert(E); assert(R); // Fields @@ -3169,7 +3221,7 @@ bool ByteCodeExprGen<Emitter>::visitZeroRecordInitializer(const Record *R, template <class Emitter> template <typename T> -bool ByteCodeExprGen<Emitter>::emitConst(T Value, PrimType Ty, const Expr *E) { +bool Compiler<Emitter>::emitConst(T Value, PrimType Ty, const Expr *E) { switch (Ty) { case PT_Sint8: return this->emitConstSint8(Value, E); @@ -3203,13 +3255,13 @@ bool ByteCodeExprGen<Emitter>::emitConst(T Value, PrimType Ty, const Expr *E) { template <class Emitter> template <typename T> -bool ByteCodeExprGen<Emitter>::emitConst(T Value, const Expr *E) { +bool Compiler<Emitter>::emitConst(T Value, const Expr *E) { return this->emitConst(Value, classifyPrim(E->getType()), E); } template <class Emitter> -bool ByteCodeExprGen<Emitter>::emitConst(const APSInt &Value, PrimType Ty, - const Expr *E) { +bool Compiler<Emitter>::emitConst(const APSInt &Value, PrimType Ty, + const Expr *E) { if (Ty == PT_IntAPS) return this->emitConstIntAPS(Value, E); if (Ty == PT_IntAP) @@ -3221,15 +3273,14 @@ bool ByteCodeExprGen<Emitter>::emitConst(const APSInt &Value, PrimType Ty, } template <class Emitter> -bool ByteCodeExprGen<Emitter>::emitConst(const APSInt &Value, const Expr *E) { +bool Compiler<Emitter>::emitConst(const APSInt &Value, const Expr *E) { return this->emitConst(Value, classifyPrim(E->getType()), E); } template <class Emitter> -unsigned ByteCodeExprGen<Emitter>::allocateLocalPrimitive(DeclTy &&Src, - PrimType Ty, - bool IsConst, - bool IsExtended) { +unsigned Compiler<Emitter>::allocateLocalPrimitive(DeclTy &&Src, PrimType Ty, + bool IsConst, + bool IsExtended) { // Make sure we don't accidentally register the same decl twice. if (const auto *VD = dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) { @@ -3252,10 +3303,9 @@ unsigned ByteCodeExprGen<Emitter>::allocateLocalPrimitive(DeclTy &&Src, template <class Emitter> std::optional<unsigned> -ByteCodeExprGen<Emitter>::allocateLocal(DeclTy &&Src, - const ValueDecl *ExtendingDecl) { +Compiler<Emitter>::allocateLocal(DeclTy &&Src, const ValueDecl *ExtendingDecl) { // Make sure we don't accidentally register the same decl twice. - if ([[maybe_unused]] const auto *VD = + if ([[maybe_unused]] const auto *VD = dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) { assert(!P.getGlobal(VD)); assert(!Locals.contains(VD)); @@ -3294,31 +3344,29 @@ ByteCodeExprGen<Emitter>::allocateLocal(DeclTy &&Src, } template <class Emitter> -const RecordType *ByteCodeExprGen<Emitter>::getRecordTy(QualType Ty) { +const RecordType *Compiler<Emitter>::getRecordTy(QualType Ty) { if (const PointerType *PT = dyn_cast<PointerType>(Ty)) return PT->getPointeeType()->getAs<RecordType>(); return Ty->getAs<RecordType>(); } -template <class Emitter> -Record *ByteCodeExprGen<Emitter>::getRecord(QualType Ty) { +template <class Emitter> Record *Compiler<Emitter>::getRecord(QualType Ty) { if (const auto *RecordTy = getRecordTy(Ty)) return getRecord(RecordTy->getDecl()); return nullptr; } template <class Emitter> -Record *ByteCodeExprGen<Emitter>::getRecord(const RecordDecl *RD) { +Record *Compiler<Emitter>::getRecord(const RecordDecl *RD) { return P.getOrCreateRecord(RD); } template <class Emitter> -const Function *ByteCodeExprGen<Emitter>::getFunction(const FunctionDecl *FD) { +const Function *Compiler<Emitter>::getFunction(const FunctionDecl *FD) { return Ctx.getOrCreateFunction(FD); } -template <class Emitter> -bool ByteCodeExprGen<Emitter>::visitExpr(const Expr *E) { +template <class Emitter> bool Compiler<Emitter>::visitExpr(const Expr *E) { ExprScope<Emitter> RootScope(this); // Void expressions. if (E->getType()->isVoidType()) { @@ -3360,8 +3408,7 @@ bool ByteCodeExprGen<Emitter>::visitExpr(const Expr *E) { /// We get here from evaluateAsInitializer(). /// We need to evaluate the initializer and return its value. template <class Emitter> -bool ByteCodeExprGen<Emitter>::visitDecl(const VarDecl *VD, - bool ConstantContext) { +bool Compiler<Emitter>::visitDecl(const VarDecl *VD, bool ConstantContext) { assert(!VD->isInvalidDecl() && "Trying to constant evaluate an invalid decl"); std::optional<PrimType> VarT = classify(VD->getType()); @@ -3434,7 +3481,7 @@ bool ByteCodeExprGen<Emitter>::visitDecl(const VarDecl *VD, } template <class Emitter> -VarCreationState ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) { +VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD) { // We don't know what to do with these, so just return false. if (VD->getType().isNull()) return false; @@ -3502,8 +3549,8 @@ VarCreationState ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::visitAPValue(const APValue &Val, - PrimType ValType, const Expr *E) { +bool Compiler<Emitter>::visitAPValue(const APValue &Val, PrimType ValType, + const Expr *E) { assert(!DiscardResult); if (Val.isInt()) return this->emitConst(Val.getInt(), ValType, E); @@ -3529,8 +3576,8 @@ bool ByteCodeExprGen<Emitter>::visitAPValue(const APValue &Val, } template <class Emitter> -bool ByteCodeExprGen<Emitter>::visitAPValueInitializer(const APValue &Val, - const Expr *E) { +bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val, + const Expr *E) { if (Val.isStruct()) { const Record *R = this->getRecord(E->getType()); @@ -3592,7 +3639,7 @@ bool ByteCodeExprGen<Emitter>::visitAPValueInitializer(const APValue &Val, } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) { +bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) { const Function *Func = getFunction(E->getDirectCallee()); if (!Func) return false; @@ -3647,7 +3694,7 @@ bool ByteCodeExprGen<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) { +bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) { if (E->getBuiltinCallee()) return VisitBuiltinCallExpr(E); @@ -3807,8 +3854,7 @@ bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitCXXDefaultInitExpr( - const CXXDefaultInitExpr *E) { +bool Compiler<Emitter>::VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) { SourceLocScope<Emitter> SLS(this, E); bool Old = InitStackActive; @@ -3819,8 +3865,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXDefaultInitExpr( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitCXXDefaultArgExpr( - const CXXDefaultArgExpr *E) { +bool Compiler<Emitter>::VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) { SourceLocScope<Emitter> SLS(this, E); const Expr *SubExpr = E->getExpr(); @@ -3832,8 +3877,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXDefaultArgExpr( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitCXXBoolLiteralExpr( - const CXXBoolLiteralExpr *E) { +bool Compiler<Emitter>::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) { if (DiscardResult) return true; @@ -3841,7 +3885,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXBoolLiteralExpr( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitCXXNullPtrLiteralExpr( +bool Compiler<Emitter>::VisitCXXNullPtrLiteralExpr( const CXXNullPtrLiteralExpr *E) { if (DiscardResult) return true; @@ -3850,7 +3894,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXNullPtrLiteralExpr( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitGNUNullExpr(const GNUNullExpr *E) { +bool Compiler<Emitter>::VisitGNUNullExpr(const GNUNullExpr *E) { if (DiscardResult) return true; @@ -3861,7 +3905,7 @@ bool ByteCodeExprGen<Emitter>::VisitGNUNullExpr(const GNUNullExpr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitCXXThisExpr(const CXXThisExpr *E) { +bool Compiler<Emitter>::VisitCXXThisExpr(const CXXThisExpr *E) { if (DiscardResult) return true; @@ -3885,8 +3929,640 @@ bool ByteCodeExprGen<Emitter>::VisitCXXThisExpr(const CXXThisExpr *E) { return this->emitThis(E); } +template <class Emitter> bool Compiler<Emitter>::visitStmt(const Stmt *S) { + switch (S->getStmtClass()) { + case Stmt::CompoundStmtClass: + return visitCompoundStmt(cast<CompoundStmt>(S)); + case Stmt::DeclStmtClass: + return visitDeclStmt(cast<DeclStmt>(S)); + case Stmt::ReturnStmtClass: + return visitReturnStmt(cast<ReturnStmt>(S)); + case Stmt::IfStmtClass: + return visitIfStmt(cast<IfStmt>(S)); + case Stmt::WhileStmtClass: + return visitWhileStmt(cast<WhileStmt>(S)); + case Stmt::DoStmtClass: + return visitDoStmt(cast<DoStmt>(S)); + case Stmt::ForStmtClass: + return visitForStmt(cast<ForStmt>(S)); + case Stmt::CXXForRangeStmtClass: + return visitCXXForRangeStmt(cast<CXXForRangeStmt>(S)); + case Stmt::BreakStmtClass: + return visitBreakStmt(cast<BreakStmt>(S)); + case Stmt::ContinueStmtClass: + return visitContinueStmt(cast<ContinueStmt>(S)); + case Stmt::SwitchStmtClass: + return visitSwitchStmt(cast<SwitchStmt>(S)); + case Stmt::CaseStmtClass: + return visitCaseStmt(cast<CaseStmt>(S)); + case Stmt::DefaultStmtClass: + return visitDefaultStmt(cast<DefaultStmt>(S)); + case Stmt::AttributedStmtClass: + return visitAttributedStmt(cast<AttributedStmt>(S)); + case Stmt::CXXTryStmtClass: + return visitCXXTryStmt(cast<CXXTryStmt>(S)); + case Stmt::NullStmtClass: + return true; + // Always invalid statements. + case Stmt::GCCAsmStmtClass: + case Stmt::MSAsmStmtClass: + case Stmt::GotoStmtClass: + return this->emitInvalid(S); + case Stmt::LabelStmtClass: + return this->visitStmt(cast<LabelStmt>(S)->getSubStmt()); + default: { + if (const auto *E = dyn_cast<Expr>(S)) + return this->discard(E); + return false; + } + } +} + +/// Visits the given statment without creating a variable +/// scope for it in case it is a compound statement. +template <class Emitter> bool Compiler<Emitter>::visitLoopBody(const Stmt *S) { + if (isa<NullStmt>(S)) + return true; + + if (const auto *CS = dyn_cast<CompoundStmt>(S)) { + for (auto *InnerStmt : CS->body()) + if (!visitStmt(InnerStmt)) + return false; + return true; + } + + return this->visitStmt(S); +} + +template <class Emitter> +bool Compiler<Emitter>::visitCompoundStmt(const CompoundStmt *S) { + BlockScope<Emitter> Scope(this); + for (auto *InnerStmt : S->body()) + if (!visitStmt(InnerStmt)) + return false; + return true; +} + +template <class Emitter> +bool Compiler<Emitter>::visitDeclStmt(const DeclStmt *DS) { + for (auto *D : DS->decls()) { + if (isa<StaticAssertDecl, TagDecl, TypedefNameDecl, UsingEnumDecl, + FunctionDecl>(D)) + continue; + + const auto *VD = dyn_cast<VarDecl>(D); + if (!VD) + return false; + if (!this->visitVarDecl(VD)) + return false; + } + + return true; +} + +template <class Emitter> +bool Compiler<Emitter>::visitReturnStmt(const ReturnStmt *RS) { + if (const Expr *RE = RS->getRetValue()) { + ExprScope<Emitter> RetScope(this); + if (ReturnType) { + // Primitive types are simply returned. + if (!this->visit(RE)) + return false; + this->emitCleanup(); + return this->emitRet(*ReturnType, RS); + } else if (RE->getType()->isVoidType()) { + if (!this->visit(RE)) + return false; + } else { + // RVO - construct the value in the return location. + if (!this->emitRVOPtr(RE)) + return false; + if (!this->visitInitializer(RE)) + return false; + if (!this->emitPopPtr(RE)) + return false; + + this->emitCleanup(); + return this->emitRetVoid(RS); + } + } + + // Void return. + this->emitCleanup(); + return this->emitRetVoid(RS); +} + +template <class Emitter> bool Compiler<Emitter>::visitIfStmt(const IfStmt *IS) { + BlockScope<Emitter> IfScope(this); + + if (IS->isNonNegatedConsteval()) + return visitStmt(IS->getThen()); + if (IS->isNegatedConsteval()) + return IS->getElse() ? visitStmt(IS->getElse()) : true; + + if (auto *CondInit = IS->getInit()) + if (!visitStmt(CondInit)) + return false; + + if (const DeclStmt *CondDecl = IS->getConditionVariableDeclStmt()) + if (!visitDeclStmt(CondDecl)) + return false; + + if (!this->visitBool(IS->getCond())) + return false; + + if (const Stmt *Else = IS->getElse()) { + LabelTy LabelElse = this->getLabel(); + LabelTy LabelEnd = this->getLabel(); + if (!this->jumpFalse(LabelElse)) + return false; + if (!visitStmt(IS->getThen())) + return false; + if (!this->jump(LabelEnd)) + return false; + this->emitLabel(LabelElse); + if (!visitStmt(Else)) + return false; + this->emitLabel(LabelEnd); + } else { + LabelTy LabelEnd = this->getLabel(); + if (!this->jumpFalse(LabelEnd)) + return false; + if (!visitStmt(IS->getThen())) + return false; + this->emitLabel(LabelEnd); + } + + return true; +} + +template <class Emitter> +bool Compiler<Emitter>::visitWhileStmt(const WhileStmt *S) { + const Expr *Cond = S->getCond(); + const Stmt *Body = S->getBody(); + + LabelTy CondLabel = this->getLabel(); // Label before the condition. + LabelTy EndLabel = this->getLabel(); // Label after the loop. + LoopScope<Emitter> LS(this, EndLabel, CondLabel); + + this->emitLabel(CondLabel); + + if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt()) + if (!visitDeclStmt(CondDecl)) + return false; + + if (!this->visitBool(Cond)) + return false; + if (!this->jumpFalse(EndLabel)) + return false; + + LocalScope<Emitter> Scope(this); + { + DestructorScope<Emitter> DS(Scope); + if (!this->visitLoopBody(Body)) + return false; + } + + if (!this->jump(CondLabel)) + return false; + this->emitLabel(EndLabel); + + return true; +} + +template <class Emitter> bool Compiler<Emitter>::visitDoStmt(const DoStmt *S) { + const Expr *Cond = S->getCond(); + const Stmt *Body = S->getBody(); + + LabelTy StartLabel = this->getLabel(); + LabelTy EndLabel = this->getLabel(); + LabelTy CondLabel = this->getLabel(); + LoopScope<Emitter> LS(this, EndLabel, CondLabel); + LocalScope<Emitter> Scope(this); + + this->emitLabel(StartLabel); + { + DestructorScope<Emitter> DS(Scope); + + if (!this->visitLoopBody(Body)) + return false; + this->emitLabel(CondLabel); + if (!this->visitBool(Cond)) + return false; + } + if (!this->jumpTrue(StartLabel)) + return false; + + this->emitLabel(EndLabel); + return true; +} + +template <class Emitter> +bool Compiler<Emitter>::visitForStmt(const ForStmt *S) { + // for (Init; Cond; Inc) { Body } + const Stmt *Init = S->getInit(); + const Expr *Cond = S->getCond(); + const Expr *Inc = S->getInc(); + const Stmt *Body = S->getBody(); + + LabelTy EndLabel = this->getLabel(); + LabelTy CondLabel = this->getLabel(); + LabelTy IncLabel = this->getLabel(); + LoopScope<Emitter> LS(this, EndLabel, IncLabel); + LocalScope<Emitter> Scope(this); + + if (Init && !this->visitStmt(Init)) + return false; + this->emitLabel(CondLabel); + + if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt()) + if (!visitDeclStmt(CondDecl)) + return false; + + if (Cond) { + if (!this->visitBool(Cond)) + return false; + if (!this->jumpFalse(EndLabel)) + return false; + } + + { + DestructorScope<Emitter> DS(Scope); + + if (Body && !this->visitLoopBody(Body)) + return false; + this->emitLabel(IncLabel); + if (Inc && !this->discard(Inc)) + return false; + } + + if (!this->jump(CondLabel)) + return false; + this->emitLabel(EndLabel); + return true; +} + +template <class Emitter> +bool Compiler<Emitter>::visitCXXForRangeStmt(const CXXForRangeStmt *S) { + const Stmt *Init = S->getInit(); + const Expr *Cond = S->getCond(); + const Expr *Inc = S->getInc(); + const Stmt *Body = S->getBody(); + const Stmt *BeginStmt = S->getBeginStmt(); + const Stmt *RangeStmt = S->getRangeStmt(); + const Stmt *EndStmt = S->getEndStmt(); + const VarDecl *LoopVar = S->getLoopVariable(); + + LabelTy EndLabel = this->getLabel(); + LabelTy CondLabel = this->getLabel(); + LabelTy IncLabel = this->getLabel(); + LoopScope<Emitter> LS(this, EndLabel, IncLabel); + + // Emit declarations needed in the loop. + if (Init && !this->visitStmt(Init)) + return false; + if (!this->visitStmt(RangeStmt)) + return false; + if (!this->visitStmt(BeginStmt)) + return false; + if (!this->visitStmt(EndStmt)) + return false; + + // Now the condition as well as the loop variable assignment. + this->emitLabel(CondLabel); + if (!this->visitBool(Cond)) + return false; + if (!this->jumpFalse(EndLabel)) + return false; + + if (!this->visitVarDecl(LoopVar)) + return false; + + // Body. + LocalScope<Emitter> Scope(this); + { + DestructorScope<Emitter> DS(Scope); + + if (!this->visitLoopBody(Body)) + return false; + this->emitLabel(IncLabel); + if (!this->discard(Inc)) + return false; + } + if (!this->jump(CondLabel)) + return false; + + this->emitLabel(EndLabel); + return true; +} + +template <class Emitter> +bool Compiler<Emitter>::visitBreakStmt(const BreakStmt *S) { + if (!BreakLabel) + return false; + + this->VarScope->emitDestructors(); + return this->jump(*BreakLabel); +} + +template <class Emitter> +bool Compiler<Emitter>::visitContinueStmt(const ContinueStmt *S) { + if (!ContinueLabel) + return false; + + this->VarScope->emitDestructors(); + return this->jump(*ContinueLabel); +} + +template <class Emitter> +bool Compiler<Emitter>::visitSwitchStmt(const SwitchStmt *S) { + const Expr *Cond = S->getCond(); + PrimType CondT = this->classifyPrim(Cond->getType()); + + LabelTy EndLabel = this->getLabel(); + OptLabelTy DefaultLabel = std::nullopt; + unsigned CondVar = this->allocateLocalPrimitive(Cond, CondT, true, false); + + if (const auto *CondInit = S->getInit()) + if (!visitStmt(CondInit)) + return false; + + if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt()) + if (!visitDeclStmt(CondDecl)) + return false; + + // Initialize condition variable. + if (!this->visit(Cond)) + return false; + if (!this->emitSetLocal(CondT, CondVar, S)) + return false; + + CaseMap CaseLabels; + // Create labels and comparison ops for all case statements. + for (const SwitchCase *SC = S->getSwitchCaseList(); SC; + SC = SC->getNextSwitchCase()) { + if (const auto *CS = dyn_cast<CaseStmt>(SC)) { + // FIXME: Implement ranges. + if (CS->caseStmtIsGNURange()) + return false; + CaseLabels[SC] = this->getLabel(); + + const Expr *Value = CS->getLHS(); + PrimType ValueT = this->classifyPrim(Value->getType()); + + // Compare the case statement's value to the switch condition. + if (!this->emitGetLocal(CondT, CondVar, CS)) + return false; + if (!this->visit(Value)) + return false; + + // Compare and jump to the case label. + if (!this->emitEQ(ValueT, S)) + return false; + if (!this->jumpTrue(CaseLabels[CS])) + return false; + } else { + assert(!DefaultLabel); + DefaultLabel = this->getLabel(); + } + } + + // If none of the conditions above were true, fall through to the default + // statement or jump after the switch statement. + if (DefaultLabel) { + if (!this->jump(*DefaultLabel)) + return false; + } else { + if (!this->jump(EndLabel)) + return false; + } + + SwitchScope<Emitter> SS(this, std::move(CaseLabels), EndLabel, DefaultLabel); + if (!this->visitStmt(S->getBody())) + return false; + this->emitLabel(EndLabel); + return true; +} + +template <class Emitter> +bool Compiler<Emitter>::visitCaseStmt(const CaseStmt *S) { + this->emitLabel(CaseLabels[S]); + return this->visitStmt(S->getSubStmt()); +} + +template <class Emitter> +bool Compiler<Emitter>::visitDefaultStmt(const DefaultStmt *S) { + this->emitLabel(*DefaultLabel); + return this->visitStmt(S->getSubStmt()); +} + +template <class Emitter> +bool Compiler<Emitter>::visitAttributedStmt(const AttributedStmt *S) { + if (this->Ctx.getLangOpts().CXXAssumptions && + !this->Ctx.getLangOpts().MSVCCompat) { + for (const Attr *A : S->getAttrs()) { + auto *AA = dyn_cast<CXXAssumeAttr>(A); + if (!AA) + continue; + + assert(isa<NullStmt>(S->getSubStmt())); + + const Expr *Assumption = AA->getAssumption(); + if (Assumption->isValueDependent()) + return false; + + if (Assumption->HasSideEffects(this->Ctx.getASTContext())) + continue; + + // Evaluate assumption. + if (!this->visitBool(Assumption)) + return false; + + if (!this->emitAssume(Assumption)) + return false; + } + } + + // Ignore other attributes. + return this->visitStmt(S->getSubStmt()); +} + +template <class Emitter> +bool Compiler<Emitter>::visitCXXTryStmt(const CXXTryStmt *S) { + // Ignore all handlers. + return this->visitStmt(S->getTryBlock()); +} + +template <class Emitter> +bool Compiler<Emitter>::emitLambdaStaticInvokerBody(const CXXMethodDecl *MD) { + assert(MD->isLambdaStaticInvoker()); + assert(MD->hasBody()); + assert(cast<CompoundStmt>(MD->getBody())->body_empty()); + + const CXXRecordDecl *ClosureClass = MD->getParent(); + const CXXMethodDecl *LambdaCallOp = ClosureClass->getLambdaCallOperator(); + assert(ClosureClass->captures_begin() == ClosureClass->captures_end()); + const Function *Func = this->getFunction(LambdaCallOp); + if (!Func) + return false; + assert(Func->hasThisPointer()); + assert(Func->getNumParams() == (MD->getNumParams() + 1 + Func->hasRVO())); + + if (Func->hasRVO()) { + if (!this->emitRVOPtr(MD)) + return false; + } + + // The lambda call operator needs an instance pointer, but we don't have + // one here, and we don't need one either because the lambda cannot have + // any captures, as verified above. Emit a null pointer. This is then + // special-cased when interpreting to not emit any misleading diagnostics. + if (!this->emitNullPtr(nullptr, MD)) + return false; + + // Forward all arguments from the static invoker to the lambda call operator. + for (const ParmVarDecl *PVD : MD->parameters()) { + auto It = this->Params.find(PVD); + assert(It != this->Params.end()); + + // We do the lvalue-to-rvalue conversion manually here, so no need + // to care about references. + PrimType ParamType = this->classify(PVD->getType()).value_or(PT_Ptr); + if (!this->emitGetParam(ParamType, It->second.Offset, MD)) + return false; + } + + if (!this->emitCall(Func, 0, LambdaCallOp)) + return false; + + this->emitCleanup(); + if (ReturnType) + return this->emitRet(*ReturnType, MD); + + // Nothing to do, since we emitted the RVO pointer above. + return this->emitRetVoid(MD); +} + +template <class Emitter> +bool Compiler<Emitter>::visitFunc(const FunctionDecl *F) { + // Classify the return type. + ReturnType = this->classify(F->getReturnType()); + + auto emitFieldInitializer = [&](const Record::Field *F, unsigned FieldOffset, + const Expr *InitExpr) -> bool { + // We don't know what to do with these, so just return false. + if (InitExpr->getType().isNull()) + return false; + + if (std::optional<PrimType> T = this->classify(InitExpr)) { + if (!this->visit(InitExpr)) + return false; + + if (F->isBitField()) + return this->emitInitThisBitField(*T, F, FieldOffset, InitExpr); + return this->emitInitThisField(*T, FieldOffset, InitExpr); + } + // Non-primitive case. Get a pointer to the field-to-initialize + // on the stack and call visitInitialzer() for it. + InitLinkScope<Emitter> FieldScope(this, InitLink::Field(F->Offset)); + if (!this->emitGetPtrThisField(FieldOffset, InitExpr)) + return false; + + if (!this->visitInitializer(InitExpr)) + return false; + + return this->emitPopPtr(InitExpr); + }; + + // Emit custom code if this is a lambda static invoker. + if (const auto *MD = dyn_cast<CXXMethodDecl>(F); + MD && MD->isLambdaStaticInvoker()) + return this->emitLambdaStaticInvokerBody(MD); + + // Constructor. Set up field initializers. + if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(F)) { + const RecordDecl *RD = Ctor->getParent(); + const Record *R = this->getRecord(RD); + if (!R) + return false; + + InitLinkScope<Emitter> InitScope(this, InitLink::This()); + for (const auto *Init : Ctor->inits()) { + // Scope needed for the initializers. + BlockScope<Emitter> Scope(this); + + const Expr *InitExpr = Init->getInit(); + if (const FieldDecl *Member = Init->getMember()) { + const Record::Field *F = R->getField(Member); + + if (!emitFieldInitializer(F, F->Offset, InitExpr)) + return false; + } else if (const Type *Base = Init->getBaseClass()) { + const auto *BaseDecl = Base->getAsCXXRecordDecl(); + assert(BaseDecl); + + if (Init->isBaseVirtual()) { + assert(R->getVirtualBase(BaseDecl)); + if (!this->emitGetPtrThisVirtBase(BaseDecl, InitExpr)) + return false; + + } else { + // Base class initializer. + // Get This Base and call initializer on it. + const Record::Base *B = R->getBase(BaseDecl); + assert(B); + if (!this->emitGetPtrThisBase(B->Offset, InitExpr)) + return false; + } + + if (!this->visitInitializer(InitExpr)) + return false; + if (!this->emitFinishInitPop(InitExpr)) + return false; + } else if (const IndirectFieldDecl *IFD = Init->getIndirectMember()) { + assert(IFD->getChainingSize() >= 2); + + unsigned NestedFieldOffset = 0; + const Record::Field *NestedField = nullptr; + for (const NamedDecl *ND : IFD->chain()) { + const auto *FD = cast<FieldDecl>(ND); + const Record *FieldRecord = + this->P.getOrCreateRecord(FD->getParent()); + assert(FieldRecord); + + NestedField = FieldRecord->getField(FD); + assert(NestedField); + + NestedFieldOffset += NestedField->Offset; + } + assert(NestedField); + + if (!emitFieldInitializer(NestedField, NestedFieldOffset, InitExpr)) + return false; + } else { + assert(Init->isDelegatingInitializer()); + if (!this->emitThis(InitExpr)) + return false; + if (!this->visitInitializer(Init->getInit())) + return false; + if (!this->emitPopPtr(InitExpr)) + return false; + } + } + } + + if (const auto *Body = F->getBody()) + if (!visitStmt(Body)) + return false; + + // Emit a guard return to protect against a code path missing one. + if (F->getReturnType()->isVoidType()) + return this->emitRetVoid(SourceInfo{}); + return this->emitNoRet(SourceInfo{}); +} + template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) { +bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) { const Expr *SubExpr = E->getSubExpr(); if (SubExpr->getType()->isAnyComplexType()) return this->VisitComplexUnaryOperator(E); @@ -4046,7 +4722,7 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) { if (!this->visit(SubExpr)) return false; return DiscardResult ? this->emitPop(*T, E) : this->emitNeg(*T, E); - case UO_Plus: // +x + case UO_Plus: // +x if (!this->visit(SubExpr)) // noop return false; return DiscardResult ? this->emitPop(*T, E) : true; @@ -4058,11 +4734,11 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) { } // We should already have a pointer when we get here. return this->delegate(SubExpr); - case UO_Deref: // *x + case UO_Deref: // *x if (DiscardResult) return this->discard(SubExpr); return this->visit(SubExpr); - case UO_Not: // ~x + case UO_Not: // ~x if (!this->visit(SubExpr)) return false; return DiscardResult ? this->emitPop(*T, E) : this->emitComp(*T, E); @@ -4085,8 +4761,7 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitComplexUnaryOperator( - const UnaryOperator *E) { +bool Compiler<Emitter>::VisitComplexUnaryOperator(const UnaryOperator *E) { const Expr *SubExpr = E->getSubExpr(); assert(SubExpr->getType()->isAnyComplexType()); @@ -4193,7 +4868,7 @@ bool ByteCodeExprGen<Emitter>::VisitComplexUnaryOperator( } template <class Emitter> -bool ByteCodeExprGen<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) { +bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) { if (DiscardResult) return true; @@ -4322,21 +4997,19 @@ bool ByteCodeExprGen<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) { +bool Compiler<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) { const auto *D = E->getDecl(); return this->visitDeclRef(D, E); } -template <class Emitter> -void ByteCodeExprGen<Emitter>::emitCleanup() { +template <class Emitter> void Compiler<Emitter>::emitCleanup() { for (VariableScope<Emitter> *C = VarScope; C; C = C->getParent()) C->emitDestruction(); } template <class Emitter> -unsigned -ByteCodeExprGen<Emitter>::collectBaseOffset(const QualType BaseType, - const QualType DerivedType) { +unsigned Compiler<Emitter>::collectBaseOffset(const QualType BaseType, + const QualType DerivedType) { const auto extractRecordDecl = [](QualType Ty) -> const CXXRecordDecl * { if (const auto *PT = dyn_cast<PointerType>(Ty)) return PT->getPointeeType()->getAsCXXRecordDecl(); @@ -4350,8 +5023,8 @@ ByteCodeExprGen<Emitter>::collectBaseOffset(const QualType BaseType, /// Emit casts from a PrimType to another PrimType. template <class Emitter> -bool ByteCodeExprGen<Emitter>::emitPrimCast(PrimType FromT, PrimType ToT, - QualType ToQT, const Expr *E) { +bool Compiler<Emitter>::emitPrimCast(PrimType FromT, PrimType ToT, + QualType ToQT, const Expr *E) { if (FromT == PT_Float) { // Floating to floating. @@ -4393,7 +5066,7 @@ bool ByteCodeExprGen<Emitter>::emitPrimCast(PrimType FromT, PrimType ToT, /// Emits __real(SubExpr) template <class Emitter> -bool ByteCodeExprGen<Emitter>::emitComplexReal(const Expr *SubExpr) { +bool Compiler<Emitter>::emitComplexReal(const Expr *SubExpr) { assert(SubExpr->getType()->isAnyComplexType()); if (DiscardResult) @@ -4413,7 +5086,7 @@ bool ByteCodeExprGen<Emitter>::emitComplexReal(const Expr *SubExpr) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::emitComplexBoolCast(const Expr *E) { +bool Compiler<Emitter>::emitComplexBoolCast(const Expr *E) { assert(!DiscardResult); PrimType ElemT = classifyComplexElementType(E->getType()); // We emit the expression (__real(E) != 0 || __imag(E) != 0) @@ -4459,9 +5132,8 @@ bool ByteCodeExprGen<Emitter>::emitComplexBoolCast(const Expr *E) { } template <class Emitter> -bool ByteCodeExprGen<Emitter>::emitComplexComparison(const Expr *LHS, - const Expr *RHS, - const BinaryOperator *E) { +bool Compiler<Emitter>::emitComplexComparison(const Expr *LHS, const Expr *RHS, + const BinaryOperator *E) { assert(E->isComparisonOp()); assert(!Initializing); assert(!DiscardResult); @@ -4558,7 +5230,7 @@ bool ByteCodeExprGen<Emitter>::emitComplexComparison(const Expr *LHS, /// on the stack. /// Emit destruction of record types (or arrays of record types). template <class Emitter> -bool ByteCodeExprGen<Emitter>::emitRecordDestruction(const Record *R) { +bool Compiler<Emitter>::emitRecordDestruction(const Record *R) { assert(R); // First, destroy all fields. for (const Record::Field &Field : llvm::reverse(R->fields())) { @@ -4606,7 +5278,7 @@ bool ByteCodeExprGen<Emitter>::emitRecordDestruction(const Record *R) { /// on the stack. /// Emit destruction of record types (or arrays of record types). template <class Emitter> -bool ByteCodeExprGen<Emitter>::emitDestruction(const Descriptor *Desc) { +bool Compiler<Emitter>::emitDestruction(const Descriptor *Desc) { assert(Desc); assert(!Desc->isPrimitive()); assert(!Desc->isPrimitiveArray()); @@ -4649,8 +5321,8 @@ bool ByteCodeExprGen<Emitter>::emitDestruction(const Descriptor *Desc) { namespace clang { namespace interp { -template class ByteCodeExprGen<ByteCodeEmitter>; -template class ByteCodeExprGen<EvalEmitter>; +template class Compiler<ByteCodeEmitter>; +template class Compiler<EvalEmitter>; } // namespace interp } // namespace clang diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/Compiler.h similarity index 87% rename from clang/lib/AST/Interp/ByteCodeExprGen.h rename to clang/lib/AST/Interp/Compiler.h index 88e9eddd55be4..89e36f9201a41 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/Compiler.h @@ -1,4 +1,4 @@ -//===--- ByteCodeExprGen.h - Code generator for expressions -----*- C++ -*-===// +//===--- Compiler.h - Code generator for expressions -----*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -36,8 +36,11 @@ template <class Emitter> class InitLinkScope; template <class Emitter> class OptionScope; template <class Emitter> class ArrayIndexScope; template <class Emitter> class SourceLocScope; +template <class Emitter> class LoopScope; +template <class Emitter> class LabelScope; +template <class Emitter> class SwitchScope; -template <class Emitter> class ByteCodeExprGen; +template <class Emitter> class Compiler; struct InitLink { public: enum { @@ -60,7 +63,7 @@ struct InitLink { InitLink(uint8_t Kind) : Kind(Kind) {} template <class Emitter> - bool emit(ByteCodeExprGen<Emitter> *Ctx, const Expr *E) const; + bool emit(Compiler<Emitter> *Ctx, const Expr *E) const; private: uint32_t Kind; @@ -84,12 +87,14 @@ struct VarCreationState { /// Compilation context for expressions. template <class Emitter> -class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>, - public Emitter { +class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>, + public Emitter { protected: // Aliases for types defined in the emitter. using LabelTy = typename Emitter::LabelTy; using AddrTy = typename Emitter::AddrTy; + using OptLabelTy = std::optional<LabelTy>; + using CaseMap = llvm::DenseMap<const SwitchCase *, LabelTy>; /// Current compilation context. Context &Ctx; @@ -99,10 +104,10 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>, public: /// Initializes the compiler and the backend emitter. template <typename... Tys> - ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args) + Compiler(Context &Ctx, Program &P, Tys &&...Args) : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {} - // Expression visitors - result returned on interp stack. + // Expressions. bool VisitCastExpr(const CastExpr *E); bool VisitIntegerLiteral(const IntegerLiteral *E); bool VisitFloatingLiteral(const FloatingLiteral *E); @@ -179,9 +184,29 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>, bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E); bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E); + // Statements. + bool visitCompoundStmt(const CompoundStmt *S); + bool visitLoopBody(const Stmt *S); + bool visitDeclStmt(const DeclStmt *DS); + bool visitReturnStmt(const ReturnStmt *RS); + bool visitIfStmt(const IfStmt *IS); + bool visitWhileStmt(const WhileStmt *S); + bool visitDoStmt(const DoStmt *S); + bool visitForStmt(const ForStmt *S); + bool visitCXXForRangeStmt(const CXXForRangeStmt *S); + bool visitBreakStmt(const BreakStmt *S); + bool visitContinueStmt(const ContinueStmt *S); + bool visitSwitchStmt(const SwitchStmt *S); + bool visitCaseStmt(const CaseStmt *S); + bool visitDefaultStmt(const DefaultStmt *S); + bool visitAttributedStmt(const AttributedStmt *S); + bool visitCXXTryStmt(const CXXTryStmt *S); + protected: + bool visitStmt(const Stmt *S); bool visitExpr(const Expr *E) override; bool visitDecl(const VarDecl *VD, bool ConstantContext) override; + bool visitFunc(const FunctionDecl *F) override; protected: /// Emits scope cleanup instructions. @@ -194,8 +219,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>, Record *getRecord(QualType Ty); Record *getRecord(const RecordDecl *RD); - // Returns a function for the given FunctionDecl. - // If the function does not exist yet, it is compiled. + /// Returns a function for the given FunctionDecl. + /// If the function does not exist yet, it is compiled. const Function *getFunction(const FunctionDecl *FD); std::optional<PrimType> classify(const Expr *E) const { @@ -305,6 +330,9 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>, friend class ArrayIndexScope<Emitter>; friend class SourceLocScope<Emitter>; friend struct InitLink; + friend class LoopScope<Emitter>; + friend class LabelScope<Emitter>; + friend class SwitchScope<Emitter>; /// Emits a zero initializer. bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E); @@ -348,6 +376,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>, bool emitDestruction(const Descriptor *Desc); unsigned collectBaseOffset(const QualType BaseType, const QualType DerivedType); + bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD); protected: /// Variable to storage mapping. @@ -378,15 +407,28 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>, /// Flag indicating if we're initializing a global variable. bool GlobalDecl = false; + + /// Type of the expression returned by the function. + std::optional<PrimType> ReturnType; + + /// Switch case mapping. + CaseMap CaseLabels; + + /// Point to break to. + OptLabelTy BreakLabel; + /// Point to continue to. + OptLabelTy ContinueLabel; + /// Default case label. + OptLabelTy DefaultLabel; }; -extern template class ByteCodeExprGen<ByteCodeEmitter>; -extern template class ByteCodeExprGen<EvalEmitter>; +extern template class Compiler<ByteCodeEmitter>; +extern template class Compiler<EvalEmitter>; /// Scope chain managing the variable lifetimes. template <class Emitter> class VariableScope { public: - VariableScope(ByteCodeExprGen<Emitter> *Ctx, const ValueDecl *VD) + VariableScope(Compiler<Emitter> *Ctx, const ValueDecl *VD) : Ctx(Ctx), Parent(Ctx->VarScope), ValDecl(VD) { Ctx->VarScope = this; } @@ -433,8 +475,8 @@ template <class Emitter> class VariableScope { VariableScope *getParent() const { return Parent; } protected: - /// ByteCodeExprGen instance. - ByteCodeExprGen<Emitter> *Ctx; + /// Compiler instance. + Compiler<Emitter> *Ctx; /// Link to the parent scope. VariableScope *Parent; const ValueDecl *ValDecl = nullptr; @@ -443,8 +485,7 @@ template <class Emitter> class VariableScope { /// Generic scope for local variables. template <class Emitter> class LocalScope : public VariableScope<Emitter> { public: - LocalScope(ByteCodeExprGen<Emitter> *Ctx) - : VariableScope<Emitter>(Ctx, nullptr) {} + LocalScope(Compiler<Emitter> *Ctx) : VariableScope<Emitter>(Ctx, nullptr) {} /// Emit a Destroy op for this scope. ~LocalScope() override { @@ -538,8 +579,7 @@ template <class Emitter> class DestructorScope final { /// variables are automatically emitted when the AutoScope is destroyed. template <class Emitter> class AutoScope : public LocalScope<Emitter> { public: - AutoScope(ByteCodeExprGen<Emitter> *Ctx) - : LocalScope<Emitter>(Ctx), DS(*this) {} + AutoScope(Compiler<Emitter> *Ctx) : LocalScope<Emitter>(Ctx), DS(*this) {} private: DestructorScope<Emitter> DS; @@ -548,7 +588,7 @@ template <class Emitter> class AutoScope : public LocalScope<Emitter> { /// Scope for storage declared in a compound statement. template <class Emitter> class BlockScope final : public AutoScope<Emitter> { public: - BlockScope(ByteCodeExprGen<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {} + BlockScope(Compiler<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {} void addExtended(const Scope::Local &Local) override { // If we to this point, just add the variable as a normal local @@ -560,12 +600,12 @@ template <class Emitter> class BlockScope final : public AutoScope<Emitter> { template <class Emitter> class ExprScope final : public AutoScope<Emitter> { public: - ExprScope(ByteCodeExprGen<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {} + ExprScope(Compiler<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {} }; template <class Emitter> class ArrayIndexScope final { public: - ArrayIndexScope(ByteCodeExprGen<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) { + ArrayIndexScope(Compiler<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) { OldArrayIndex = Ctx->ArrayIndex; Ctx->ArrayIndex = Index; } @@ -573,14 +613,13 @@ template <class Emitter> class ArrayIndexScope final { ~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; } private: - ByteCodeExprGen<Emitter> *Ctx; + Compiler<Emitter> *Ctx; std::optional<uint64_t> OldArrayIndex; }; template <class Emitter> class SourceLocScope final { public: - SourceLocScope(ByteCodeExprGen<Emitter> *Ctx, const Expr *DefaultExpr) - : Ctx(Ctx) { + SourceLocScope(Compiler<Emitter> *Ctx, const Expr *DefaultExpr) : Ctx(Ctx) { assert(DefaultExpr); // We only switch if the current SourceLocDefaultExpr is null. if (!Ctx->SourceLocDefaultExpr) { @@ -595,20 +634,20 @@ template <class Emitter> class SourceLocScope final { } private: - ByteCodeExprGen<Emitter> *Ctx; + Compiler<Emitter> *Ctx; bool Enabled = false; }; template <class Emitter> class InitLinkScope final { public: - InitLinkScope(ByteCodeExprGen<Emitter> *Ctx, InitLink &&Link) : Ctx(Ctx) { + InitLinkScope(Compiler<Emitter> *Ctx, InitLink &&Link) : Ctx(Ctx) { Ctx->InitStack.push_back(std::move(Link)); } ~InitLinkScope() { this->Ctx->InitStack.pop_back(); } private: - ByteCodeExprGen<Emitter> *Ctx; + Compiler<Emitter> *Ctx; }; } // namespace interp diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp index 98d1837204ebc..22ccae4fa30f8 100644 --- a/clang/lib/AST/Interp/Context.cpp +++ b/clang/lib/AST/Interp/Context.cpp @@ -8,8 +8,7 @@ #include "Context.h" #include "ByteCodeEmitter.h" -#include "ByteCodeExprGen.h" -#include "ByteCodeStmtGen.h" +#include "Compiler.h" #include "EvalEmitter.h" #include "Interp.h" #include "InterpFrame.h" @@ -30,7 +29,7 @@ bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) { assert(Stk.empty()); Function *Func = P->getFunction(FD); if (!Func || !Func->hasBody()) - Func = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD); + Func = Compiler<ByteCodeEmitter>(*this, *P).compileFunc(FD); APValue DummyResult; if (!Run(Parent, Func, DummyResult)) @@ -41,7 +40,7 @@ bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) { bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) { bool Recursing = !Stk.empty(); - ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk); + Compiler<EvalEmitter> C(*this, *P, Parent, Stk); auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/E->isGLValue()); @@ -67,7 +66,7 @@ bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) { bool Context::evaluate(State &Parent, const Expr *E, APValue &Result) { bool Recursing = !Stk.empty(); - ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk); + Compiler<EvalEmitter> C(*this, *P, Parent, Stk); auto Res = C.interpretExpr(E); if (Res.isInvalid()) { @@ -92,7 +91,7 @@ bool Context::evaluate(State &Parent, const Expr *E, APValue &Result) { bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD, APValue &Result) { bool Recursing = !Stk.empty(); - ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk); + Compiler<EvalEmitter> C(*this, *P, Parent, Stk); bool CheckGlobalInitialized = shouldBeGloballyIndexed(VD) && @@ -261,7 +260,7 @@ const Function *Context::getOrCreateFunction(const FunctionDecl *FD) { return Func; if (!Func || WasNotDefined) { - if (auto F = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD)) + if (auto F = Compiler<ByteCodeEmitter>(*this, *P).compileFunc(FD)) Func = F; } diff --git a/clang/lib/AST/Interp/EvalEmitter.h b/clang/lib/AST/Interp/EvalEmitter.h index e85f37d757b69..109e6e0bc0d76 100644 --- a/clang/lib/AST/Interp/EvalEmitter.h +++ b/clang/lib/AST/Interp/EvalEmitter.h @@ -56,6 +56,7 @@ class EvalEmitter : public SourceMapper { /// Methods implemented by the compiler. virtual bool visitExpr(const Expr *E) = 0; virtual bool visitDecl(const VarDecl *VD, bool ConstantContext) = 0; + virtual bool visitFunc(const FunctionDecl *F) = 0; /// Emits jumps. bool jumpTrue(const LabelTy &Label); diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp index 7b1f719779e90..caff9d01cdfee 100644 --- a/clang/lib/AST/Interp/Program.cpp +++ b/clang/lib/AST/Interp/Program.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "Program.h" -#include "ByteCodeStmtGen.h" #include "Context.h" #include "Function.h" #include "Integral.h" _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits