[clang] [clang][bytecode] Try to load local and global variables directly (PR #151833)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Sat Aug 2 23:06:24 PDT 2025
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/151833
>From 8ad0af7e8efc3fe1c830a5199642010289a48822 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at 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/ByteCodeEmitter.cpp | 3 +-
clang/lib/AST/ByteCode/Compiler.cpp | 29 +++++++++++++---
clang/lib/AST/ByteCode/EvalEmitter.cpp | 7 +++-
clang/lib/AST/ByteCode/Function.h | 1 +
clang/lib/AST/ByteCode/Interp.cpp | 39 ++++++++++++----------
clang/lib/AST/ByteCode/Interp.h | 12 ++-----
clang/test/AST/ByteCode/cxx11.cpp | 13 ++++++++
7 files changed, 72 insertions(+), 32 deletions(-)
diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
index d4746052c5cfe..3300733335747 100644
--- a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
+++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
@@ -93,10 +93,11 @@ void ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl,
}
Scope::Local ByteCodeEmitter::createLocal(Descriptor *D) {
+ OptPrimType PrimT = D->isPrimitive() ? D->getPrimType() : OptPrimType();
NextLocalOffset += sizeof(Block);
unsigned Location = NextLocalOffset;
NextLocalOffset += align(D->getAllocSize());
- return {Location, D};
+ return {PrimT, Location, D};
}
void ByteCodeEmitter::emitLabel(LabelTy Label) {
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 6e451acd4b6b4..9a38f8cc8a703 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -200,6 +200,30 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
if (SubExpr->getType().isVolatileQualified())
return this->emitInvalidCast(CastKind::Volatile, /*Fatal=*/true, CE);
+ // Try to load the value directly. This is purely a performance
+ // optimization.
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(SubExpr)) {
+ const ValueDecl *D = DRE->getDecl();
+ bool IsReference = D->getType()->isReferenceType();
+
+ if (!IsReference) {
+ if (auto It = Locals.find(D); It != Locals.end()) {
+ OptPrimType PrimT = It->second.PrimT;
+ unsigned Offset = It->second.Offset;
+ if (PrimT)
+ return this->emitGetLocal(*PrimT, Offset, CE);
+ } else if (auto GlobalIndex = P.getGlobal(D)) {
+ if (OptPrimType T = classify(CE))
+ return this->emitGetGlobal(*T, *GlobalIndex, CE);
+ } else if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) {
+ if (auto It = this->Params.find(PVD); It != this->Params.end()) {
+ if (OptPrimType T = classify(CE))
+ return this->emitGetParam(*T, It->second.Offset, CE);
+ }
+ }
+ }
+ }
+
OptPrimType SubExprT = classify(SubExpr->getType());
// Prepare storage for the result.
if (!Initializing && !SubExprT) {
@@ -3857,10 +3881,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..08aae82c0b948 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.cpp
+++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp
@@ -124,9 +124,10 @@ Scope::Local EvalEmitter::createLocal(Descriptor *D) {
Desc.IsInitialized = false;
// Register the local.
+ OptPrimType PrimT = D->isPrimitive() ? D->getPrimType() : OptPrimType();
unsigned Off = Locals.size();
Locals.push_back(std::move(Memory));
- return {Off, D};
+ return {PrimT, Off, D};
}
bool EvalEmitter::jumpTrue(const LabelTy &Label) {
@@ -282,6 +283,10 @@ bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) {
using T = typename PrimConv<OpType>::T;
Block *B = getLocal(I);
+
+ if (!CheckPrimitiveLoad(S, OpPC, Pointer(B)))
+ return false;
+
S.Stk.push<T>(*reinterpret_cast<T *>(B->data()));
return true;
}
diff --git a/clang/lib/AST/ByteCode/Function.h b/clang/lib/AST/ByteCode/Function.h
index de88f3ded34dc..d42438ffde6a1 100644
--- a/clang/lib/AST/ByteCode/Function.h
+++ b/clang/lib/AST/ByteCode/Function.h
@@ -37,6 +37,7 @@ class Scope final {
public:
/// Information about a local's storage.
struct Local {
+ OptPrimType PrimT;
/// Offset of the local in frame.
unsigned Offset;
/// Descriptor of the local.
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 224d65c490f54..4eb341fe1576a 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,28 @@ 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/local values.
+// For example, since those can't be members of structs, they also can't
+// be mutable.
+bool CheckPrimitiveLoad(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;
+}
+
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..d61e9cef70f50 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -91,8 +91,8 @@ 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 CheckPrimitiveLoad(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 +1465,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 (!CheckPrimitiveLoad(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}}
+ }
+ }
+}
+
+
More information about the cfe-commits
mailing list