|
25 | 25 | #include "clang/AST/Attr.h"
|
26 | 26 | #include "clang/AST/Decl.h"
|
27 | 27 | #include "clang/AST/OSLog.h"
|
| 28 | +#include "clang/AST/OperationKinds.h" |
28 | 29 | #include "clang/Basic/TargetBuiltins.h"
|
29 | 30 | #include "clang/Basic/TargetInfo.h"
|
30 | 31 | #include "clang/Basic/TargetOptions.h"
|
@@ -858,63 +859,155 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type,
|
858 | 859 | }
|
859 | 860 | }
|
860 | 861 |
|
| 862 | + // LLVM can't handle Type=3 appropriately, and __builtin_object_size shouldn't |
| 863 | + // evaluate E for side-effects. In either case, we shouldn't lower to |
| 864 | + // @llvm.objectsize. |
| 865 | + if (Type == 3 || (!EmittedE && E->HasSideEffects(getContext()))) |
| 866 | + return getDefaultBuiltinObjectSizeResult(Type, ResType); |
| 867 | + |
861 | 868 | if (IsDynamic) {
|
862 |
| - LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = |
863 |
| - getLangOpts().getStrictFlexArraysLevel(); |
| 869 | + // The code generated here calculates the size of a struct with a flexible |
| 870 | + // array member that uses the counted_by attribute. There are two instances |
| 871 | + // we handle: |
| 872 | + // |
| 873 | + // struct s { |
| 874 | + // unsigned long flags; |
| 875 | + // int count; |
| 876 | + // int array[] __attribute__((counted_by(count))); |
| 877 | + // } |
| 878 | + // |
| 879 | + // 1) bdos of the flexible array itself: |
| 880 | + // |
| 881 | + // __builtin_dynamic_object_size(p->array, 1) == |
| 882 | + // p->count * sizeof(*p->array) |
| 883 | + // |
| 884 | + // 2) bdos of a pointer into the flexible array: |
| 885 | + // |
| 886 | + // __builtin_dynamic_object_size(&p->array[42], 1) == |
| 887 | + // (p->count - 42) * sizeof(*p->array) |
| 888 | + // |
| 889 | + // 2) bdos of the whole struct, including the flexible array: |
| 890 | + // |
| 891 | + // __builtin_dynamic_object_size(p, 1) == |
| 892 | + // max(sizeof(struct s), |
| 893 | + // offsetof(struct s, array) + p->count * sizeof(*p->array)) |
| 894 | + // |
864 | 895 | const Expr *Base = E->IgnoreParenImpCasts();
|
865 |
| - |
866 |
| - if (FieldDecl *FD = FindCountedByField(Base, StrictFlexArraysLevel)) { |
867 |
| - const auto *ME = dyn_cast<MemberExpr>(Base); |
868 |
| - llvm::Value *ObjectSize = nullptr; |
869 |
| - |
870 |
| - if (!ME) { |
871 |
| - const auto *DRE = dyn_cast<DeclRefExpr>(Base); |
872 |
| - ValueDecl *VD = nullptr; |
873 |
| - |
874 |
| - ObjectSize = ConstantInt::get( |
875 |
| - ResType, |
876 |
| - getContext().getTypeSize(DRE->getType()->getPointeeType()) / 8, |
877 |
| - true); |
878 |
| - |
879 |
| - if (auto *RD = DRE->getType()->getPointeeType()->getAsRecordDecl()) |
880 |
| - VD = RD->getLastField(); |
881 |
| - |
882 |
| - Expr *ICE = ImplicitCastExpr::Create( |
883 |
| - getContext(), DRE->getType(), CK_LValueToRValue, |
884 |
| - const_cast<Expr *>(cast<Expr>(DRE)), nullptr, VK_PRValue, |
885 |
| - FPOptionsOverride()); |
886 |
| - ME = MemberExpr::CreateImplicit(getContext(), ICE, true, VD, |
887 |
| - VD->getType(), VK_LValue, OK_Ordinary); |
| 896 | + const Expr *Idx = nullptr; |
| 897 | + if (const auto *UO = dyn_cast<UnaryOperator>(Base); |
| 898 | + UO && UO->getOpcode() == UO_AddrOf) { |
| 899 | + if (const auto *ASE = |
| 900 | + dyn_cast<ArraySubscriptExpr>(UO->getSubExpr()->IgnoreParens())) { |
| 901 | + Base = ASE->getBase(); |
| 902 | + Idx = ASE->getIdx()->IgnoreParenImpCasts(); |
| 903 | + |
| 904 | + if (const auto *IL = dyn_cast<IntegerLiteral>(Idx); |
| 905 | + IL && !IL->getValue().getSExtValue()) |
| 906 | + Idx = nullptr; |
888 | 907 | }
|
| 908 | + } |
889 | 909 |
|
890 |
| - // At this point, we know that \p ME is a flexible array member. |
891 |
| - const auto *ArrayTy = getContext().getAsArrayType(ME->getType()); |
892 |
| - unsigned Size = getContext().getTypeSize(ArrayTy->getElementType()); |
893 |
| - |
894 |
| - llvm::Value *CountField = |
895 |
| - EmitAnyExprToTemp(MemberExpr::CreateImplicit( |
896 |
| - getContext(), const_cast<Expr *>(ME->getBase()), |
897 |
| - ME->isArrow(), FD, FD->getType(), VK_LValue, |
898 |
| - OK_Ordinary)) |
899 |
| - .getScalarVal(); |
| 910 | + if (const ValueDecl *CountedByFD = FindCountedByField(Base)) { |
| 911 | + bool IsSigned = CountedByFD->getType()->isSignedIntegerType(); |
| 912 | + const RecordDecl *OuterRD = |
| 913 | + CountedByFD->getDeclContext()->getOuterLexicalRecordContext(); |
| 914 | + ASTContext &Ctx = getContext(); |
| 915 | + |
| 916 | + // Load the counted_by field. |
| 917 | + const Expr *CountedByExpr = BuildCountedByFieldExpr(Base, CountedByFD); |
| 918 | + Value *CountedByInst = EmitAnyExprToTemp(CountedByExpr).getScalarVal(); |
| 919 | + llvm::Type *CountedByTy = CountedByInst->getType(); |
| 920 | + |
| 921 | + if (Idx) { |
| 922 | + // There's an index into the array. Remove it from the count. |
| 923 | + bool IdxSigned = Idx->getType()->isSignedIntegerType(); |
| 924 | + Value *IdxInst = EmitAnyExprToTemp(Idx).getScalarVal(); |
| 925 | + IdxInst = IdxSigned ? Builder.CreateSExtOrTrunc(IdxInst, CountedByTy) |
| 926 | + : Builder.CreateZExtOrTrunc(IdxInst, CountedByTy); |
| 927 | + |
| 928 | + // If the index is negative, don't subtract it from the counted_by |
| 929 | + // value. The pointer is pointing to something before the FAM. |
| 930 | + IdxInst = Builder.CreateNeg(IdxInst, "", !IdxSigned, IdxSigned); |
| 931 | + CountedByInst = |
| 932 | + Builder.CreateAdd(CountedByInst, IdxInst, "", !IsSigned, IsSigned); |
| 933 | + } |
900 | 934 |
|
901 |
| - llvm::Value *Mul = Builder.CreateMul( |
902 |
| - CountField, llvm::ConstantInt::get(CountField->getType(), Size / 8)); |
903 |
| - Mul = Builder.CreateZExtOrTrunc(Mul, ResType); |
| 935 | + // Get the size of the flexible array member's base type. |
| 936 | + const ValueDecl *FAMDecl = nullptr; |
| 937 | + if (const auto *ME = dyn_cast<MemberExpr>(Base)) { |
| 938 | + const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = |
| 939 | + getLangOpts().getStrictFlexArraysLevel(); |
| 940 | + if (const ValueDecl *MD = ME->getMemberDecl(); |
| 941 | + MD && Decl::isFlexibleArrayMemberLike( |
| 942 | + Ctx, MD, MD->getType(), StrictFlexArraysLevel, |
| 943 | + /*IgnoreTemplateOrMacroSubstitution=*/true)) |
| 944 | + // Base is referencing the FAM itself. |
| 945 | + FAMDecl = MD; |
| 946 | + } |
904 | 947 |
|
905 |
| - if (ObjectSize) |
906 |
| - return Builder.CreateAdd(ObjectSize, Mul); |
| 948 | + if (!FAMDecl) |
| 949 | + FAMDecl = FindFlexibleArrayMemberField(Ctx, OuterRD); |
| 950 | + |
| 951 | + assert(FAMDecl && "Can't find the flexible array member field"); |
| 952 | + |
| 953 | + const ArrayType *ArrayTy = Ctx.getAsArrayType(FAMDecl->getType()); |
| 954 | + CharUnits Size = Ctx.getTypeSizeInChars(ArrayTy->getElementType()); |
| 955 | + llvm::Constant *ElemSize = |
| 956 | + llvm::ConstantInt::get(CountedByTy, Size.getQuantity(), IsSigned); |
| 957 | + |
| 958 | + // Calculate how large the flexible array member is in bytes. |
| 959 | + Value *FAMSize = |
| 960 | + Builder.CreateMul(CountedByInst, ElemSize, "", !IsSigned, IsSigned); |
| 961 | + FAMSize = IsSigned ? Builder.CreateSExtOrTrunc(FAMSize, ResType) |
| 962 | + : Builder.CreateZExtOrTrunc(FAMSize, ResType); |
| 963 | + Value *Res = FAMSize; |
| 964 | + |
| 965 | + if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) { |
| 966 | + // The whole struct is specificed in the __bdos. |
| 967 | + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(OuterRD); |
| 968 | + |
| 969 | + // Get the offset of the FAM. |
| 970 | + CharUnits Offset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(FAMDecl)); |
| 971 | + llvm::Constant *FAMOffset = |
| 972 | + ConstantInt::get(ResType, Offset.getQuantity(), IsSigned); |
| 973 | + |
| 974 | + // max(sizeof(struct s), |
| 975 | + // offsetof(struct s, array) + p->count * sizeof(*p->array)) |
| 976 | + Value *OffsetAndFAMSize = |
| 977 | + Builder.CreateAdd(FAMOffset, Res, "", !IsSigned, IsSigned); |
| 978 | + |
| 979 | + // Get the full size of the struct. |
| 980 | + llvm::Constant *SizeofStruct = |
| 981 | + ConstantInt::get(ResType, Layout.getSize().getQuantity(), IsSigned); |
| 982 | + |
| 983 | + Res = IsSigned |
| 984 | + ? Builder.CreateBinaryIntrinsic( |
| 985 | + llvm::Intrinsic::smax, OffsetAndFAMSize, SizeofStruct) |
| 986 | + : Builder.CreateBinaryIntrinsic( |
| 987 | + llvm::Intrinsic::umax, OffsetAndFAMSize, SizeofStruct); |
| 988 | + } else if (const auto *ME = dyn_cast<MemberExpr>(Base)) { |
| 989 | + // Pointing to a place before the FAM. Add the difference to the FAM's |
| 990 | + // size. |
| 991 | + if (const ValueDecl *MD = ME->getMemberDecl(); MD != FAMDecl) { |
| 992 | + CharUnits Offset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(MD)); |
| 993 | + CharUnits FAMOffset = |
| 994 | + Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(FAMDecl)); |
| 995 | + |
| 996 | + Res = Builder.CreateAdd( |
| 997 | + Res, ConstantInt::get(ResType, FAMOffset.getQuantity() - |
| 998 | + Offset.getQuantity())); |
| 999 | + } |
| 1000 | + } |
907 | 1001 |
|
908 |
| - return Mul; |
| 1002 | + // A negative 'FAMSize' means that the index was greater than the count, |
| 1003 | + // or an improperly set count field. Return -1 (for types 0 and 1) or 0 |
| 1004 | + // (for types 2 and 3). |
| 1005 | + return Builder.CreateSelect( |
| 1006 | + Builder.CreateIsNeg(FAMSize), |
| 1007 | + getDefaultBuiltinObjectSizeResult(Type, ResType), Res); |
909 | 1008 | }
|
910 | 1009 | }
|
911 | 1010 |
|
912 |
| - // LLVM can't handle Type=3 appropriately, and __builtin_object_size shouldn't |
913 |
| - // evaluate E for side-effects. In either case, we shouldn't lower to |
914 |
| - // @llvm.objectsize. |
915 |
| - if (Type == 3 || (!EmittedE && E->HasSideEffects(getContext()))) |
916 |
| - return getDefaultBuiltinObjectSizeResult(Type, ResType); |
917 |
| - |
918 | 1011 | Value *Ptr = EmittedE ? EmittedE : EmitScalarExpr(E);
|
919 | 1012 | assert(Ptr->getType()->isPointerTy() &&
|
920 | 1013 | "Non-pointer passed to __builtin_object_size?");
|
|
0 commit comments