https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/151833
>From 2be4164de3317ad592d63a849010a5dffdeaff3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com> Date: Sat, 2 Aug 2025 19:50:48 +0200 Subject: [PATCH] [clang][bytecode] Try to load local and global variables directly Instead of doing a GetPtrLocal + Load or GetPtrGlobal + Load pair, try to load the value directly. --- clang/lib/AST/ByteCode/Compiler.cpp | 27 ++++++++++++--- clang/lib/AST/ByteCode/EvalEmitter.cpp | 4 +++ clang/lib/AST/ByteCode/Interp.cpp | 48 +++++++++++++++++--------- clang/lib/AST/ByteCode/Interp.h | 13 +++---- clang/test/AST/ByteCode/cxx11.cpp | 13 +++++++ 5 files changed, 75 insertions(+), 30 deletions(-) diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 6e451acd4b6b4..7a5bd4dfc0bed 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -201,6 +201,28 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { return this->emitInvalidCast(CastKind::Volatile, /*Fatal=*/true, CE); OptPrimType SubExprT = classify(SubExpr->getType()); + // Try to load the value directly. This is purely a performance + // optimization. + if (SubExprT) { + if (const auto *DRE = dyn_cast<DeclRefExpr>(SubExpr)) { + const ValueDecl *D = DRE->getDecl(); + bool IsReference = D->getType()->isReferenceType(); + + if (!IsReference) { + if (Context::shouldBeGloballyIndexed(D)) { + if (auto GlobalIndex = P.getGlobal(D)) + return this->emitGetGlobal(*SubExprT, *GlobalIndex, CE); + } else if (auto It = Locals.find(D); It != Locals.end()) { + return this->emitGetLocal(*SubExprT, It->second.Offset, CE); + } else if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) { + if (auto It = this->Params.find(PVD); It != this->Params.end()) { + return this->emitGetParam(*SubExprT, It->second.Offset, CE); + } + } + } + } + } + // Prepare storage for the result. if (!Initializing && !SubExprT) { std::optional<unsigned> LocalIndex = allocateLocal(SubExpr); @@ -3857,10 +3879,7 @@ template <class Emitter> bool Compiler<Emitter>::VisitAddrLabelExpr(const AddrLabelExpr *E) { assert(E->getType()->isVoidPointerType()); - unsigned Offset = - allocateLocalPrimitive(E->getLabel(), PT_Ptr, /*IsConst=*/true); - - return this->emitGetLocal(PT_Ptr, Offset, E); + return this->emitDummyPtr(E, E); } template <class Emitter> diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp index 81ebc5694d6f0..fd7f3423c0f9b 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.cpp +++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp @@ -282,6 +282,10 @@ bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) { using T = typename PrimConv<OpType>::T; Block *B = getLocal(I); + + if (!CheckLocalLoad(S, OpPC, Pointer(B))) + return false; + S.Stk.push<T>(*reinterpret_cast<T *>(B->data())); return true; } diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 224d65c490f54..f2366f674f45b 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -715,23 +715,6 @@ static bool CheckLifetime(InterpState &S, CodePtr OpPC, const Pointer &Ptr, return false; } -bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { - if (Ptr.isInitialized()) - return true; - - assert(S.getLangOpts().CPlusPlus); - const auto *VD = cast<VarDecl>(Ptr.getDeclDesc()->asValueDecl()); - if ((!VD->hasConstantInitialization() && - VD->mightBeUsableInConstantExpressions(S.getASTContext())) || - (S.getLangOpts().OpenCL && !S.getLangOpts().CPlusPlus11 && - !VD->hasICEInitializer(S.getASTContext()))) { - const SourceInfo &Loc = S.Current->getSource(OpPC); - S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD; - S.Note(VD->getLocation(), diag::note_declared_at); - } - return false; -} - static bool CheckWeak(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { if (!Ptr.isWeak()) return true; @@ -745,6 +728,37 @@ static bool CheckWeak(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { return false; } +// The list of checks here is just the one from CheckLoad, but with the +// ones removed that are impossible on primitive global values. +// For example, since those can't be members of structs, they also can't +// be mutable. +bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { + if (!CheckExtern(S, OpPC, Ptr)) + return false; + if (!CheckConstant(S, OpPC, Ptr)) + return false; + if (!CheckDummy(S, OpPC, Ptr, AK_Read)) + return false; + if (!CheckInitialized(S, OpPC, Ptr, AK_Read)) + return false; + if (!CheckTemporary(S, OpPC, Ptr, AK_Read)) + return false; + if (!CheckWeak(S, OpPC, Ptr)) + return false; + if (!CheckVolatile(S, OpPC, Ptr, AK_Read)) + return false; + return true; +} + +// Similarly, for local loads. +bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { + if (!CheckInitialized(S, OpPC, Ptr, AK_Read)) + return false; + if (!CheckVolatile(S, OpPC, Ptr, AK_Read)) + return false; + return true; +} + bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK) { if (!CheckLive(S, OpPC, Ptr, AK)) diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 9a325ab55ca6a..61e776965a006 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -91,8 +91,9 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr); bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK); -/// Check if a global variable is initialized. -bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr); +/// Checks a direct load of a primitive value from a global or local variable. +bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr); +bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr); /// Checks if a value can be stored in a block. bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr); @@ -1465,14 +1466,8 @@ bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) { template <PrimType Name, class T = typename PrimConv<Name>::T> bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { const Pointer &Ptr = S.P.getPtrGlobal(I); - if (!CheckConstant(S, OpPC, Ptr.getFieldDesc())) - return false; - if (Ptr.isExtern()) - return false; - // If a global variable is uninitialized, that means the initializer we've - // compiled for it wasn't a constant expression. Diagnose that. - if (!CheckGlobalInitialized(S, OpPC, Ptr)) + if (!CheckGlobalLoad(S, OpPC, Ptr)) return false; S.Stk.push<T>(Ptr.deref<T>()); diff --git a/clang/test/AST/ByteCode/cxx11.cpp b/clang/test/AST/ByteCode/cxx11.cpp index 378702f9b3620..8a125a497c649 100644 --- a/clang/test/AST/ByteCode/cxx11.cpp +++ b/clang/test/AST/ByteCode/cxx11.cpp @@ -289,3 +289,16 @@ namespace OverlappingStrings { } + +namespace NonConstLocal { + int a() { + const int t=t; // both-note {{declared here}} + + switch(1) { + case t:; // both-note {{initializer of 't' is not a constant expression}} \ + // both-error {{case value is not a constant expression}} + } + } +} + + _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits