Skip to content

[NFC] Refactor ConstantArrayType size storage #85716

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 84 additions & 24 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -1689,7 +1689,10 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {

/// Whether we have a stored size expression.
LLVM_PREFERRED_TYPE(bool)
unsigned HasStoredSizeExpr : 1;
unsigned HasExternalSize : 1;

LLVM_PREFERRED_TYPE(unsigned)
unsigned SizeWidth : 5;
};

class BuiltinTypeBitfields {
Expand Down Expand Up @@ -3181,35 +3184,93 @@ class ArrayType : public Type, public llvm::FoldingSetNode {
/// Represents the canonical version of C arrays with a specified constant size.
/// For example, the canonical type for 'int A[4 + 4*100]' is a
/// ConstantArrayType where the element type is 'int' and the size is 404.
class ConstantArrayType final
: public ArrayType,
private llvm::TrailingObjects<ConstantArrayType, const Expr *> {
class ConstantArrayType final : public ArrayType {
friend class ASTContext; // ASTContext creates these.
friend TrailingObjects;

llvm::APInt Size; // Allows us to unique the type.
struct ExternalSize {
ExternalSize(const llvm::APInt &Sz, const Expr *SE)
: Size(Sz), SizeExpr(SE) {}
llvm::APInt Size; // Allows us to unique the type.
const Expr *SizeExpr;
};

ConstantArrayType(QualType et, QualType can, const llvm::APInt &size,
const Expr *sz, ArraySizeModifier sm, unsigned tq)
: ArrayType(ConstantArray, et, can, sm, tq, sz), Size(size) {
ConstantArrayTypeBits.HasStoredSizeExpr = sz != nullptr;
if (ConstantArrayTypeBits.HasStoredSizeExpr) {
assert(!can.isNull() && "canonical constant array should not have size");
*getTrailingObjects<const Expr*>() = sz;
}
union {
uint64_t Size;
ExternalSize *SizePtr;
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm reading this correctly, this actually saves 8 bytes over the current representation? That's nice.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My clearly wrong math is why I should do all math in bit shifts... Will fix.


ConstantArrayType(QualType Et, QualType Can, uint64_t Width, uint64_t Sz,
ArraySizeModifier SM, unsigned TQ)
: ArrayType(ConstantArray, Et, Can, SM, TQ, nullptr), Size(Sz) {
ConstantArrayTypeBits.HasExternalSize = false;
ConstantArrayTypeBits.SizeWidth = Width / 8;
// The in-structure size stores the size in bytes rather than bits so we
// drop the three least significant bits since they're always zero anyways.
assert(Width < 0xFF && "Type width in bits must be less than 8 bits");
}

unsigned numTrailingObjects(OverloadToken<const Expr*>) const {
return ConstantArrayTypeBits.HasStoredSizeExpr;
ConstantArrayType(QualType Et, QualType Can, ExternalSize *SzPtr,
ArraySizeModifier SM, unsigned TQ)
: ArrayType(ConstantArray, Et, Can, SM, TQ, SzPtr->SizeExpr),
SizePtr(SzPtr) {
ConstantArrayTypeBits.HasExternalSize = true;
ConstantArrayTypeBits.SizeWidth = 0;

assert((SzPtr->SizeExpr == nullptr || !Can.isNull()) &&
"canonical constant array should not have size expression");
}

static ConstantArrayType *Create(const ASTContext &Ctx, QualType ET,
QualType Can, const llvm::APInt &Sz,
const Expr *SzExpr, ArraySizeModifier SzMod,
unsigned Qual);

public:
const llvm::APInt &getSize() const { return Size; }
/// Return the constant array size as an APInt.
llvm::APInt getSize() const {
return ConstantArrayTypeBits.HasExternalSize
? SizePtr->Size
: llvm::APInt(ConstantArrayTypeBits.SizeWidth * 8, Size);
}

/// Return the bit width of the size type.
unsigned getSizeBitWidth() const {
return ConstantArrayTypeBits.HasExternalSize
? SizePtr->Size.getBitWidth()
: static_cast<unsigned>(ConstantArrayTypeBits.SizeWidth * 8);
}

/// Return true if the size is zero.
bool isZeroSize() const {
return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.isZero()
: 0 == Size;
}

/// Return the size zero-extended as a uint64_t.
uint64_t getZExtSize() const {
return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.getZExtValue()
: Size;
}

/// Return the size sign-extended as a uint64_t.
int64_t getSExtSize() const {
return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.getSExtValue()
: static_cast<int64_t>(Size);
}

/// Return the size zero-extended to uint64_t or UINT64_MAX if the value is
/// larger than UINT64_MAX.
uint64_t getLimitedSize() const {
return ConstantArrayTypeBits.HasExternalSize
? SizePtr->Size.getLimitedValue()
: Size;
}

/// Return a pointer to the size expression.
const Expr *getSizeExpr() const {
return ConstantArrayTypeBits.HasStoredSizeExpr
? *getTrailingObjects<const Expr *>()
: nullptr;
return ConstantArrayTypeBits.HasExternalSize ? SizePtr->SizeExpr : nullptr;
}

bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }

Expand All @@ -3226,14 +3287,13 @@ class ConstantArrayType final
static unsigned getMaxSizeBits(const ASTContext &Context);

void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) {
Profile(ID, Ctx, getElementType(), getSize(), getSizeExpr(),
Profile(ID, Ctx, getElementType(), getZExtSize(), getSizeExpr(),
getSizeModifier(), getIndexTypeCVRQualifiers());
}

static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx,
QualType ET, const llvm::APInt &ArraySize,
const Expr *SizeExpr, ArraySizeModifier SizeMod,
unsigned TypeQuals);
QualType ET, uint64_t ArraySize, const Expr *SizeExpr,
ArraySizeModifier SizeMod, unsigned TypeQuals);

static bool classof(const Type *T) {
return T->getTypeClass() == ConstantArray;
Expand Down
21 changes: 9 additions & 12 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1766,7 +1766,7 @@ TypeInfoChars
static getConstantArrayInfoInChars(const ASTContext &Context,
const ConstantArrayType *CAT) {
TypeInfoChars EltInfo = Context.getTypeInfoInChars(CAT->getElementType());
uint64_t Size = CAT->getSize().getZExtValue();
uint64_t Size = CAT->getZExtSize();
assert((Size == 0 || static_cast<uint64_t>(EltInfo.Width.getQuantity()) <=
(uint64_t)(-1)/Size) &&
"Overflow in array type char size evaluation");
Expand Down Expand Up @@ -1910,7 +1910,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
// Model non-constant sized arrays as size zero, but track the alignment.
uint64_t Size = 0;
if (const auto *CAT = dyn_cast<ConstantArrayType>(T))
Size = CAT->getSize().getZExtValue();
Size = CAT->getZExtSize();

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

llvm::FoldingSetNodeID ID;
ConstantArrayType::Profile(ID, *this, EltTy, ArySize, SizeExpr, ASM,
IndexTypeQuals);
ConstantArrayType::Profile(ID, *this, EltTy, ArySize.getZExtValue(), SizeExpr,
ASM, IndexTypeQuals);

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

void *Mem = Allocate(
ConstantArrayType::totalSizeToAlloc<const Expr *>(SizeExpr ? 1 : 0),
alignof(ConstantArrayType));
auto *New = new (Mem)
ConstantArrayType(EltTy, Canon, ArySize, SizeExpr, ASM, IndexTypeQuals);
auto *New = ConstantArrayType::Create(*this, EltTy, Canon, ArySize, SizeExpr,
ASM, IndexTypeQuals);
ConstantArrayTypes.InsertNode(New, InsertPos);
Types.push_back(New);
return QualType(New, 0);
Expand Down Expand Up @@ -7022,7 +7019,7 @@ uint64_t
ASTContext::getConstantArrayElementCount(const ConstantArrayType *CA) const {
uint64_t ElementCount = 1;
do {
ElementCount *= CA->getSize().getZExtValue();
ElementCount *= CA->getZExtSize();
CA = dyn_cast_or_null<ConstantArrayType>(
CA->getElementType()->getAsArrayTypeUnsafe());
} while (CA);
Expand Down Expand Up @@ -8345,7 +8342,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
S += '[';

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

QualType LHSElem = getAsArrayType(LHS)->getElementType();
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2840,7 +2840,7 @@ bool VarDecl::hasFlexibleArrayInit(const ASTContext &Ctx) const {
auto InitTy = Ctx.getAsConstantArrayType(FlexibleInit->getType());
if (!InitTy)
return false;
return InitTy->getSize() != 0;
return !InitTy->isZeroSize();
}

CharUnits VarDecl::getFlexibleArrayInitChars(const ASTContext &Ctx) const {
Expand Down
31 changes: 15 additions & 16 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ namespace {
IsArray = true;

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

unsigned Elts = CAT->getSize().getZExtValue();
unsigned Elts = CAT->getZExtSize();
Result = APValue(APValue::UninitArray(),
std::min(S->getLength(), Elts), Elts);
APSInt Value(Info.Ctx.getTypeSize(CharType),
Expand Down Expand Up @@ -3619,7 +3619,7 @@ static bool CheckArraySize(EvalInfo &Info, const ConstantArrayType *CAT,
SourceLocation CallLoc = {}) {
return Info.CheckArraySize(
CAT->getSizeExpr() ? CAT->getSizeExpr()->getBeginLoc() : CallLoc,
CAT->getNumAddressingBits(Info.Ctx), CAT->getSize().getZExtValue(),
CAT->getNumAddressingBits(Info.Ctx), CAT->getZExtSize(),
/*Diag=*/true);
}

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

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

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

if (!CheckArraySize(Info, CAT, CallRange.getBegin()))
Expand Down Expand Up @@ -7396,7 +7396,7 @@ class BufferToAPValueConverter {
}

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

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

unsigned Bits =
std::max(CAT->getSize().getBitWidth(), ArrayBound.getBitWidth());
std::max(CAT->getSizeBitWidth(), ArrayBound.getBitWidth());
llvm::APInt InitBound = CAT->getSize().zext(Bits);
llvm::APInt AllocBound = ArrayBound.zext(Bits);
if (InitBound.ugt(AllocBound)) {
Expand Down Expand Up @@ -10410,7 +10410,7 @@ bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(

if (Field->getType()->isIncompleteArrayType()) {
if (auto *CAT = Info.Ctx.getAsConstantArrayType(Init->getType())) {
if (!CAT->getSize().isZero()) {
if (!CAT->isZeroSize()) {
// Bail out for now. This might sort of "work", but the rest of the
// code isn't really prepared to handle it.
Info.FFDiag(Init, diag::note_constexpr_unsupported_flexible_array);
Expand Down Expand Up @@ -10554,7 +10554,7 @@ bool RecordExprEvaluator::VisitCXXStdInitializerListExpr(
// End pointer.
if (!HandleLValueArrayAdjustment(Info, E, Array,
ArrayType->getElementType(),
ArrayType->getSize().getZExtValue()))
ArrayType->getZExtSize()))
return false;
Array.moveInto(Result.getStructField(1));
} else if (Info.Ctx.hasSameType(Field->getType(), Info.Ctx.getSizeType()))
Expand Down Expand Up @@ -10996,8 +10996,7 @@ namespace {
return Error(E);
}

Result = APValue(APValue::UninitArray(), 0,
CAT->getSize().getZExtValue());
Result = APValue(APValue::UninitArray(), 0, CAT->getZExtSize());
if (!Result.hasArrayFiller())
return true;

Expand Down Expand Up @@ -11122,7 +11121,7 @@ bool ArrayExprEvaluator::VisitCXXParenListOrInitListExpr(
Filler = Result.getArrayFiller();

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

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

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

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

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

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

// Preserve the array filler if we had prior zero-initialization.
APValue Filler =
Expand Down Expand Up @@ -11940,7 +11939,7 @@ static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) {
return true;
const auto *CAT = cast<ConstantArrayType>(Ctx.getAsArrayType(BaseType));
uint64_t Index = Entry.getAsArrayIndex();
if (Index + 1 != CAT->getSize())
if (Index + 1 != CAT->getZExtSize())
return false;
BaseType = CAT->getElementType();
} else if (BaseType->isAnyComplexType()) {
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,7 @@ bool ByteCodeExprGen<Emitter>::VisitImplicitValueInitExpr(const ImplicitValueIni
const ArrayType *AT = QT->getAsArrayTypeUnsafe();
assert(AT);
const auto *CAT = cast<ConstantArrayType>(AT);
size_t NumElems = CAT->getSize().getZExtValue();
size_t NumElems = CAT->getZExtSize();
PrimType ElemT = classifyPrim(CAT->getElementType());

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

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

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

Expand Down Expand Up @@ -1919,7 +1919,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXConstructExpr(
const ConstantArrayType *CAT =
Ctx.getASTContext().getAsConstantArrayType(E->getType());
assert(CAT);
size_t NumElems = CAT->getSize().getZExtValue();
size_t NumElems = CAT->getZExtSize();
const Function *Func = getFunction(E->getConstructor());
if (!Func || !Func->isConstexpr())
return false;
Expand Down
Loading