Skip to content

Commit a76adfb

Browse files
authored
[NFC][Clang] Refactor code to calculate flexible array member size (#72790)
The code that calculates the flexible array member size is big enough to warrant its own method.
1 parent eb76982 commit a76adfb

File tree

2 files changed

+159
-140
lines changed

2 files changed

+159
-140
lines changed

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 156 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,158 @@ CodeGenFunction::evaluateOrEmitBuiltinObjectSize(const Expr *E, unsigned Type,
822822
return ConstantInt::get(ResType, ObjectSize, /*isSigned=*/true);
823823
}
824824

825+
llvm::Value *
826+
CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
827+
llvm::IntegerType *ResType) {
828+
// The code generated here calculates the size of a struct with a flexible
829+
// array member that uses the counted_by attribute. There are two instances
830+
// we handle:
831+
//
832+
// struct s {
833+
// unsigned long flags;
834+
// int count;
835+
// int array[] __attribute__((counted_by(count)));
836+
// }
837+
//
838+
// 1) bdos of the flexible array itself:
839+
//
840+
// __builtin_dynamic_object_size(p->array, 1) ==
841+
// p->count * sizeof(*p->array)
842+
//
843+
// 2) bdos of a pointer into the flexible array:
844+
//
845+
// __builtin_dynamic_object_size(&p->array[42], 1) ==
846+
// (p->count - 42) * sizeof(*p->array)
847+
//
848+
// 2) bdos of the whole struct, including the flexible array:
849+
//
850+
// __builtin_dynamic_object_size(p, 1) ==
851+
// max(sizeof(struct s),
852+
// offsetof(struct s, array) + p->count * sizeof(*p->array))
853+
//
854+
const Expr *Base = E->IgnoreParenImpCasts();
855+
const Expr *Idx = nullptr;
856+
857+
if (const auto *UO = dyn_cast<UnaryOperator>(Base);
858+
UO && UO->getOpcode() == UO_AddrOf) {
859+
if (const auto *ASE =
860+
dyn_cast<ArraySubscriptExpr>(UO->getSubExpr()->IgnoreParens())) {
861+
Base = ASE->getBase();
862+
Idx = ASE->getIdx()->IgnoreParenImpCasts();
863+
864+
if (const auto *IL = dyn_cast<IntegerLiteral>(Idx);
865+
IL && !IL->getValue().getSExtValue())
866+
Idx = nullptr;
867+
}
868+
}
869+
870+
const ValueDecl *CountedByFD = FindCountedByField(Base);
871+
if (!CountedByFD)
872+
// Can't find the field referenced by the "counted_by" attribute.
873+
return nullptr;
874+
875+
// Build a load of the counted_by field.
876+
bool IsSigned = CountedByFD->getType()->isSignedIntegerType();
877+
const RecordDecl *OuterRD =
878+
CountedByFD->getDeclContext()->getOuterLexicalRecordContext();
879+
ASTContext &Ctx = getContext();
880+
881+
// Load the counted_by field.
882+
const Expr *CountedByExpr = BuildCountedByFieldExpr(Base, CountedByFD);
883+
Value *CountedByInst = EmitAnyExprToTemp(CountedByExpr).getScalarVal();
884+
llvm::Type *CountedByTy = CountedByInst->getType();
885+
886+
if (Idx) {
887+
// There's an index into the array. Remove it from the count.
888+
bool IdxSigned = Idx->getType()->isSignedIntegerType();
889+
Value *IdxInst = EmitAnyExprToTemp(Idx).getScalarVal();
890+
IdxInst = IdxSigned ? Builder.CreateSExtOrTrunc(IdxInst, CountedByTy)
891+
: Builder.CreateZExtOrTrunc(IdxInst, CountedByTy);
892+
893+
// If the index is negative, don't subtract it from the counted_by
894+
// value. The pointer is pointing to something before the FAM.
895+
IdxInst = Builder.CreateNeg(IdxInst, "", !IdxSigned, IdxSigned);
896+
CountedByInst =
897+
Builder.CreateAdd(CountedByInst, IdxInst, "", !IsSigned, IsSigned);
898+
}
899+
900+
// Get the size of the flexible array member's base type.
901+
const ValueDecl *FAMDecl = nullptr;
902+
if (const auto *ME = dyn_cast<MemberExpr>(Base)) {
903+
const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
904+
getLangOpts().getStrictFlexArraysLevel();
905+
if (const ValueDecl *MD = ME->getMemberDecl()) {
906+
if (!Decl::isFlexibleArrayMemberLike(
907+
Ctx, MD, MD->getType(), StrictFlexArraysLevel,
908+
/*IgnoreTemplateOrMacroSubstitution=*/true))
909+
return nullptr;
910+
// Base is referencing the FAM itself.
911+
FAMDecl = MD;
912+
}
913+
}
914+
915+
if (!FAMDecl)
916+
FAMDecl = FindFlexibleArrayMemberField(Ctx, OuterRD);
917+
918+
assert(FAMDecl && "Can't find the flexible array member field");
919+
920+
const ArrayType *ArrayTy = Ctx.getAsArrayType(FAMDecl->getType());
921+
CharUnits Size = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
922+
llvm::Constant *ElemSize =
923+
llvm::ConstantInt::get(CountedByTy, Size.getQuantity(), IsSigned);
924+
925+
// Calculate how large the flexible array member is in bytes.
926+
Value *FAMSize =
927+
Builder.CreateMul(CountedByInst, ElemSize, "", !IsSigned, IsSigned);
928+
FAMSize = IsSigned ? Builder.CreateSExtOrTrunc(FAMSize, ResType)
929+
: Builder.CreateZExtOrTrunc(FAMSize, ResType);
930+
Value *Res = FAMSize;
931+
932+
if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) {
933+
// The whole struct is specificed in the __bdos.
934+
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(OuterRD);
935+
936+
// Get the offset of the FAM.
937+
CharUnits Offset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(FAMDecl));
938+
llvm::Constant *FAMOffset =
939+
ConstantInt::get(ResType, Offset.getQuantity(), IsSigned);
940+
941+
// max(sizeof(struct s),
942+
// offsetof(struct s, array) + p->count * sizeof(*p->array))
943+
Value *OffsetAndFAMSize =
944+
Builder.CreateAdd(FAMOffset, Res, "", !IsSigned, IsSigned);
945+
946+
// Get the full size of the struct.
947+
llvm::Constant *SizeofStruct =
948+
ConstantInt::get(ResType, Layout.getSize().getQuantity(), IsSigned);
949+
950+
Res = IsSigned
951+
? Builder.CreateBinaryIntrinsic(llvm::Intrinsic::smax,
952+
OffsetAndFAMSize, SizeofStruct)
953+
: Builder.CreateBinaryIntrinsic(llvm::Intrinsic::umax,
954+
OffsetAndFAMSize, SizeofStruct);
955+
} else if (const auto *ME = dyn_cast<MemberExpr>(Base)) {
956+
// Pointing to a place before the FAM. Add the difference to the FAM's
957+
// size.
958+
if (const ValueDecl *MD = ME->getMemberDecl(); MD != FAMDecl) {
959+
CharUnits Offset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(MD));
960+
CharUnits FAMOffset =
961+
Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(FAMDecl));
962+
963+
Res = Builder.CreateAdd(
964+
Res, ConstantInt::get(ResType, FAMOffset.getQuantity() -
965+
Offset.getQuantity()));
966+
}
967+
}
968+
969+
// A negative 'FAMSize' means that the index was greater than the count,
970+
// or an improperly set count field. Return -1 (for types 0 and 1) or 0
971+
// (for types 2 and 3).
972+
return Builder.CreateSelect(Builder.CreateIsNeg(FAMSize),
973+
getDefaultBuiltinObjectSizeResult(Type, ResType),
974+
Res);
975+
}
976+
825977
/// Returns a Value corresponding to the size of the given expression.
826978
/// This Value may be either of the following:
827979
/// - A llvm::Argument (if E is a param with the pass_object_size attribute on
@@ -861,146 +1013,10 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type,
8611013
return getDefaultBuiltinObjectSizeResult(Type, ResType);
8621014

8631015
if (IsDynamic) {
864-
// The code generated here calculates the size of a struct with a flexible
865-
// array member that uses the counted_by attribute. There are two instances
866-
// we handle:
867-
//
868-
// struct s {
869-
// unsigned long flags;
870-
// int count;
871-
// int array[] __attribute__((counted_by(count)));
872-
// }
873-
//
874-
// 1) bdos of the flexible array itself:
875-
//
876-
// __builtin_dynamic_object_size(p->array, 1) ==
877-
// p->count * sizeof(*p->array)
878-
//
879-
// 2) bdos of a pointer into the flexible array:
880-
//
881-
// __builtin_dynamic_object_size(&p->array[42], 1) ==
882-
// (p->count - 42) * sizeof(*p->array)
883-
//
884-
// 2) bdos of the whole struct, including the flexible array:
885-
//
886-
// __builtin_dynamic_object_size(p, 1) ==
887-
// max(sizeof(struct s),
888-
// offsetof(struct s, array) + p->count * sizeof(*p->array))
889-
//
890-
const Expr *Base = E->IgnoreParenImpCasts();
891-
const Expr *Idx = nullptr;
892-
if (const auto *UO = dyn_cast<UnaryOperator>(Base);
893-
UO && UO->getOpcode() == UO_AddrOf) {
894-
if (const auto *ASE =
895-
dyn_cast<ArraySubscriptExpr>(UO->getSubExpr()->IgnoreParens())) {
896-
Base = ASE->getBase();
897-
Idx = ASE->getIdx()->IgnoreParenImpCasts();
898-
899-
if (const auto *IL = dyn_cast<IntegerLiteral>(Idx);
900-
IL && !IL->getValue().getSExtValue())
901-
Idx = nullptr;
902-
}
903-
}
904-
905-
if (const ValueDecl *CountedByFD = FindCountedByField(Base)) {
906-
bool IsSigned = CountedByFD->getType()->isSignedIntegerType();
907-
const RecordDecl *OuterRD =
908-
CountedByFD->getDeclContext()->getOuterLexicalRecordContext();
909-
ASTContext &Ctx = getContext();
910-
911-
// Load the counted_by field.
912-
const Expr *CountedByExpr = BuildCountedByFieldExpr(Base, CountedByFD);
913-
Value *CountedByInst = EmitAnyExprToTemp(CountedByExpr).getScalarVal();
914-
llvm::Type *CountedByTy = CountedByInst->getType();
915-
916-
if (Idx) {
917-
// There's an index into the array. Remove it from the count.
918-
bool IdxSigned = Idx->getType()->isSignedIntegerType();
919-
Value *IdxInst = EmitAnyExprToTemp(Idx).getScalarVal();
920-
IdxInst = IdxSigned ? Builder.CreateSExtOrTrunc(IdxInst, CountedByTy)
921-
: Builder.CreateZExtOrTrunc(IdxInst, CountedByTy);
922-
923-
// If the index is negative, don't subtract it from the counted_by
924-
// value. The pointer is pointing to something before the FAM.
925-
IdxInst = Builder.CreateNeg(IdxInst, "", !IdxSigned, IdxSigned);
926-
CountedByInst =
927-
Builder.CreateAdd(CountedByInst, IdxInst, "", !IsSigned, IsSigned);
928-
}
929-
930-
// Get the size of the flexible array member's base type.
931-
const ValueDecl *FAMDecl = nullptr;
932-
if (const auto *ME = dyn_cast<MemberExpr>(Base)) {
933-
const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
934-
getLangOpts().getStrictFlexArraysLevel();
935-
if (const ValueDecl *MD = ME->getMemberDecl();
936-
MD && Decl::isFlexibleArrayMemberLike(
937-
Ctx, MD, MD->getType(), StrictFlexArraysLevel,
938-
/*IgnoreTemplateOrMacroSubstitution=*/true))
939-
// Base is referencing the FAM itself.
940-
FAMDecl = MD;
941-
}
942-
943-
if (!FAMDecl)
944-
FAMDecl = FindFlexibleArrayMemberField(Ctx, OuterRD);
945-
946-
assert(FAMDecl && "Can't find the flexible array member field");
947-
948-
const ArrayType *ArrayTy = Ctx.getAsArrayType(FAMDecl->getType());
949-
CharUnits Size = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
950-
llvm::Constant *ElemSize =
951-
llvm::ConstantInt::get(CountedByTy, Size.getQuantity(), IsSigned);
952-
953-
// Calculate how large the flexible array member is in bytes.
954-
Value *FAMSize =
955-
Builder.CreateMul(CountedByInst, ElemSize, "", !IsSigned, IsSigned);
956-
FAMSize = IsSigned ? Builder.CreateSExtOrTrunc(FAMSize, ResType)
957-
: Builder.CreateZExtOrTrunc(FAMSize, ResType);
958-
Value *Res = FAMSize;
959-
960-
if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) {
961-
// The whole struct is specificed in the __bdos.
962-
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(OuterRD);
963-
964-
// Get the offset of the FAM.
965-
CharUnits Offset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(FAMDecl));
966-
llvm::Constant *FAMOffset =
967-
ConstantInt::get(ResType, Offset.getQuantity(), IsSigned);
968-
969-
// max(sizeof(struct s),
970-
// offsetof(struct s, array) + p->count * sizeof(*p->array))
971-
Value *OffsetAndFAMSize =
972-
Builder.CreateAdd(FAMOffset, Res, "", !IsSigned, IsSigned);
973-
974-
// Get the full size of the struct.
975-
llvm::Constant *SizeofStruct =
976-
ConstantInt::get(ResType, Layout.getSize().getQuantity(), IsSigned);
977-
978-
Res = IsSigned
979-
? Builder.CreateBinaryIntrinsic(
980-
llvm::Intrinsic::smax, OffsetAndFAMSize, SizeofStruct)
981-
: Builder.CreateBinaryIntrinsic(
982-
llvm::Intrinsic::umax, OffsetAndFAMSize, SizeofStruct);
983-
} else if (const auto *ME = dyn_cast<MemberExpr>(Base)) {
984-
// Pointing to a place before the FAM. Add the difference to the FAM's
985-
// size.
986-
if (const ValueDecl *MD = ME->getMemberDecl(); MD != FAMDecl) {
987-
CharUnits Offset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(MD));
988-
CharUnits FAMOffset =
989-
Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(FAMDecl));
990-
991-
Res = Builder.CreateAdd(
992-
Res, ConstantInt::get(ResType, FAMOffset.getQuantity() -
993-
Offset.getQuantity()));
994-
}
995-
}
996-
997-
// A negative 'FAMSize' means that the index was greater than the count,
998-
// or an improperly set count field. Return -1 (for types 0 and 1) or 0
999-
// (for types 2 and 3).
1000-
return Builder.CreateSelect(
1001-
Builder.CreateIsNeg(FAMSize),
1002-
getDefaultBuiltinObjectSizeResult(Type, ResType), Res);
1003-
}
1016+
// Emit special code for a flexible array member with the "counted_by"
1017+
// attribute.
1018+
if (Value *V = emitFlexibleArrayMemberSize(E, Type, ResType))
1019+
return V;
10041020
}
10051021

10061022
Value *Ptr = EmittedE ? EmittedE : EmitScalarExpr(E);

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4830,6 +4830,9 @@ class CodeGenFunction : public CodeGenTypeCache {
48304830
llvm::Value *EmittedE,
48314831
bool IsDynamic);
48324832

4833+
llvm::Value *emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
4834+
llvm::IntegerType *ResType);
4835+
48334836
void emitZeroOrPatternForAutoVarInit(QualType type, const VarDecl &D,
48344837
Address Loc);
48354838

0 commit comments

Comments
 (0)