Skip to content

Commit 28ddbd4

Browse files
authored
[NFC] Refactor ConstantArrayType size storage (#85716)
In PR #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 #85124.
1 parent 0e5c504 commit 28ddbd4

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

+207
-149
lines changed

clang/include/clang/AST/Type.h

Lines changed: 84 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1690,7 +1690,10 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
16901690

16911691
/// Whether we have a stored size expression.
16921692
LLVM_PREFERRED_TYPE(bool)
1693-
unsigned HasStoredSizeExpr : 1;
1693+
unsigned HasExternalSize : 1;
1694+
1695+
LLVM_PREFERRED_TYPE(unsigned)
1696+
unsigned SizeWidth : 5;
16941697
};
16951698

16961699
class BuiltinTypeBitfields {
@@ -3338,35 +3341,93 @@ class ArrayType : public Type, public llvm::FoldingSetNode {
33383341
/// Represents the canonical version of C arrays with a specified constant size.
33393342
/// For example, the canonical type for 'int A[4 + 4*100]' is a
33403343
/// ConstantArrayType where the element type is 'int' and the size is 404.
3341-
class ConstantArrayType final
3342-
: public ArrayType,
3343-
private llvm::TrailingObjects<ConstantArrayType, const Expr *> {
3344+
class ConstantArrayType final : public ArrayType {
33443345
friend class ASTContext; // ASTContext creates these.
3345-
friend TrailingObjects;
33463346

3347-
llvm::APInt Size; // Allows us to unique the type.
3347+
struct ExternalSize {
3348+
ExternalSize(const llvm::APInt &Sz, const Expr *SE)
3349+
: Size(Sz), SizeExpr(SE) {}
3350+
llvm::APInt Size; // Allows us to unique the type.
3351+
const Expr *SizeExpr;
3352+
};
33483353

3349-
ConstantArrayType(QualType et, QualType can, const llvm::APInt &size,
3350-
const Expr *sz, ArraySizeModifier sm, unsigned tq)
3351-
: ArrayType(ConstantArray, et, can, sm, tq, sz), Size(size) {
3352-
ConstantArrayTypeBits.HasStoredSizeExpr = sz != nullptr;
3353-
if (ConstantArrayTypeBits.HasStoredSizeExpr) {
3354-
assert(!can.isNull() && "canonical constant array should not have size");
3355-
*getTrailingObjects<const Expr*>() = sz;
3356-
}
3354+
union {
3355+
uint64_t Size;
3356+
ExternalSize *SizePtr;
3357+
};
3358+
3359+
ConstantArrayType(QualType Et, QualType Can, uint64_t Width, uint64_t Sz,
3360+
ArraySizeModifier SM, unsigned TQ)
3361+
: ArrayType(ConstantArray, Et, Can, SM, TQ, nullptr), Size(Sz) {
3362+
ConstantArrayTypeBits.HasExternalSize = false;
3363+
ConstantArrayTypeBits.SizeWidth = Width / 8;
3364+
// The in-structure size stores the size in bytes rather than bits so we
3365+
// drop the three least significant bits since they're always zero anyways.
3366+
assert(Width < 0xFF && "Type width in bits must be less than 8 bits");
33573367
}
33583368

3359-
unsigned numTrailingObjects(OverloadToken<const Expr*>) const {
3360-
return ConstantArrayTypeBits.HasStoredSizeExpr;
3369+
ConstantArrayType(QualType Et, QualType Can, ExternalSize *SzPtr,
3370+
ArraySizeModifier SM, unsigned TQ)
3371+
: ArrayType(ConstantArray, Et, Can, SM, TQ, SzPtr->SizeExpr),
3372+
SizePtr(SzPtr) {
3373+
ConstantArrayTypeBits.HasExternalSize = true;
3374+
ConstantArrayTypeBits.SizeWidth = 0;
3375+
3376+
assert((SzPtr->SizeExpr == nullptr || !Can.isNull()) &&
3377+
"canonical constant array should not have size expression");
33613378
}
33623379

3380+
static ConstantArrayType *Create(const ASTContext &Ctx, QualType ET,
3381+
QualType Can, const llvm::APInt &Sz,
3382+
const Expr *SzExpr, ArraySizeModifier SzMod,
3383+
unsigned Qual);
3384+
33633385
public:
3364-
const llvm::APInt &getSize() const { return Size; }
3386+
/// Return the constant array size as an APInt.
3387+
llvm::APInt getSize() const {
3388+
return ConstantArrayTypeBits.HasExternalSize
3389+
? SizePtr->Size
3390+
: llvm::APInt(ConstantArrayTypeBits.SizeWidth * 8, Size);
3391+
}
3392+
3393+
/// Return the bit width of the size type.
3394+
unsigned getSizeBitWidth() const {
3395+
return ConstantArrayTypeBits.HasExternalSize
3396+
? SizePtr->Size.getBitWidth()
3397+
: static_cast<unsigned>(ConstantArrayTypeBits.SizeWidth * 8);
3398+
}
3399+
3400+
/// Return true if the size is zero.
3401+
bool isZeroSize() const {
3402+
return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.isZero()
3403+
: 0 == Size;
3404+
}
3405+
3406+
/// Return the size zero-extended as a uint64_t.
3407+
uint64_t getZExtSize() const {
3408+
return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.getZExtValue()
3409+
: Size;
3410+
}
3411+
3412+
/// Return the size sign-extended as a uint64_t.
3413+
int64_t getSExtSize() const {
3414+
return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.getSExtValue()
3415+
: static_cast<int64_t>(Size);
3416+
}
3417+
3418+
/// Return the size zero-extended to uint64_t or UINT64_MAX if the value is
3419+
/// larger than UINT64_MAX.
3420+
uint64_t getLimitedSize() const {
3421+
return ConstantArrayTypeBits.HasExternalSize
3422+
? SizePtr->Size.getLimitedValue()
3423+
: Size;
3424+
}
3425+
3426+
/// Return a pointer to the size expression.
33653427
const Expr *getSizeExpr() const {
3366-
return ConstantArrayTypeBits.HasStoredSizeExpr
3367-
? *getTrailingObjects<const Expr *>()
3368-
: nullptr;
3428+
return ConstantArrayTypeBits.HasExternalSize ? SizePtr->SizeExpr : nullptr;
33693429
}
3430+
33703431
bool isSugared() const { return false; }
33713432
QualType desugar() const { return QualType(this, 0); }
33723433

@@ -3383,14 +3444,13 @@ class ConstantArrayType final
33833444
static unsigned getMaxSizeBits(const ASTContext &Context);
33843445

33853446
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) {
3386-
Profile(ID, Ctx, getElementType(), getSize(), getSizeExpr(),
3447+
Profile(ID, Ctx, getElementType(), getZExtSize(), getSizeExpr(),
33873448
getSizeModifier(), getIndexTypeCVRQualifiers());
33883449
}
33893450

33903451
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx,
3391-
QualType ET, const llvm::APInt &ArraySize,
3392-
const Expr *SizeExpr, ArraySizeModifier SizeMod,
3393-
unsigned TypeQuals);
3452+
QualType ET, uint64_t ArraySize, const Expr *SizeExpr,
3453+
ArraySizeModifier SizeMod, unsigned TypeQuals);
33943454

33953455
static bool classof(const Type *T) {
33963456
return T->getTypeClass() == ConstantArray;

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) &&
@@ -3560,8 +3560,8 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
35603560
ArySize = ArySize.zextOrTrunc(Target->getMaxPointerWidth());
35613561

35623562
llvm::FoldingSetNodeID ID;
3563-
ConstantArrayType::Profile(ID, *this, EltTy, ArySize, SizeExpr, ASM,
3564-
IndexTypeQuals);
3563+
ConstantArrayType::Profile(ID, *this, EltTy, ArySize.getZExtValue(), SizeExpr,
3564+
ASM, IndexTypeQuals);
35653565

35663566
void *InsertPos = nullptr;
35673567
if (ConstantArrayType *ATP =
@@ -3585,11 +3585,8 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
35853585
assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP;
35863586
}
35873587

3588-
void *Mem = Allocate(
3589-
ConstantArrayType::totalSizeToAlloc<const Expr *>(SizeExpr ? 1 : 0),
3590-
alignof(ConstantArrayType));
3591-
auto *New = new (Mem)
3592-
ConstantArrayType(EltTy, Canon, ArySize, SizeExpr, ASM, IndexTypeQuals);
3588+
auto *New = ConstantArrayType::Create(*this, EltTy, Canon, ArySize, SizeExpr,
3589+
ASM, IndexTypeQuals);
35933590
ConstantArrayTypes.InsertNode(New, InsertPos);
35943591
Types.push_back(New);
35953592
return QualType(New, 0);
@@ -7051,7 +7048,7 @@ uint64_t
70517048
ASTContext::getConstantArrayElementCount(const ConstantArrayType *CA) const {
70527049
uint64_t ElementCount = 1;
70537050
do {
7054-
ElementCount *= CA->getSize().getZExtValue();
7051+
ElementCount *= CA->getZExtSize();
70557052
CA = dyn_cast_or_null<ConstantArrayType>(
70567053
CA->getElementType()->getAsArrayTypeUnsafe());
70577054
} while (CA);
@@ -8374,7 +8371,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
83748371
S += '[';
83758372

83768373
if (const auto *CAT = dyn_cast<ConstantArrayType>(AT))
8377-
S += llvm::utostr(CAT->getSize().getZExtValue());
8374+
S += llvm::utostr(CAT->getZExtSize());
83788375
else {
83798376
//Variable length arrays are encoded as a regular array with 0 elements.
83808377
assert((isa<VariableArrayType>(AT) || isa<IncompleteArrayType>(AT)) &&
@@ -10808,7 +10805,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer,
1080810805
{
1080910806
const ConstantArrayType* LCAT = getAsConstantArrayType(LHS);
1081010807
const ConstantArrayType* RCAT = getAsConstantArrayType(RHS);
10811-
if (LCAT && RCAT && RCAT->getSize() != LCAT->getSize())
10808+
if (LCAT && RCAT && RCAT->getZExtSize() != LCAT->getZExtSize())
1081210809
return {};
1081310810

1081410811
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 & 16 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()))
@@ -10996,8 +10996,7 @@ namespace {
1099610996
return Error(E);
1099710997
}
1099810998

10999-
Result = APValue(APValue::UninitArray(), 0,
11000-
CAT->getSize().getZExtValue());
10999+
Result = APValue(APValue::UninitArray(), 0, CAT->getZExtSize());
1100111000
if (!Result.hasArrayFiller())
1100211001
return true;
1100311002

@@ -11122,7 +11121,7 @@ bool ArrayExprEvaluator::VisitCXXParenListOrInitListExpr(
1112211121
Filler = Result.getArrayFiller();
1112311122

1112411123
unsigned NumEltsToInit = Args.size();
11125-
unsigned NumElts = CAT->getSize().getZExtValue();
11124+
unsigned NumElts = CAT->getZExtSize();
1112611125

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

1118111180
auto *CAT = cast<ConstantArrayType>(E->getType()->castAsArrayTypeUnsafe());
1118211181

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

1118611185
LValue Subobject = This;
@@ -11225,7 +11224,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
1122511224
bool HadZeroInit = Value->hasValue();
1122611225

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

1123011229
// Preserve the array filler if we had prior zero-initialization.
1123111230
APValue Filler =
@@ -11940,7 +11939,7 @@ static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) {
1194011939
return true;
1194111940
const auto *CAT = cast<ConstantArrayType>(Ctx.getAsArrayType(BaseType));
1194211941
uint64_t Index = Entry.getAsArrayIndex();
11943-
if (Index + 1 != CAT->getSize())
11942+
if (Index + 1 != CAT->getZExtSize())
1194411943
return false;
1194511944
BaseType = CAT->getElementType();
1194611945
} 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;

0 commit comments

Comments
 (0)