[clang] [clang][bytecode] Speed up `EvaluationResult::CheckArrayInitialized()` (PR #155756)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 27 23:18:08 PDT 2025
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/155756
>From bbe785eb324a33b8d43a48439a09c03401595e0c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Thu, 28 Aug 2025 06:02:54 +0200
Subject: [PATCH] ElementsInitialized
---
clang/lib/AST/ByteCode/EvaluationResult.cpp | 18 +++++-
clang/lib/AST/ByteCode/Pointer.cpp | 65 ++++++++++++++++-----
clang/lib/AST/ByteCode/Pointer.h | 7 ++-
3 files changed, 70 insertions(+), 20 deletions(-)
diff --git a/clang/lib/AST/ByteCode/EvaluationResult.cpp b/clang/lib/AST/ByteCode/EvaluationResult.cpp
index 5110e243d167c..a4a44f6952351 100644
--- a/clang/lib/AST/ByteCode/EvaluationResult.cpp
+++ b/clang/lib/AST/ByteCode/EvaluationResult.cpp
@@ -66,8 +66,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()) {
@@ -82,8 +86,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