Skip to content

Commit 8fe38c4

Browse files
authored
[clang][bytecode] Allocate InitMaps via Program/InterpState allocators (#170272)
Save them as a pointer intead of using a shared_ptr. This we we can use the pointer integer value to differentiate the "no initmap yet" and "all values initialzed" cases. This regresses one test case in const-eval.c, but as it turns out, that only worked coincidentally before.
1 parent 75aa7bd commit 8fe38c4

File tree

12 files changed

+185
-188
lines changed

12 files changed

+185
-188
lines changed

clang/lib/AST/ByteCode/Descriptor.cpp

Lines changed: 20 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,8 @@ static void dtorTy(Block *, std::byte *Ptr, const Descriptor *) {
5252
template <typename T>
5353
static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,
5454
const Descriptor *D) {
55-
new (Ptr) InitMapPtr(std::nullopt);
56-
5755
if constexpr (needsCtor<T>()) {
58-
Ptr += sizeof(InitMapPtr);
56+
Ptr += sizeof(InitMap *);
5957
for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
6058
new (&reinterpret_cast<T *>(Ptr)[I]) T();
6159
}
@@ -64,13 +62,8 @@ static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,
6462

6563
template <typename T>
6664
static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) {
67-
InitMapPtr &IMP = *reinterpret_cast<InitMapPtr *>(Ptr);
68-
69-
if (IMP)
70-
IMP = std::nullopt;
71-
7265
if constexpr (needsCtor<T>()) {
73-
Ptr += sizeof(InitMapPtr);
66+
Ptr += sizeof(InitMap *);
7467
for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
7568
reinterpret_cast<T *>(Ptr)[I].~T();
7669
}
@@ -239,12 +232,6 @@ static bool needsRecordDtor(const Record *R) {
239232

240233
static BlockCtorFn getCtorPrim(PrimType T) {
241234
switch (T) {
242-
case PT_Float:
243-
return ctorTy<PrimConv<PT_Float>::T>;
244-
case PT_IntAP:
245-
return ctorTy<PrimConv<PT_IntAP>::T>;
246-
case PT_IntAPS:
247-
return ctorTy<PrimConv<PT_IntAPS>::T>;
248235
case PT_Ptr:
249236
return ctorTy<PrimConv<PT_Ptr>::T>;
250237
case PT_MemberPtr:
@@ -257,12 +244,6 @@ static BlockCtorFn getCtorPrim(PrimType T) {
257244

258245
static BlockDtorFn getDtorPrim(PrimType T) {
259246
switch (T) {
260-
case PT_Float:
261-
return dtorTy<PrimConv<PT_Float>::T>;
262-
case PT_IntAP:
263-
return dtorTy<PrimConv<PT_IntAP>::T>;
264-
case PT_IntAPS:
265-
return dtorTy<PrimConv<PT_IntAPS>::T>;
266247
case PT_Ptr:
267248
return dtorTy<PrimConv<PT_Ptr>::T>;
268249
case PT_MemberPtr:
@@ -273,14 +254,16 @@ static BlockDtorFn getDtorPrim(PrimType T) {
273254
llvm_unreachable("Unhandled PrimType");
274255
}
275256

276-
static BlockCtorFn getCtorArrayPrim(PrimType Type) {
277-
TYPE_SWITCH(Type, return ctorArrayTy<T>);
278-
llvm_unreachable("unknown Expr");
279-
}
280-
281-
static BlockDtorFn getDtorArrayPrim(PrimType Type) {
282-
TYPE_SWITCH(Type, return dtorArrayTy<T>);
283-
llvm_unreachable("unknown Expr");
257+
static BlockDtorFn getDtorArrayPrim(PrimType T) {
258+
switch (T) {
259+
case PT_Ptr:
260+
return dtorArrayTy<PrimConv<PT_Ptr>::T>;
261+
case PT_MemberPtr:
262+
return dtorArrayTy<PrimConv<PT_MemberPtr>::T>;
263+
default:
264+
return nullptr;
265+
}
266+
llvm_unreachable("Unhandled PrimType");
284267
}
285268

286269
/// Primitives.
@@ -302,10 +285,9 @@ Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,
302285
bool IsMutable)
303286
: Source(D), ElemSize(primSize(Type)), Size(ElemSize * NumElems),
304287
MDSize(MD.value_or(0)),
305-
AllocSize(align(MDSize) + align(Size) + sizeof(InitMapPtr)), PrimT(Type),
288+
AllocSize(align(MDSize) + align(Size) + sizeof(InitMap *)), PrimT(Type),
306289
IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
307-
IsArray(true), CtorFn(getCtorArrayPrim(Type)),
308-
DtorFn(getDtorArrayPrim(Type)) {
290+
IsArray(true), DtorFn(getDtorArrayPrim(Type)) {
309291
assert(Source && "Missing source");
310292
assert(NumElems <= (MaxArrayElemBytes / ElemSize));
311293
}
@@ -315,10 +297,9 @@ Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,
315297
bool IsTemporary, bool IsConst, UnknownSize)
316298
: Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark),
317299
MDSize(MD.value_or(0)),
318-
AllocSize(MDSize + sizeof(InitMapPtr) + alignof(void *)), PrimT(Type),
300+
AllocSize(MDSize + sizeof(InitMap *) + alignof(void *)), PrimT(Type),
319301
IsConst(IsConst), IsMutable(false), IsTemporary(IsTemporary),
320-
IsArray(true), CtorFn(getCtorArrayPrim(Type)),
321-
DtorFn(getDtorArrayPrim(Type)) {
302+
IsArray(true), DtorFn(getDtorArrayPrim(Type)) {
322303
assert(Source && "Missing source");
323304
}
324305

@@ -468,15 +449,16 @@ bool Descriptor::hasTrivialDtor() const {
468449

469450
bool Descriptor::isUnion() const { return isRecord() && ElemRecord->isUnion(); }
470451

471-
InitMap::InitMap(unsigned N)
472-
: UninitFields(N), Data(std::make_unique<T[]>(numFields(N))) {}
452+
InitMap::InitMap(unsigned N) : UninitFields(N) {
453+
std::memset(data(), 0, numFields(N) * sizeof(T));
454+
}
473455

474456
bool InitMap::initializeElement(unsigned I) {
475457
unsigned Bucket = I / PER_FIELD;
476458
T Mask = T(1) << (I % PER_FIELD);
477459
if (!(data()[Bucket] & Mask)) {
478460
data()[Bucket] |= Mask;
479-
UninitFields -= 1;
461+
--UninitFields;
480462
}
481463
return UninitFields == 0;
482464
}

clang/lib/AST/ByteCode/Descriptor.h

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "PrimType.h"
1717
#include "clang/AST/Decl.h"
1818
#include "clang/AST/Expr.h"
19+
#include <limits>
1920

2021
namespace clang {
2122
namespace interp {
@@ -27,7 +28,6 @@ struct Descriptor;
2728
enum PrimType : uint8_t;
2829

2930
using DeclTy = llvm::PointerUnion<const Decl *, const Expr *>;
30-
using InitMapPtr = std::optional<std::pair<bool, std::shared_ptr<InitMap>>>;
3131

3232
/// Invoked whenever a block is created. The constructor method fills in the
3333
/// inline descriptors of all fields and array elements. It also initializes
@@ -146,7 +146,7 @@ struct Descriptor final {
146146

147147
/// Maximum number of bytes to be used for array elements.
148148
static constexpr unsigned MaxArrayElemBytes =
149-
std::numeric_limits<decltype(AllocSize)>::max() - sizeof(InitMapPtr) -
149+
std::numeric_limits<decltype(AllocSize)>::max() - sizeof(InitMap *) -
150150
align(std::max(*InlineDescMD, *GlobalMD));
151151

152152
/// Pointer to the record, if block contains records.
@@ -278,7 +278,7 @@ struct Descriptor final {
278278
};
279279

280280
/// Bitfield tracking the initialisation status of elements of primitive arrays.
281-
struct InitMap final {
281+
struct alignas(alignof(uint64_t)) InitMap final {
282282
private:
283283
/// Type packing bits.
284284
using T = uint64_t;
@@ -289,12 +289,33 @@ struct InitMap final {
289289
/// Initializes the map with no fields set.
290290
explicit InitMap(unsigned N);
291291

292+
/// Checks if all elements have been initialized.
293+
static bool allInitialized(const InitMap *IM) {
294+
return reinterpret_cast<uintptr_t>(IM) ==
295+
std::numeric_limits<uintptr_t>::max();
296+
}
297+
298+
/// Marks all elements as initialized.
299+
static void markAllInitialized(InitMap *&IMPtr) {
300+
std::memset(&IMPtr, static_cast<int>(std::numeric_limits<uintptr_t>::max()),
301+
sizeof(void *));
302+
}
303+
304+
/// Returns the number of bytes needed to allocate the InitMap for
305+
/// \param N elements.
306+
static unsigned allocBytes(unsigned N) {
307+
return align(sizeof(InitMap)) + (numFields(N) * sizeof(T));
308+
}
309+
292310
private:
293311
friend class Pointer;
294312

295313
/// Returns a pointer to storage.
296-
T *data() { return Data.get(); }
297-
const T *data() const { return Data.get(); }
314+
T *data() {
315+
return reinterpret_cast<T *>(reinterpret_cast<std::byte *>(this) +
316+
align(sizeof(InitMap)));
317+
}
318+
const T *data() const { return const_cast<InitMap *>(this)->data(); }
298319

299320
/// Initializes an element. Returns true when object if fully initialized.
300321
bool initializeElement(unsigned I);
@@ -307,7 +328,6 @@ struct InitMap final {
307328
}
308329
/// Number of fields not initialized.
309330
unsigned UninitFields;
310-
std::unique_ptr<T[]> Data;
311331
};
312332

313333
} // namespace interp

clang/lib/AST/ByteCode/Disasm.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ LLVM_DUMP_METHOD void Descriptor::dumpFull(unsigned Offset,
455455
OS.indent(Spaces) << "Elements: " << getNumElems() << '\n';
456456
OS.indent(Spaces) << "Element type: " << primTypeToString(getPrimType())
457457
<< '\n';
458-
unsigned FO = Offset + sizeof(InitMapPtr);
458+
unsigned FO = Offset + sizeof(InitMap *);
459459
for (unsigned I = 0; I != getNumElems(); ++I) {
460460
OS.indent(Spaces) << "Element " << I << " offset: " << FO << '\n';
461461
FO += getElemSize();

clang/lib/AST/ByteCode/EvaluationResult.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,11 @@ static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc,
5454
} else {
5555
// Primitive arrays.
5656
if (S.getContext().canClassify(ElemType)) {
57-
if (BasePtr.allElementsInitialized()) {
57+
if (BasePtr.allElementsInitialized())
5858
return true;
59-
} else {
60-
DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField());
61-
return false;
62-
}
59+
60+
DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField());
61+
return false;
6362
}
6463

6564
for (size_t I = 0; I != NumElems; ++I) {

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2318,7 +2318,7 @@ bool FinishInitGlobal(InterpState &S, CodePtr OpPC) {
23182318

23192319
finishGlobalRecurse(S, Ptr);
23202320
if (Ptr.canBeInitialized()) {
2321-
Ptr.initialize();
2321+
Ptr.initialize(S);
23222322
Ptr.activate();
23232323
}
23242324

0 commit comments

Comments
 (0)