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

Reply via email to