Skip to content

Commit 2155f17

Browse files
authored
[clang][bytecode] Optimize InitElem{,Pop} (llvm#159084)
Try harder to avoid creating a new `Pointer` for the element.
1 parent 5829652 commit 2155f17

File tree

3 files changed

+65
-36
lines changed

3 files changed

+65
-36
lines changed

clang/lib/AST/ByteCode/Interp.h

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2127,19 +2127,28 @@ bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
21272127
if (Ptr.isUnknownSizeArray())
21282128
return false;
21292129

2130+
const Descriptor *Desc = Ptr.getFieldDesc();
21302131
// In the unlikely event that we're initializing the first item of
21312132
// a non-array, skip the atIndex().
2132-
if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {
2133+
if (Idx == 0 && !Desc->isArray()) {
21332134
Ptr.initialize();
21342135
new (&Ptr.deref<T>()) T(Value);
21352136
return true;
21362137
}
21372138

2138-
const Pointer &ElemPtr = Ptr.atIndex(Idx);
2139-
if (!CheckInit(S, OpPC, ElemPtr))
2139+
if (!CheckLive(S, OpPC, Ptr, AK_Assign))
21402140
return false;
2141-
ElemPtr.initialize();
2142-
new (&ElemPtr.deref<T>()) T(Value);
2141+
if (Idx >= Desc->getNumElems()) {
2142+
// CheckRange.
2143+
if (S.getLangOpts().CPlusPlus) {
2144+
const SourceInfo &Loc = S.Current->getSource(OpPC);
2145+
S.FFDiag(Loc, diag::note_constexpr_access_past_end)
2146+
<< AK_Assign << S.Current->getRange(OpPC);
2147+
}
2148+
return false;
2149+
}
2150+
Ptr.initializeElement(Idx);
2151+
new (&Ptr.elem<T>(Idx)) T(Value);
21432152
return true;
21442153
}
21452154

@@ -2148,22 +2157,32 @@ template <PrimType Name, class T = typename PrimConv<Name>::T>
21482157
bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
21492158
const T &Value = S.Stk.pop<T>();
21502159
const Pointer &Ptr = S.Stk.pop<Pointer>();
2160+
21512161
if (Ptr.isUnknownSizeArray())
21522162
return false;
21532163

2164+
const Descriptor *Desc = Ptr.getFieldDesc();
21542165
// In the unlikely event that we're initializing the first item of
21552166
// a non-array, skip the atIndex().
2156-
if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {
2167+
if (Idx == 0 && !Desc->isArray()) {
21572168
Ptr.initialize();
21582169
new (&Ptr.deref<T>()) T(Value);
21592170
return true;
21602171
}
21612172

2162-
const Pointer &ElemPtr = Ptr.atIndex(Idx);
2163-
if (!CheckInit(S, OpPC, ElemPtr))
2173+
if (!CheckLive(S, OpPC, Ptr, AK_Assign))
21642174
return false;
2165-
ElemPtr.initialize();
2166-
new (&ElemPtr.deref<T>()) T(Value);
2175+
if (Idx >= Desc->getNumElems()) {
2176+
// CheckRange.
2177+
if (S.getLangOpts().CPlusPlus) {
2178+
const SourceInfo &Loc = S.Current->getSource(OpPC);
2179+
S.FFDiag(Loc, diag::note_constexpr_access_past_end)
2180+
<< AK_Assign << S.Current->getRange(OpPC);
2181+
}
2182+
return false;
2183+
}
2184+
Ptr.initializeElement(Idx);
2185+
new (&Ptr.elem<T>(Idx)) T(Value);
21672186
return true;
21682187
}
21692188

clang/lib/AST/ByteCode/Pointer.cpp

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,8 @@ bool Pointer::isInitialized() const {
433433
if (!isBlockPointer())
434434
return true;
435435

436-
if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
436+
if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
437+
Offset == BS.Base) {
437438
const GlobalInlineDescriptor &GD =
438439
*reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
439440
return GD.InitState == GlobalInitState::Initialized;
@@ -461,7 +462,8 @@ bool Pointer::isElementInitialized(unsigned Index) const {
461462
if (isStatic() && BS.Base == 0)
462463
return true;
463464

464-
if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
465+
if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
466+
Offset == BS.Base) {
465467
const GlobalInlineDescriptor &GD =
466468
*reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
467469
return GD.InitState == GlobalInitState::Initialized;
@@ -486,7 +488,8 @@ void Pointer::initialize() const {
486488

487489
assert(BS.Pointee && "Cannot initialize null pointer");
488490

489-
if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
491+
if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
492+
Offset == BS.Base) {
490493
GlobalInlineDescriptor &GD = *reinterpret_cast<GlobalInlineDescriptor *>(
491494
asBlockPointer().Pointee->rawData());
492495
GD.InitState = GlobalInitState::Initialized;
@@ -496,35 +499,39 @@ void Pointer::initialize() const {
496499
const Descriptor *Desc = getFieldDesc();
497500
assert(Desc);
498501
if (Desc->isPrimitiveArray()) {
499-
// Primitive global arrays don't have an initmap.
500-
if (isStatic() && BS.Base == 0)
501-
return;
502+
if (Desc->getNumElems() != 0)
503+
initializeElement(getIndex());
504+
return;
505+
}
502506

503-
// Nothing to do for these.
504-
if (Desc->getNumElems() == 0)
505-
return;
507+
// Field has its bit in an inline descriptor.
508+
assert(BS.Base != 0 && "Only composite fields can be initialised");
509+
getInlineDesc()->IsInitialized = true;
510+
}
506511

507-
InitMapPtr &IM = getInitMap();
508-
if (!IM)
509-
IM =
510-
std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems()));
512+
void Pointer::initializeElement(unsigned Index) const {
513+
// Primitive global arrays don't have an initmap.
514+
if (isStatic() && BS.Base == 0)
515+
return;
511516

512-
assert(IM);
517+
assert(Index < getFieldDesc()->getNumElems());
513518

514-
// All initialized.
515-
if (IM->first)
516-
return;
519+
InitMapPtr &IM = getInitMap();
520+
if (!IM) {
521+
const Descriptor *Desc = getFieldDesc();
522+
IM = std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems()));
523+
}
517524

518-
if (IM->second->initializeElement(getIndex())) {
519-
IM->first = true;
520-
IM->second.reset();
521-
}
525+
assert(IM);
526+
527+
// All initialized.
528+
if (IM->first)
522529
return;
523-
}
524530

525-
// Field has its bit in an inline descriptor.
526-
assert(BS.Base != 0 && "Only composite fields can be initialised");
527-
getInlineDesc()->IsInitialized = true;
531+
if (IM->second->initializeElement(Index)) {
532+
IM->first = true;
533+
IM->second.reset();
534+
}
528535
}
529536

530537
void Pointer::initializeAllElements() const {
@@ -547,7 +554,8 @@ bool Pointer::allElementsInitialized() const {
547554
if (isStatic() && BS.Base == 0)
548555
return true;
549556

550-
if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
557+
if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
558+
Offset == BS.Base) {
551559
const GlobalInlineDescriptor &GD =
552560
*reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
553561
return GD.InitState == GlobalInitState::Initialized;

clang/lib/AST/ByteCode/Pointer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,8 @@ class Pointer {
702702

703703
/// Initializes a field.
704704
void initialize() const;
705+
/// Initialized the given element of a primitive array.
706+
void initializeElement(unsigned Index) const;
705707
/// Initialize all elements of a primitive array at once. This can be
706708
/// used in situations where we *know* we have initialized *all* elements
707709
/// of a primtive array.

0 commit comments

Comments
 (0)