[clang] 839916c - [clang][bytecode] Speed up `EvaluationResult::CheckArrayInitialized()` (#155756)

via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 28 00:14:26 PDT 2025


Author: Timm Baeder
Date: 2025-08-28T09:14:22+02:00
New Revision: 839916c8c92bcf0dbcf4acb5b597f56d240acf78

URL: https://github.com/llvm/llvm-project/commit/839916c8c92bcf0dbcf4acb5b597f56d240acf78
DIFF: https://github.com/llvm/llvm-project/commit/839916c8c92bcf0dbcf4acb5b597f56d240acf78.diff

LOG: [clang][bytecode] Speed up `EvaluationResult::CheckArrayInitialized()` (#155756)

For large primitive arrays, avoid creating a new `Pointer` for every
element (via `Pointer::isElementInitialized()`) or avoid iterating over
the array altogether (via `Pointer::allElementsInitialized()`).

Added: 
    

Modified: 
    clang/lib/AST/ByteCode/EvaluationResult.cpp
    clang/lib/AST/ByteCode/Pointer.cpp
    clang/lib/AST/ByteCode/Pointer.h

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ByteCode/EvaluationResult.cpp b/clang/lib/AST/ByteCode/EvaluationResult.cpp
index de049b4da90a7..773d9f96e5fd9 100644
--- a/clang/lib/AST/ByteCode/EvaluationResult.cpp
+++ b/clang/lib/AST/ByteCode/EvaluationResult.cpp
@@ -62,8 +62,12 @@ static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
 static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc,
                                   const Pointer &BasePtr,
                                   const ConstantArrayType *CAT) {
-  bool Result = true;
   size_t NumElems = CAT->getZExtSize();
+
+  if (NumElems == 0)
+    return true;
+
+  bool Result = true;
   QualType ElemType = CAT->getElementType();
 
   if (ElemType->isRecordType()) {
@@ -78,8 +82,18 @@ static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc,
       Result &= CheckArrayInitialized(S, Loc, ElemPtr, ElemCAT);
     }
   } else {
+    // Primitive arrays.
+    if (S.getContext().canClassify(ElemType)) {
+      if (BasePtr.allElementsInitialized()) {
+        return true;
+      } else {
+        DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField());
+        return false;
+      }
+    }
+
     for (size_t I = 0; I != NumElems; ++I) {
-      if (!BasePtr.atIndex(I).isInitialized()) {
+      if (!BasePtr.isElementInitialized(I)) {
         DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField());
         Result = false;
       }

diff  --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp
index 9fc5b5183f5f6..973bc7cbad62a 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -442,26 +442,42 @@ bool Pointer::isInitialized() const {
   assert(BS.Pointee && "Cannot check if null pointer was initialized");
   const Descriptor *Desc = getFieldDesc();
   assert(Desc);
-  if (Desc->isPrimitiveArray()) {
-    if (isStatic() && BS.Base == 0)
-      return true;
+  if (Desc->isPrimitiveArray())
+    return isElementInitialized(getIndex());
 
-    InitMapPtr &IM = getInitMap();
+  if (asBlockPointer().Base == 0)
+    return true;
+  // Field has its bit in an inline descriptor.
+  return getInlineDesc()->IsInitialized;
+}
+
+bool Pointer::isElementInitialized(unsigned Index) const {
+  if (!isBlockPointer())
+    return true;
+
+  const Descriptor *Desc = getFieldDesc();
+  assert(Desc);
+
+  if (isStatic() && BS.Base == 0)
+    return true;
+
+  if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
+    const GlobalInlineDescriptor &GD =
+        *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
+    return GD.InitState == GlobalInitState::Initialized;
+  }
 
+  if (Desc->isPrimitiveArray()) {
+    InitMapPtr &IM = getInitMap();
     if (!IM)
       return false;
 
     if (IM->first)
       return true;
 
-    return IM->second->isElementInitialized(getIndex());
+    return IM->second->isElementInitialized(Index);
   }
-
-  if (asBlockPointer().Base == 0)
-    return true;
-
-  // Field has its bit in an inline descriptor.
-  return getInlineDesc()->IsInitialized;
+  return isInitialized();
 }
 
 void Pointer::initialize() const {
@@ -524,6 +540,23 @@ void Pointer::initializeAllElements() const {
   }
 }
 
+bool Pointer::allElementsInitialized() const {
+  assert(getFieldDesc()->isPrimitiveArray());
+  assert(isArrayRoot());
+
+  if (isStatic() && BS.Base == 0)
+    return true;
+
+  if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
+    const GlobalInlineDescriptor &GD =
+        *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
+    return GD.InitState == GlobalInitState::Initialized;
+  }
+
+  InitMapPtr &IM = getInitMap();
+  return IM && IM->first;
+}
+
 void Pointer::activate() const {
   // Field has its bit in an inline descriptor.
   assert(BS.Base != 0 && "Only composite fields can be activated");
@@ -771,13 +804,13 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
       R = APValue(APValue::UninitArray{}, NumElems, NumElems);
 
       bool Ok = true;
-      for (unsigned I = 0; I < NumElems; ++I) {
+      OptPrimType ElemT = Ctx.classify(ElemTy);
+      for (unsigned I = 0; I != NumElems; ++I) {
         APValue &Slot = R.getArrayInitializedElt(I);
-        const Pointer &EP = Ptr.atIndex(I);
-        if (OptPrimType T = Ctx.classify(ElemTy)) {
-          TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue(ASTCtx));
+        if (ElemT) {
+          TYPE_SWITCH(*ElemT, Slot = Ptr.elem<T>(I).toAPValue(ASTCtx));
         } else {
-          Ok &= Composite(ElemTy, EP.narrow(), Slot);
+          Ok &= Composite(ElemTy, Ptr.atIndex(I).narrow(), Slot);
         }
       }
       return Ok;

diff  --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index b2e9786b8ac7a..49d701c3e27b6 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -528,8 +528,6 @@ class Pointer {
     assert(isBlockPointer());
     return BS.Pointee->isWeak();
   }
-  /// Checks if an object was initialized.
-  bool isInitialized() const;
   /// Checks if the object is active.
   bool isActive() const {
     if (!isBlockPointer())
@@ -707,6 +705,11 @@ class Pointer {
   /// used in situations where we *know* we have initialized *all* elements
   /// of a primtive array.
   void initializeAllElements() const;
+  /// Checks if an object was initialized.
+  bool isInitialized() const;
+  /// Like isInitialized(), but for primitive arrays.
+  bool isElementInitialized(unsigned Index) const;
+  bool allElementsInitialized() const;
   /// Activats a field.
   void activate() const;
   /// Deactivates an entire strurcutre.


        


More information about the cfe-commits mailing list