@@ -822,6 +822,158 @@ CodeGenFunction::evaluateOrEmitBuiltinObjectSize(const Expr *E, unsigned Type,
822
822
return ConstantInt::get(ResType, ObjectSize, /*isSigned=*/true);
823
823
}
824
824
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
+
825
977
/// Returns a Value corresponding to the size of the given expression.
826
978
/// This Value may be either of the following:
827
979
/// - 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,
861
1013
return getDefaultBuiltinObjectSizeResult(Type, ResType);
862
1014
863
1015
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;
1004
1020
}
1005
1021
1006
1022
Value *Ptr = EmittedE ? EmittedE : EmitScalarExpr(E);
0 commit comments