@@ -1001,6 +1001,24 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
10011001 // Can't find the field referenced by the "counted_by" attribute.
10021002 return nullptr;
10031003
1004+ if (isa<DeclRefExpr>(Base))
1005+ // The whole struct is specificed in the __bdos. The calculation of the
1006+ // whole size of the structure can be done in two ways:
1007+ //
1008+ // 1) sizeof(struct S) + count * sizeof(typeof(fam))
1009+ // 2) offsetof(struct S, fam) + count * sizeof(typeof(fam))
1010+ //
1011+ // The first will add additional padding after the end of the array,
1012+ // allocation while the second method is more precise, but not quite
1013+ // expected from programmers. See
1014+ // https://lore.kernel.org/lkml/ZvV6X5FPBBW7CO1f@archlinux/ for a
1015+ // discussion of the topic.
1016+ //
1017+ // GCC isn't (currently) able to calculate __bdos on a pointer to the whole
1018+ // structure. Therefore, because of the above issue, we'll choose to match
1019+ // what GCC does for consistency's sake.
1020+ return nullptr;
1021+
10041022 // Build a load of the counted_by field.
10051023 bool IsSigned = CountedByFD->getType()->isSignedIntegerType();
10061024 Value *CountedByInst = EmitCountedByFieldExpr(Base, FAMDecl, CountedByFD);
@@ -1031,32 +1049,9 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
10311049 CharUnits Size = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
10321050 llvm::Constant *ElemSize =
10331051 llvm::ConstantInt::get(ResType, Size.getQuantity(), IsSigned);
1034- Value *FAMSize =
1052+ Value *Res =
10351053 Builder.CreateMul(CountedByInst, ElemSize, "", !IsSigned, IsSigned);
1036- FAMSize = Builder.CreateIntCast(FAMSize, ResType, IsSigned);
1037- Value *Res = FAMSize;
1038-
1039- if (isa<DeclRefExpr>(Base)) {
1040- // The whole struct is specificed in the __bdos.
1041- const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(OuterRD);
1042-
1043- // Get the offset of the FAM.
1044- llvm::Constant *FAMOffset = ConstantInt::get(ResType, Offset, IsSigned);
1045- Value *OffsetAndFAMSize =
1046- Builder.CreateAdd(FAMOffset, Res, "", !IsSigned, IsSigned);
1047-
1048- // Get the full size of the struct.
1049- llvm::Constant *SizeofStruct =
1050- ConstantInt::get(ResType, Layout.getSize().getQuantity(), IsSigned);
1051-
1052- // max(sizeof(struct s),
1053- // offsetof(struct s, array) + p->count * sizeof(*p->array))
1054- Res = IsSigned
1055- ? Builder.CreateBinaryIntrinsic(llvm::Intrinsic::smax,
1056- OffsetAndFAMSize, SizeofStruct)
1057- : Builder.CreateBinaryIntrinsic(llvm::Intrinsic::umax,
1058- OffsetAndFAMSize, SizeofStruct);
1059- }
1054+ Res = Builder.CreateIntCast(Res, ResType, IsSigned);
10601055
10611056 // A negative \p IdxInst or \p CountedByInst means that the index lands
10621057 // outside of the flexible array member. If that's the case, we want to
0 commit comments