[llvm] [clang-tools-extra] [clang] [CodeGen] Revamp counted_by calculations (PR #70606)
Bill Wendling via cfe-commits
cfe-commits at lists.llvm.org
Wed Nov 8 14:59:51 PST 2023
================
@@ -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());
+ 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());
----------------
bwendling wrote:
At this point, we know that FAM can't be null. The `FindCountedByField` call above can only return non-null if there's a FAM.
https://github.com/llvm/llvm-project/pull/70606
More information about the cfe-commits
mailing list