[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 11:13:13 PDT 2025
Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/151833 at github.com>
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/151833
>From 3f106340a4f861e3c452cd1d7d8df52e7a3ddf38 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 1/2] [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 | 19 +++++++++++++++++++
clang/lib/AST/ByteCode/EvalEmitter.cpp | 3 ++-
clang/lib/AST/ByteCode/Function.h | 1 +
clang/lib/AST/ByteCode/Interp.h | 8 +-------
5 files changed, 25 insertions(+), 9 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..ae21d45fa8fa0 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -200,6 +200,25 @@ 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);
+ }
+ }
+ }
+
OptPrimType SubExprT = classify(SubExpr->getType());
// Prepare storage for the result.
if (!Initializing && !SubExprT) {
diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp
index 81ebc5694d6f0..271ffd67ff5fe 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) {
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.h b/clang/lib/AST/ByteCode/Interp.h
index 9a325ab55ca6a..8c77dbd85c950 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -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 (!CheckLoad(S, OpPC, Ptr))
return false;
S.Stk.push<T>(Ptr.deref<T>());
>From cbbdc9dca3ae88ac8ee29be768917bf340da11f6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Sat, 2 Aug 2025 20:12:45 +0200
Subject: [PATCH 2/2] On second thought, include parameters as well.
---
clang/lib/AST/ByteCode/Compiler.cpp | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index ae21d45fa8fa0..863bf00f12bb9 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -215,6 +215,11 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *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);
+ }
}
}
}
More information about the cfe-commits
mailing list