https://github.com/tbaederr updated 
https://github.com/llvm/llvm-project/pull/151833

>From d0356829a9749ff703577fff1ea8788f09aedf7a 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/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, 76 insertions(+), 28 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..174cab4abc3b8 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) {
@@ -3860,6 +3884,11 @@ bool Compiler<Emitter>::VisitAddrLabelExpr(const 
AddrLabelExpr *E) {
   unsigned Offset =
       allocateLocalPrimitive(E->getLabel(), PT_Ptr, /*IsConst=*/true);
 
+  if (!this->emitNullPtr(0, nullptr, E))
+    return false;
+  if (!this->emitSetLocal(PT_Ptr, Offset, E))
+    return false;
+
   return this->emitGetLocal(PT_Ptr, Offset, E);
 }
 
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}}
+    }
+  }
+}
+
+

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to