@@ -1001,6 +1001,24 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
1001
1001
// Can't find the field referenced by the "counted_by" attribute.
1002
1002
return nullptr;
1003
1003
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
+
1004
1022
// Build a load of the counted_by field.
1005
1023
bool IsSigned = CountedByFD->getType()->isSignedIntegerType();
1006
1024
Value *CountedByInst = EmitCountedByFieldExpr(Base, FAMDecl, CountedByFD);
@@ -1031,32 +1049,9 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
1031
1049
CharUnits Size = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
1032
1050
llvm::Constant *ElemSize =
1033
1051
llvm::ConstantInt::get(ResType, Size.getQuantity(), IsSigned);
1034
- Value *FAMSize =
1052
+ Value *Res =
1035
1053
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);
1060
1055
1061
1056
// A negative \p IdxInst or \p CountedByInst means that the index lands
1062
1057
// outside of the flexible array member. If that's the case, we want to
0 commit comments