-
Notifications
You must be signed in to change notification settings - Fork 15.7k
[CodeGen] Revamp counted_by calculations #70606
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 15 commits
19dd7db
36b5271
8c6880b
a5fac56
4d2e39c
e70b487
3f98e8e
b503de0
82588c3
dc8f0df
6260945
7a20a34
1e94fec
c9819d7
163de1d
7abab68
cbdfc3b
c15f340
e6f5299
ff321b0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,6 +25,7 @@ | |
| #include "clang/AST/Attr.h" | ||
| #include "clang/AST/Decl.h" | ||
| #include "clang/AST/OSLog.h" | ||
| #include "clang/AST/OperationKinds.h" | ||
| #include "clang/Basic/TargetBuiltins.h" | ||
| #include "clang/Basic/TargetInfo.h" | ||
| #include "clang/Basic/TargetOptions.h" | ||
|
|
@@ -859,53 +860,93 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, | |
| } | ||
|
|
||
| if (IsDynamic) { | ||
| LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = | ||
| getLangOpts().getStrictFlexArraysLevel(); | ||
| // The code generated here calculates the size of a struct with a flexible | ||
| // array member that uses the counted_by attribute. There are two instances | ||
| // we handle: | ||
| // | ||
| // struct s { | ||
| // unsigned long flags; | ||
| // int count; | ||
| // int array[] __attribute__((counted_by(count))); | ||
| // } | ||
| // | ||
| // 1) bdos of the flexible array itself: | ||
| // | ||
| // __builtin_dynamic_object_size(p->array, 1) == | ||
| // p->count * sizeof(*p->array) | ||
| // | ||
| // 2) bdos of a pointer into the flexible array: | ||
| // | ||
| // __builtin_dynamic_object_size(&p->array[42], 1) == | ||
| // (p->count - 42) * sizeof(*p->array) | ||
| // | ||
| // 2) bdos of the whole struct, including the flexible array: | ||
| // | ||
| // __builtin_dynamic_object_size(p, 1) == | ||
| // max(sizeof(struct s), | ||
| // offsetof(struct s, array) + p->count * sizeof(*p->array)) | ||
| // | ||
| const Expr *Base = E->IgnoreParenImpCasts(); | ||
|
|
||
| if (FieldDecl *FD = FindCountedByField(Base, StrictFlexArraysLevel)) { | ||
| const auto *ME = dyn_cast<MemberExpr>(Base); | ||
| llvm::Value *ObjectSize = nullptr; | ||
|
|
||
| if (!ME) { | ||
| const auto *DRE = dyn_cast<DeclRefExpr>(Base); | ||
| ValueDecl *VD = nullptr; | ||
|
|
||
| ObjectSize = ConstantInt::get( | ||
| ResType, | ||
| getContext().getTypeSize(DRE->getType()->getPointeeType()) / 8, | ||
| true); | ||
|
|
||
| if (auto *RD = DRE->getType()->getPointeeType()->getAsRecordDecl()) | ||
| VD = RD->getLastField(); | ||
|
|
||
| Expr *ICE = ImplicitCastExpr::Create( | ||
| getContext(), DRE->getType(), CK_LValueToRValue, | ||
| const_cast<Expr *>(cast<Expr>(DRE)), nullptr, VK_PRValue, | ||
| FPOptionsOverride()); | ||
| ME = MemberExpr::CreateImplicit(getContext(), ICE, true, VD, | ||
| VD->getType(), VK_LValue, OK_Ordinary); | ||
| const Expr *Idx = nullptr; | ||
| if (const auto *UO = dyn_cast<UnaryOperator>(Base); | ||
| UO && UO->getOpcode() == UO_AddrOf) { | ||
| if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(UO->getSubExpr())) { | ||
| Base = ASE->getBase(); | ||
| Idx = ASE->getIdx()->IgnoreParenImpCasts(); | ||
| if (const auto *IL = dyn_cast<IntegerLiteral>(Idx); | ||
| IL && !IL->getValue().getZExtValue()) { | ||
| Idx = nullptr; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // At this point, we know that \p ME is a flexible array member. | ||
| const auto *ArrayTy = getContext().getAsArrayType(ME->getType()); | ||
| unsigned Size = getContext().getTypeSize(ArrayTy->getElementType()); | ||
| if (const ValueDecl *CountedByFD = FindCountedByField(Base)) { | ||
| const RecordDecl *OuterRD = | ||
| CountedByFD->getDeclContext()->getOuterLexicalRecordContext(); | ||
| ASTContext &Ctx = getContext(); | ||
|
|
||
| llvm::Value *CountField = | ||
| EmitAnyExprToTemp(MemberExpr::CreateImplicit( | ||
| getContext(), const_cast<Expr *>(ME->getBase()), | ||
| ME->isArrow(), FD, FD->getType(), VK_LValue, | ||
| OK_Ordinary)) | ||
| .getScalarVal(); | ||
| // Load the counted_by field. | ||
| const Expr *CountedByExpr = BuildCountedByFieldExpr(Base, CountedByFD); | ||
| llvm::Value *CountedByInst = | ||
| EmitAnyExprToTemp(CountedByExpr).getScalarVal(); | ||
|
|
||
| llvm::Value *Mul = Builder.CreateMul( | ||
| CountField, llvm::ConstantInt::get(CountField->getType(), Size / 8)); | ||
| Mul = Builder.CreateZExtOrTrunc(Mul, ResType); | ||
| if (Idx) { | ||
| llvm::Value *IdxInst = EmitAnyExprToTemp(Idx).getScalarVal(); | ||
| IdxInst = Builder.CreateZExtOrTrunc(IdxInst, CountedByInst->getType()); | ||
bwendling marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| CountedByInst = Builder.CreateSub(CountedByInst, IdxInst); | ||
| } | ||
|
|
||
| if (ObjectSize) | ||
| return Builder.CreateAdd(ObjectSize, Mul); | ||
| // Get the size of the flexible array member's base type. | ||
| const ValueDecl *FAM = FindFlexibleArrayMemberField(Ctx, OuterRD); | ||
| const ArrayType *ArrayTy = Ctx.getAsArrayType(FAM->getType()); | ||
|
||
| CharUnits Size = Ctx.getTypeSizeInChars(ArrayTy->getElementType()); | ||
| llvm::Constant *ElemSize = | ||
| llvm::ConstantInt::get(CountedByInst->getType(), Size.getQuantity()); | ||
|
|
||
| llvm::Value *FAMSize = Builder.CreateMul(CountedByInst, ElemSize); | ||
|
||
| llvm::Value *Res = Builder.CreateZExtOrTrunc(FAMSize, ResType); | ||
|
|
||
| if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) { | ||
| // The whole struct is specificed in the __bdos. | ||
| // Get the full size of the struct. | ||
| const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(OuterRD); | ||
| llvm::Value *SizeofStruct = | ||
| ConstantInt::get(ResType, Layout.getSize().getQuantity(), true); | ||
|
|
||
| // Get the offset of the FAM. | ||
| CharUnits Offset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(FAM)); | ||
| llvm::Value *FAMOffset = | ||
| ConstantInt::get(ResType, Offset.getQuantity(), true); | ||
|
|
||
| // max(sizeof(struct s), | ||
| // offsetof(struct s, array) + p->count * sizeof(*p->array)) | ||
| llvm::Value *OffsetAndFAMSize = Builder.CreateAdd(FAMOffset, Res); | ||
| Res = Builder.CreateBinaryIntrinsic(llvm::Intrinsic::smax, | ||
| OffsetAndFAMSize, SizeofStruct); | ||
| } | ||
|
|
||
| return Mul; | ||
| // PULL THE STRING!! | ||
| return Res; | ||
| } | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.