Skip to content

Commit 839916c

Browse files
authored
[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()`).
1 parent da65685 commit 839916c

File tree

3 files changed

+70
-20
lines changed

3 files changed

+70
-20
lines changed

clang/lib/AST/ByteCode/EvaluationResult.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,12 @@ static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
6262
static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc,
6363
const Pointer &BasePtr,
6464
const ConstantArrayType *CAT) {
65-
bool Result = true;
6665
size_t NumElems = CAT->getZExtSize();
66+
67+
if (NumElems == 0)
68+
return true;
69+
70+
bool Result = true;
6771
QualType ElemType = CAT->getElementType();
6872

6973
if (ElemType->isRecordType()) {
@@ -78,8 +82,18 @@ static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc,
7882
Result &= CheckArrayInitialized(S, Loc, ElemPtr, ElemCAT);
7983
}
8084
} else {
85+
// Primitive arrays.
86+
if (S.getContext().canClassify(ElemType)) {
87+
if (BasePtr.allElementsInitialized()) {
88+
return true;
89+
} else {
90+
DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField());
91+
return false;
92+
}
93+
}
94+
8195
for (size_t I = 0; I != NumElems; ++I) {
82-
if (!BasePtr.atIndex(I).isInitialized()) {
96+
if (!BasePtr.isElementInitialized(I)) {
8397
DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField());
8498
Result = false;
8599
}

clang/lib/AST/ByteCode/Pointer.cpp

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -442,26 +442,42 @@ bool Pointer::isInitialized() const {
442442
assert(BS.Pointee && "Cannot check if null pointer was initialized");
443443
const Descriptor *Desc = getFieldDesc();
444444
assert(Desc);
445-
if (Desc->isPrimitiveArray()) {
446-
if (isStatic() && BS.Base == 0)
447-
return true;
445+
if (Desc->isPrimitiveArray())
446+
return isElementInitialized(getIndex());
448447

449-
InitMapPtr &IM = getInitMap();
448+
if (asBlockPointer().Base == 0)
449+
return true;
450+
// Field has its bit in an inline descriptor.
451+
return getInlineDesc()->IsInitialized;
452+
}
453+
454+
bool Pointer::isElementInitialized(unsigned Index) const {
455+
if (!isBlockPointer())
456+
return true;
457+
458+
const Descriptor *Desc = getFieldDesc();
459+
assert(Desc);
460+
461+
if (isStatic() && BS.Base == 0)
462+
return true;
463+
464+
if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
465+
const GlobalInlineDescriptor &GD =
466+
*reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
467+
return GD.InitState == GlobalInitState::Initialized;
468+
}
450469

470+
if (Desc->isPrimitiveArray()) {
471+
InitMapPtr &IM = getInitMap();
451472
if (!IM)
452473
return false;
453474

454475
if (IM->first)
455476
return true;
456477

457-
return IM->second->isElementInitialized(getIndex());
478+
return IM->second->isElementInitialized(Index);
458479
}
459-
460-
if (asBlockPointer().Base == 0)
461-
return true;
462-
463-
// Field has its bit in an inline descriptor.
464-
return getInlineDesc()->IsInitialized;
480+
return isInitialized();
465481
}
466482

467483
void Pointer::initialize() const {
@@ -524,6 +540,23 @@ void Pointer::initializeAllElements() const {
524540
}
525541
}
526542

543+
bool Pointer::allElementsInitialized() const {
544+
assert(getFieldDesc()->isPrimitiveArray());
545+
assert(isArrayRoot());
546+
547+
if (isStatic() && BS.Base == 0)
548+
return true;
549+
550+
if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
551+
const GlobalInlineDescriptor &GD =
552+
*reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
553+
return GD.InitState == GlobalInitState::Initialized;
554+
}
555+
556+
InitMapPtr &IM = getInitMap();
557+
return IM && IM->first;
558+
}
559+
527560
void Pointer::activate() const {
528561
// Field has its bit in an inline descriptor.
529562
assert(BS.Base != 0 && "Only composite fields can be activated");
@@ -771,13 +804,13 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
771804
R = APValue(APValue::UninitArray{}, NumElems, NumElems);
772805

773806
bool Ok = true;
774-
for (unsigned I = 0; I < NumElems; ++I) {
807+
OptPrimType ElemT = Ctx.classify(ElemTy);
808+
for (unsigned I = 0; I != NumElems; ++I) {
775809
APValue &Slot = R.getArrayInitializedElt(I);
776-
const Pointer &EP = Ptr.atIndex(I);
777-
if (OptPrimType T = Ctx.classify(ElemTy)) {
778-
TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue(ASTCtx));
810+
if (ElemT) {
811+
TYPE_SWITCH(*ElemT, Slot = Ptr.elem<T>(I).toAPValue(ASTCtx));
779812
} else {
780-
Ok &= Composite(ElemTy, EP.narrow(), Slot);
813+
Ok &= Composite(ElemTy, Ptr.atIndex(I).narrow(), Slot);
781814
}
782815
}
783816
return Ok;

clang/lib/AST/ByteCode/Pointer.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -528,8 +528,6 @@ class Pointer {
528528
assert(isBlockPointer());
529529
return BS.Pointee->isWeak();
530530
}
531-
/// Checks if an object was initialized.
532-
bool isInitialized() const;
533531
/// Checks if the object is active.
534532
bool isActive() const {
535533
if (!isBlockPointer())
@@ -707,6 +705,11 @@ class Pointer {
707705
/// used in situations where we *know* we have initialized *all* elements
708706
/// of a primtive array.
709707
void initializeAllElements() const;
708+
/// Checks if an object was initialized.
709+
bool isInitialized() const;
710+
/// Like isInitialized(), but for primitive arrays.
711+
bool isElementInitialized(unsigned Index) const;
712+
bool allElementsInitialized() const;
710713
/// Activats a field.
711714
void activate() const;
712715
/// Deactivates an entire strurcutre.

0 commit comments

Comments
 (0)