@@ -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);
0 commit comments