Skip to content

Commit 4a11a73

Browse files
committed
[NFC] Refactor ConstantArrayType size storage
In PR llvm#79382, I need to add a new type that derives from ConstantArrayType. This means that ConstantArrayType can no longer use `llvm::TrailingObjects` to store the trailing optional Expr*. This change refactors ConstantArrayType to store a 60-bit integer and 4-bits for the integer size in bytes. This replaces the APInt field previously in the type but preserves enough information to recreate it where needed. To reduce the number of places where the APInt is re-constructed I've also added some helper methods to the ConstantArrayType to allow some common use cases that operate on either the stored small integer or the APInt as appropriate. Resolves llvm#85124.
1 parent 4841858 commit 4a11a73

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+201
-127
lines changed

clang/include/clang/AST/Type.h

Lines changed: 84 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1689,7 +1689,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
16891689

16901690
/// Whether we have a stored size expression.
16911691
LLVM_PREFERRED_TYPE(bool)
1692-
unsigned HasStoredSizeExpr : 1;
1692+
unsigned HasExternalSize : 1;
16931693
};
16941694

16951695
class BuiltinTypeBitfields {
@@ -3182,34 +3182,98 @@ class ArrayType : public Type, public llvm::FoldingSetNode {
31823182
/// For example, the canonical type for 'int A[4 + 4*100]' is a
31833183
/// ConstantArrayType where the element type is 'int' and the size is 404.
31843184
class ConstantArrayType final
3185-
: public ArrayType,
3186-
private llvm::TrailingObjects<ConstantArrayType, const Expr *> {
3185+
: public ArrayType {
31873186
friend class ASTContext; // ASTContext creates these.
3188-
friend TrailingObjects;
31893187

3190-
llvm::APInt Size; // Allows us to unique the type.
3188+
struct ExternalSize {
3189+
ExternalSize(const llvm::APInt &Sz, const Expr *SE)
3190+
: Size(Sz), SizeExpr(SE) {}
3191+
llvm::APInt Size; // Allows us to unique the type.
3192+
const Expr *SizeExpr;
3193+
};
3194+
struct InlineSize {
3195+
InlineSize(uint64_t TSz, uint64_t Sz) : ByteWidth(TSz), Size(Sz) {}
3196+
uint64_t ByteWidth : 4;
3197+
uint64_t Size : 60;
3198+
};
3199+
union {
3200+
struct InlineSize I;
3201+
ExternalSize *SizePtr;
3202+
};
31913203

3192-
ConstantArrayType(QualType et, QualType can, const llvm::APInt &size,
3193-
const Expr *sz, ArraySizeModifier sm, unsigned tq)
3194-
: ArrayType(ConstantArray, et, can, sm, tq, sz), Size(size) {
3195-
ConstantArrayTypeBits.HasStoredSizeExpr = sz != nullptr;
3196-
if (ConstantArrayTypeBits.HasStoredSizeExpr) {
3197-
assert(!can.isNull() && "canonical constant array should not have size");
3198-
*getTrailingObjects<const Expr*>() = sz;
3199-
}
3204+
ConstantArrayType(QualType Et, QualType Can, uint64_t Width, uint64_t Sz,
3205+
ArraySizeModifier SM, unsigned TQ)
3206+
: ArrayType(ConstantArray, Et, Can, SM, TQ, nullptr), I(Width / 8, Sz) {
3207+
ConstantArrayTypeBits.HasExternalSize = false;
3208+
assert(Sz < 0x0FFFFFFFFFFFFFFF && "Size must fit in 60 bits");
3209+
assert(Width < 0xFF && "Type width must fit in 8 bits");
32003210
}
32013211

3202-
unsigned numTrailingObjects(OverloadToken<const Expr*>) const {
3203-
return ConstantArrayTypeBits.HasStoredSizeExpr;
3212+
ConstantArrayType(QualType Et, QualType Can, ExternalSize *SzPtr,
3213+
ArraySizeModifier SM, unsigned TQ)
3214+
: ArrayType(ConstantArray, Et, Can, SM, TQ, SzPtr->SizeExpr),
3215+
SizePtr(SzPtr) {
3216+
ConstantArrayTypeBits.HasExternalSize = true;
3217+
3218+
assert((SzPtr->SizeExpr == nullptr || !Can.isNull()) &&
3219+
"canonical constant array should not have size expression");
32043220
}
32053221

3222+
static ConstantArrayType *Create(const ASTContext &Ctx, QualType ET,
3223+
QualType Can, const llvm::APInt &Sz,
3224+
const Expr *SzExpr, ArraySizeModifier SzMod,
3225+
unsigned Qual);
3226+
32063227
public:
3207-
const llvm::APInt &getSize() const { return Size; }
3228+
/// Return the constant array size as an APInt.
3229+
llvm::APInt getSize() const {
3230+
return ConstantArrayTypeBits.HasExternalSize
3231+
? SizePtr->Size
3232+
: llvm::APInt(I.ByteWidth * 8, I.Size);
3233+
}
3234+
3235+
/// Return the bit width of the size type.
3236+
unsigned getSizeBitWidth() const {
3237+
return ConstantArrayTypeBits.HasExternalSize
3238+
? SizePtr->Size.getBitWidth()
3239+
: static_cast<unsigned>(I.ByteWidth * 8);
3240+
}
3241+
3242+
/// Return true if the size is zero.
3243+
bool isZeroSize() const {
3244+
return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.isZero()
3245+
: 0 == I.Size;
3246+
}
3247+
3248+
/// Return the size zero-extended as a uint64_t.
3249+
uint64_t getZExtSize() const {
3250+
return ConstantArrayTypeBits.HasExternalSize
3251+
? SizePtr->Size.getZExtValue()
3252+
: I.Size;
3253+
}
3254+
3255+
/// Return the size zero-extended as a uint64_t.
3256+
int64_t getSExtSize() const {
3257+
return ConstantArrayTypeBits.HasExternalSize
3258+
? SizePtr->Size.getSExtValue()
3259+
: static_cast<int64_t>(I.Size);
3260+
}
3261+
3262+
/// Return the size zero-extended to uint64_t or UINT64_MAX if the value is
3263+
/// larger than UINT64_MAX.
3264+
uint64_t getLimitedSize() const {
3265+
return ConstantArrayTypeBits.HasExternalSize
3266+
? SizePtr->Size.getLimitedValue()
3267+
: I.Size;
3268+
}
3269+
3270+
/// Return a pointer to the size expression.
32083271
const Expr *getSizeExpr() const {
3209-
return ConstantArrayTypeBits.HasStoredSizeExpr
3210-
? *getTrailingObjects<const Expr *>()
3272+
return ConstantArrayTypeBits.HasExternalSize
3273+
? SizePtr->SizeExpr
32113274
: nullptr;
32123275
}
3276+
32133277
bool isSugared() const { return false; }
32143278
QualType desugar() const { return QualType(this, 0); }
32153279

@@ -3226,12 +3290,12 @@ class ConstantArrayType final
32263290
static unsigned getMaxSizeBits(const ASTContext &Context);
32273291

32283292
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) {
3229-
Profile(ID, Ctx, getElementType(), getSize(), getSizeExpr(),
3293+
Profile(ID, Ctx, getElementType(), getZExtSize(), getSizeExpr(),
32303294
getSizeModifier(), getIndexTypeCVRQualifiers());
32313295
}
32323296

32333297
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx,
3234-
QualType ET, const llvm::APInt &ArraySize,
3298+
QualType ET, uint64_t ArraySize,
32353299
const Expr *SizeExpr, ArraySizeModifier SizeMod,
32363300
unsigned TypeQuals);
32373301

clang/lib/AST/ASTContext.cpp

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1766,7 +1766,7 @@ TypeInfoChars
17661766
static getConstantArrayInfoInChars(const ASTContext &Context,
17671767
const ConstantArrayType *CAT) {
17681768
TypeInfoChars EltInfo = Context.getTypeInfoInChars(CAT->getElementType());
1769-
uint64_t Size = CAT->getSize().getZExtValue();
1769+
uint64_t Size = CAT->getZExtSize();
17701770
assert((Size == 0 || static_cast<uint64_t>(EltInfo.Width.getQuantity()) <=
17711771
(uint64_t)(-1)/Size) &&
17721772
"Overflow in array type char size evaluation");
@@ -1910,7 +1910,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
19101910
// Model non-constant sized arrays as size zero, but track the alignment.
19111911
uint64_t Size = 0;
19121912
if (const auto *CAT = dyn_cast<ConstantArrayType>(T))
1913-
Size = CAT->getSize().getZExtValue();
1913+
Size = CAT->getZExtSize();
19141914

19151915
TypeInfo EltInfo = getTypeInfo(cast<ArrayType>(T)->getElementType());
19161916
assert((Size == 0 || EltInfo.Width <= (uint64_t)(-1) / Size) &&
@@ -3531,8 +3531,8 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
35313531
ArySize = ArySize.zextOrTrunc(Target->getMaxPointerWidth());
35323532

35333533
llvm::FoldingSetNodeID ID;
3534-
ConstantArrayType::Profile(ID, *this, EltTy, ArySize, SizeExpr, ASM,
3535-
IndexTypeQuals);
3534+
ConstantArrayType::Profile(ID, *this, EltTy, ArySize.getZExtValue(), SizeExpr,
3535+
ASM, IndexTypeQuals);
35363536

35373537
void *InsertPos = nullptr;
35383538
if (ConstantArrayType *ATP =
@@ -3556,11 +3556,8 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
35563556
assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP;
35573557
}
35583558

3559-
void *Mem = Allocate(
3560-
ConstantArrayType::totalSizeToAlloc<const Expr *>(SizeExpr ? 1 : 0),
3561-
alignof(ConstantArrayType));
3562-
auto *New = new (Mem)
3563-
ConstantArrayType(EltTy, Canon, ArySize, SizeExpr, ASM, IndexTypeQuals);
3559+
auto *New = ConstantArrayType::Create(*this, EltTy, Canon, ArySize, SizeExpr,
3560+
ASM, IndexTypeQuals);
35643561
ConstantArrayTypes.InsertNode(New, InsertPos);
35653562
Types.push_back(New);
35663563
return QualType(New, 0);
@@ -7022,7 +7019,7 @@ uint64_t
70227019
ASTContext::getConstantArrayElementCount(const ConstantArrayType *CA) const {
70237020
uint64_t ElementCount = 1;
70247021
do {
7025-
ElementCount *= CA->getSize().getZExtValue();
7022+
ElementCount *= CA->getZExtSize();
70267023
CA = dyn_cast_or_null<ConstantArrayType>(
70277024
CA->getElementType()->getAsArrayTypeUnsafe());
70287025
} while (CA);
@@ -8345,7 +8342,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
83458342
S += '[';
83468343

83478344
if (const auto *CAT = dyn_cast<ConstantArrayType>(AT))
8348-
S += llvm::utostr(CAT->getSize().getZExtValue());
8345+
S += llvm::utostr(CAT->getZExtSize());
83498346
else {
83508347
//Variable length arrays are encoded as a regular array with 0 elements.
83518348
assert((isa<VariableArrayType>(AT) || isa<IncompleteArrayType>(AT)) &&
@@ -10779,7 +10776,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer,
1077910776
{
1078010777
const ConstantArrayType* LCAT = getAsConstantArrayType(LHS);
1078110778
const ConstantArrayType* RCAT = getAsConstantArrayType(RHS);
10782-
if (LCAT && RCAT && RCAT->getSize() != LCAT->getSize())
10779+
if (LCAT && RCAT && RCAT->getZExtSize() != LCAT->getZExtSize())
1078310780
return {};
1078410781

1078510782
QualType LHSElem = getAsArrayType(LHS)->getElementType();

clang/lib/AST/Decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2840,7 +2840,7 @@ bool VarDecl::hasFlexibleArrayInit(const ASTContext &Ctx) const {
28402840
auto InitTy = Ctx.getAsConstantArrayType(FlexibleInit->getType());
28412841
if (!InitTy)
28422842
return false;
2843-
return InitTy->getSize() != 0;
2843+
return !InitTy->isZeroSize();
28442844
}
28452845

28462846
CharUnits VarDecl::getFlexibleArrayInitChars(const ASTContext &Ctx) const {

clang/lib/AST/ExprConstant.cpp

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ namespace {
209209
IsArray = true;
210210

211211
if (auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
212-
ArraySize = CAT->getSize().getZExtValue();
212+
ArraySize = CAT->getZExtSize();
213213
} else {
214214
assert(I == 0 && "unexpected unsized array designator");
215215
FirstEntryIsUnsizedArray = true;
@@ -401,7 +401,7 @@ namespace {
401401
// This is a most-derived object.
402402
MostDerivedType = CAT->getElementType();
403403
MostDerivedIsArrayElement = true;
404-
MostDerivedArraySize = CAT->getSize().getZExtValue();
404+
MostDerivedArraySize = CAT->getZExtSize();
405405
MostDerivedPathLength = Entries.size();
406406
}
407407
/// Update this designator to refer to the first element within the array of
@@ -3476,7 +3476,7 @@ static void expandStringLiteral(EvalInfo &Info, const StringLiteral *S,
34763476
QualType CharType = CAT->getElementType();
34773477
assert(CharType->isIntegerType() && "unexpected character type");
34783478

3479-
unsigned Elts = CAT->getSize().getZExtValue();
3479+
unsigned Elts = CAT->getZExtSize();
34803480
Result = APValue(APValue::UninitArray(),
34813481
std::min(S->getLength(), Elts), Elts);
34823482
APSInt Value(Info.Ctx.getTypeSize(CharType),
@@ -3619,7 +3619,7 @@ static bool CheckArraySize(EvalInfo &Info, const ConstantArrayType *CAT,
36193619
SourceLocation CallLoc = {}) {
36203620
return Info.CheckArraySize(
36213621
CAT->getSizeExpr() ? CAT->getSizeExpr()->getBeginLoc() : CallLoc,
3622-
CAT->getNumAddressingBits(Info.Ctx), CAT->getSize().getZExtValue(),
3622+
CAT->getNumAddressingBits(Info.Ctx), CAT->getZExtSize(),
36233623
/*Diag=*/true);
36243624
}
36253625

@@ -4908,7 +4908,7 @@ static bool handleDefaultInitValue(QualType T, APValue &Result) {
49084908

49094909
if (auto *AT =
49104910
dyn_cast_or_null<ConstantArrayType>(T->getAsArrayTypeUnsafe())) {
4911-
Result = APValue(APValue::UninitArray(), 0, AT->getSize().getZExtValue());
4911+
Result = APValue(APValue::UninitArray(), 0, AT->getZExtSize());
49124912
if (Result.hasArrayFiller())
49134913
Success &=
49144914
handleDefaultInitValue(AT->getElementType(), Result.getArrayFiller());
@@ -6595,7 +6595,7 @@ static bool HandleDestructionImpl(EvalInfo &Info, SourceRange CallRange,
65956595

65966596
// For arrays, destroy elements right-to-left.
65976597
if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(T)) {
6598-
uint64_t Size = CAT->getSize().getZExtValue();
6598+
uint64_t Size = CAT->getZExtSize();
65996599
QualType ElemT = CAT->getElementType();
66006600

66016601
if (!CheckArraySize(Info, CAT, CallRange.getBegin()))
@@ -7396,7 +7396,7 @@ class BufferToAPValueConverter {
73967396
}
73977397

73987398
std::optional<APValue> visit(const ConstantArrayType *Ty, CharUnits Offset) {
7399-
size_t Size = Ty->getSize().getLimitedValue();
7399+
size_t Size = Ty->getLimitedSize();
74007400
CharUnits ElementWidth = Info.Ctx.getTypeSizeInChars(Ty->getElementType());
74017401

74027402
APValue ArrayValue(APValue::UninitArray(), Size, Size);
@@ -9951,7 +9951,7 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
99519951
assert(CAT && "unexpected type for array initializer");
99529952

99539953
unsigned Bits =
9954-
std::max(CAT->getSize().getBitWidth(), ArrayBound.getBitWidth());
9954+
std::max(CAT->getSizeBitWidth(), ArrayBound.getBitWidth());
99559955
llvm::APInt InitBound = CAT->getSize().zext(Bits);
99569956
llvm::APInt AllocBound = ArrayBound.zext(Bits);
99579957
if (InitBound.ugt(AllocBound)) {
@@ -10410,7 +10410,7 @@ bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
1041010410

1041110411
if (Field->getType()->isIncompleteArrayType()) {
1041210412
if (auto *CAT = Info.Ctx.getAsConstantArrayType(Init->getType())) {
10413-
if (!CAT->getSize().isZero()) {
10413+
if (!CAT->isZeroSize()) {
1041410414
// Bail out for now. This might sort of "work", but the rest of the
1041510415
// code isn't really prepared to handle it.
1041610416
Info.FFDiag(Init, diag::note_constexpr_unsupported_flexible_array);
@@ -10554,7 +10554,7 @@ bool RecordExprEvaluator::VisitCXXStdInitializerListExpr(
1055410554
// End pointer.
1055510555
if (!HandleLValueArrayAdjustment(Info, E, Array,
1055610556
ArrayType->getElementType(),
10557-
ArrayType->getSize().getZExtValue()))
10557+
ArrayType->getZExtSize()))
1055810558
return false;
1055910559
Array.moveInto(Result.getStructField(1));
1056010560
} else if (Info.Ctx.hasSameType(Field->getType(), Info.Ctx.getSizeType()))
@@ -10997,7 +10997,7 @@ namespace {
1099710997
}
1099810998

1099910999
Result = APValue(APValue::UninitArray(), 0,
11000-
CAT->getSize().getZExtValue());
11000+
CAT->getZExtSize());
1100111001
if (!Result.hasArrayFiller())
1100211002
return true;
1100311003

@@ -11122,7 +11122,7 @@ bool ArrayExprEvaluator::VisitCXXParenListOrInitListExpr(
1112211122
Filler = Result.getArrayFiller();
1112311123

1112411124
unsigned NumEltsToInit = Args.size();
11125-
unsigned NumElts = CAT->getSize().getZExtValue();
11125+
unsigned NumElts = CAT->getZExtSize();
1112611126

1112711127
// If the initializer might depend on the array index, run it for each
1112811128
// array element.
@@ -11180,7 +11180,7 @@ bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
1118011180

1118111181
auto *CAT = cast<ConstantArrayType>(E->getType()->castAsArrayTypeUnsafe());
1118211182

11183-
uint64_t Elements = CAT->getSize().getZExtValue();
11183+
uint64_t Elements = CAT->getZExtSize();
1118411184
Result = APValue(APValue::UninitArray(), Elements, Elements);
1118511185

1118611186
LValue Subobject = This;
@@ -11225,7 +11225,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
1122511225
bool HadZeroInit = Value->hasValue();
1122611226

1122711227
if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(Type)) {
11228-
unsigned FinalSize = CAT->getSize().getZExtValue();
11228+
unsigned FinalSize = CAT->getZExtSize();
1122911229

1123011230
// Preserve the array filler if we had prior zero-initialization.
1123111231
APValue Filler =
@@ -11940,7 +11940,7 @@ static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) {
1194011940
return true;
1194111941
const auto *CAT = cast<ConstantArrayType>(Ctx.getAsArrayType(BaseType));
1194211942
uint64_t Index = Entry.getAsArrayIndex();
11943-
if (Index + 1 != CAT->getSize())
11943+
if (Index + 1 != CAT->getZExtSize())
1194411944
return false;
1194511945
BaseType = CAT->getElementType();
1194611946
} else if (BaseType->isAnyComplexType()) {

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -819,7 +819,7 @@ bool ByteCodeExprGen<Emitter>::VisitImplicitValueInitExpr(const ImplicitValueIni
819819
const ArrayType *AT = QT->getAsArrayTypeUnsafe();
820820
assert(AT);
821821
const auto *CAT = cast<ConstantArrayType>(AT);
822-
size_t NumElems = CAT->getSize().getZExtValue();
822+
size_t NumElems = CAT->getZExtSize();
823823
PrimType ElemT = classifyPrim(CAT->getElementType());
824824

825825
for (size_t I = 0; I != NumElems; ++I) {
@@ -992,7 +992,7 @@ bool ByteCodeExprGen<Emitter>::VisitInitListExpr(const InitListExpr *E) {
992992
if (const Expr *Filler = E->getArrayFiller()) {
993993
const ConstantArrayType *CAT =
994994
Ctx.getASTContext().getAsConstantArrayType(E->getType());
995-
uint64_t NumElems = CAT->getSize().getZExtValue();
995+
uint64_t NumElems = CAT->getZExtSize();
996996

997997
for (; ElementIndex != NumElems; ++ElementIndex) {
998998
if (!this->visitArrayElemInit(ElementIndex, Filler))
@@ -1318,7 +1318,7 @@ bool ByteCodeExprGen<Emitter>::VisitStringLiteral(const StringLiteral *E) {
13181318

13191319
// If the initializer string is too long, a diagnostic has already been
13201320
// emitted. Read only the array length from the string literal.
1321-
unsigned ArraySize = CAT->getSize().getZExtValue();
1321+
unsigned ArraySize = CAT->getZExtSize();
13221322
unsigned N = std::min(ArraySize, E->getLength());
13231323
size_t CharWidth = E->getCharByteWidth();
13241324

@@ -1919,7 +1919,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXConstructExpr(
19191919
const ConstantArrayType *CAT =
19201920
Ctx.getASTContext().getAsConstantArrayType(E->getType());
19211921
assert(CAT);
1922-
size_t NumElems = CAT->getSize().getZExtValue();
1922+
size_t NumElems = CAT->getZExtSize();
19231923
const Function *Func = getFunction(E->getConstructor());
19241924
if (!Func || !Func->isConstexpr())
19251925
return false;

clang/lib/AST/Interp/EvaluationResult.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc,
6666
const Pointer &BasePtr,
6767
const ConstantArrayType *CAT) {
6868
bool Result = true;
69-
size_t NumElems = CAT->getSize().getZExtValue();
69+
size_t NumElems = CAT->getZExtSize();
7070
QualType ElemType = CAT->getElementType();
7171

7272
if (ElemType->isRecordType()) {

0 commit comments

Comments
 (0)