[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Jan 8 16:12:20 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Bill Wendling (bwendling)
<details>
<summary>Changes</summary>
Refactoring of how __builtin_dynamic_object_size() is calculated for flexible array members (in preparation for adding support for the 'counted_by' attribute on pointers in structs).
The only functionality change is that we use the already emitted Expr code to build our calculations off of rather than re-emitting the Expr. That allows the 'StructFieldAccess' visitor to sift through all casts and ArraySubscriptExprs to find the first MemberExpr. We build our GEPs and calculate offsets based off of relative distances from that MemberExpr.
The testcase passes execution tests.
There are four categories to support:
struct p;
struct s {
/* ... */
int count;
struct p *array[] __attribute__((counted_by(count)));
};
1) Object size of full flexible array member's size 'ptr->array':
size_t count = (size_t) ptr->count;
size_t flexible_array_member_base_size = sizeof (*ptr->array);
size_t flexible_array_member_size =
count * flexible_array_member_base_size;
return flexible_array_member_size;
2) Object size from partial flexible array member '&ptr->array[idx]':
size_t count = (size_t) ptr->count;
size_t index = (size_t) idx;
size_t flexible_array_member_base_size = sizeof (*ptr->array);
size_t flexible_array_member_size =
count * flexible_array_member_base_size;
size_t index_size = index * flexible_array_member_base_size;
return flexible_array_member_size - index_size;
3) Object size from '&ptr->field':
size_t count = (size_t) ptr->count;
size_t sizeof_struct = sizeof (struct s);
size_t flexible_array_member_base_size = sizeof (*ptr->array);
size_t flexible_array_member_size =
count * flexible_array_member_base_size;
size_t field_offset = offsetof (struct s, field);
size_t offset_diff = sizeof_struct - field_offset;
return flexible_array_member_size + offset_diff;
4) Object size from '&ptr->field[idx]':
size_t count = (size_t) ptr->count;
size_t index = (size_t) idx;
size_t sizeof_struct = sizeof (struct s);
size_t field_base_size = sizeof (*ptr->field);
size_t flexible_array_member_base_size = sizeof (*ptr->array);
size_t flexible_array_member_size =
count * flexible_array_member_base_size;
size_t field_offset =
offsetof (struct s, field) + index * field_base_size;
size_t offset_diff = sizeof_struct - field_offset;
return offset_diff + flexible_array_member_size;
---
Patch is 127.44 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/122198.diff
3 Files Affected:
- (modified) clang/lib/CodeGen/CGBuiltin.cpp (+290-197)
- (modified) clang/lib/CodeGen/CodeGenFunction.h (+5-13)
- (modified) clang/test/CodeGen/attr-counted-by.c (+514-316)
``````````diff
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index dcea32969fb990..61450bcb5f9af8 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -29,6 +29,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/OSLog.h"
#include "clang/AST/OperationKinds.h"
+#include "clang/AST/StmtVisitor.h"
#include "clang/AST/Type.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
@@ -1060,33 +1061,82 @@ CodeGenFunction::evaluateOrEmitBuiltinObjectSize(const Expr *E, unsigned Type,
return ConstantInt::get(ResType, ObjectSize, /*isSigned=*/true);
}
-const FieldDecl *CodeGenFunction::FindFlexibleArrayMemberFieldAndOffset(
- ASTContext &Ctx, const RecordDecl *RD, const FieldDecl *FAMDecl,
- uint64_t &Offset) {
+namespace {
+
+/// StructFieldAccess is a simple visitor class to grab the first MemberExpr
+/// from an Expr. It records any ArraySubscriptExpr we meet along the way.
+struct StructFieldAccess
+ : public ConstStmtVisitor<StructFieldAccess, const MemberExpr *> {
+ const ArraySubscriptExpr *ASE = nullptr;
+
+ const MemberExpr *VisitMemberExpr(const MemberExpr *E) { return E; }
+
+ const MemberExpr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+ ASE = E;
+ return Visit(E->getBase());
+ }
+ const MemberExpr *VisitCastExpr(const CastExpr *E) {
+ return Visit(E->getSubExpr());
+ }
+ const MemberExpr *VisitParenExpr(const ParenExpr *E) {
+ return Visit(E->getSubExpr());
+ }
+ const MemberExpr *VisitUnaryAddrOf(const clang::UnaryOperator *E) {
+ return Visit(E->getSubExpr());
+ }
+ const MemberExpr *VisitUnaryDeref(const clang::UnaryOperator *E) {
+ return Visit(E->getSubExpr());
+ }
+};
+
+} // end anonymous namespace
+
+/// Find a struct's flexible array member. It may be embedded inside multiple
+/// sub-structs, but must still be the last field.
+static const FieldDecl *FindFlexibleArrayMemberField(CodeGenFunction &CGF,
+ ASTContext &Ctx,
+ const RecordDecl *RD) {
const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
- getLangOpts().getStrictFlexArraysLevel();
- uint32_t FieldNo = 0;
+ CGF.getLangOpts().getStrictFlexArraysLevel();
if (RD->isImplicit())
return nullptr;
for (const FieldDecl *FD : RD->fields()) {
- if ((!FAMDecl || FD == FAMDecl) &&
- Decl::isFlexibleArrayMemberLike(
+ if (Decl::isFlexibleArrayMemberLike(
Ctx, FD, FD->getType(), StrictFlexArraysLevel,
- /*IgnoreTemplateOrMacroSubstitution=*/true)) {
- const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
- Offset += Layout.getFieldOffset(FieldNo);
+ /*IgnoreTemplateOrMacroSubstitution=*/true))
return FD;
+
+ if (auto RT = FD->getType()->getAs<RecordType>())
+ if (const FieldDecl *FD =
+ FindFlexibleArrayMemberField(CGF, Ctx, RT->getAsRecordDecl()))
+ return FD;
+ }
+
+ return nullptr;
+}
+
+/// Calculate the offset of a struct field. It may be embedded inside multiple
+/// sub-structs.
+static bool GetFieldOffset(ASTContext &Ctx, const RecordDecl *RD,
+ const FieldDecl *FD, int64_t &Offset) {
+ if (RD->isImplicit())
+ return false;
+
+ const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
+ uint32_t FieldNo = 0;
+
+ for (const FieldDecl *Field : RD->fields()) {
+ if (Field == FD) {
+ Offset += Layout.getFieldOffset(FieldNo);
+ return true;
}
- QualType Ty = FD->getType();
- if (Ty->isRecordType()) {
- if (const FieldDecl *Field = FindFlexibleArrayMemberFieldAndOffset(
- Ctx, Ty->getAsRecordDecl(), FAMDecl, Offset)) {
- const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
+ if (auto RT = Field->getType()->getAs<RecordType>()) {
+ if (GetFieldOffset(Ctx, RT->getAsRecordDecl(), FD, Offset)) {
Offset += Layout.getFieldOffset(FieldNo);
- return Field;
+ return true;
}
}
@@ -1094,204 +1144,248 @@ const FieldDecl *CodeGenFunction::FindFlexibleArrayMemberFieldAndOffset(
++FieldNo;
}
- return nullptr;
+ return false;
}
-static unsigned CountCountedByAttrs(const RecordDecl *RD) {
- unsigned Num = 0;
+llvm::Value *
+CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE,
+ unsigned Type,
+ llvm::IntegerType *ResType) {
+ ASTContext &Ctx = getContext();
- for (const FieldDecl *FD : RD->fields()) {
- if (FD->getType()->isCountAttributedType())
- return ++Num;
+ // Note: If the whole struct is specificed in the __bdos (i.e. Visitor
+ // returns a DeclRefExpr). The calculation of the whole size of the structure
+ // with a flexible array member can be done in two ways:
+ //
+ // 1) sizeof(struct S) + count * sizeof(typeof(fam))
+ // 2) offsetof(struct S, fam) + count * sizeof(typeof(fam))
+ //
+ // The first will add additional padding after the end of the array
+ // allocation while the second method is more precise, but not quite expected
+ // from programmers. See
+ // https://lore.kernel.org/lkml/ZvV6X5FPBBW7CO1f@archlinux/ for a discussion
+ // of the topic.
+ //
+ // GCC isn't (currently) able to calculate __bdos on a pointer to the whole
+ // structure. Therefore, because of the above issue, we choose to match what
+ // GCC does for consistency's sake.
- QualType Ty = FD->getType();
- if (Ty->isRecordType())
- Num += CountCountedByAttrs(Ty->getAsRecordDecl());
- }
+ StructFieldAccess Visitor;
+ const MemberExpr *ME = Visitor.Visit(E);
+ if (!ME)
+ return nullptr;
- return Num;
-}
+ const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());
+ if (!FD)
+ return nullptr;
-llvm::Value *
-CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
- llvm::IntegerType *ResType) {
- // 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:
+ const RecordDecl *RD = FD->getDeclContext()->getOuterLexicalRecordContext();
+ const FieldDecl *FlexibleArrayMemberFD = nullptr;
+
+ if (Decl::isFlexibleArrayMemberLike(
+ Ctx, FD, FD->getType(), getLangOpts().getStrictFlexArraysLevel(),
+ /*IgnoreTemplateOrMacroSubstitution=*/true))
+ FlexibleArrayMemberFD = FD;
+ else
+ FlexibleArrayMemberFD = FindFlexibleArrayMemberField(*this, Ctx, RD);
+
+ if (!FlexibleArrayMemberFD ||
+ !FlexibleArrayMemberFD->getType()->isCountAttributedType())
+ return nullptr;
+
+ const FieldDecl *CountFD = FlexibleArrayMemberFD->findCountedByField();
+ if (!CountFD)
+ // Can't find the field referenced by the "counted_by" attribute.
+ return nullptr;
+
+ const Expr *Idx = nullptr;
+ if (Visitor.ASE) {
+ Idx = Visitor.ASE->getIdx();
+
+ if (Idx->HasSideEffects(Ctx))
+ // We can't have side-effects.
+ return getDefaultBuiltinObjectSizeResult(Type, ResType);
+
+ if (const auto *IL = dyn_cast<IntegerLiteral>(Idx)) {
+ int64_t Val = IL->getValue().getSExtValue();
+ if (Val < 0)
+ return getDefaultBuiltinObjectSizeResult(Type, ResType);
+
+ // The index is 0, so we don't need to take it into account.
+ if (Val == 0)
+ Idx = nullptr;
+ }
+ }
+
+ // Calculate the flexible array member's object size using these formulae
+ // (note: if the calculation is negative, we return 0.):
//
- // struct s {
- // unsigned long flags;
- // int count;
- // int array[] __attribute__((counted_by(count)));
- // }
+ // struct p;
+ // struct s {
+ // /* ... */
+ // int count;
+ // struct p *array[] __attribute__((counted_by(count)));
+ // };
//
- // 1) bdos of the flexible array itself:
+ // 1) 'ptr->array':
//
- // __builtin_dynamic_object_size(p->array, 1) ==
- // p->count * sizeof(*p->array)
+ // size_t count = (size_t) ptr->count;
//
- // 2) bdos of a pointer into the flexible array:
+ // size_t flexible_array_member_base_size = sizeof (*ptr->array);
+ // size_t flexible_array_member_size =
+ // count * flexible_array_member_base_size;
//
- // __builtin_dynamic_object_size(&p->array[42], 1) ==
- // (p->count - 42) * sizeof(*p->array)
+ // return flexible_array_member_size;
//
- // 2) bdos of the whole struct, including the flexible array:
+ // 2) '&ptr->array[idx]':
//
- // __builtin_dynamic_object_size(p, 1) ==
- // max(sizeof(struct s),
- // offsetof(struct s, array) + p->count * sizeof(*p->array))
+ // size_t count = (size_t) ptr->count;
+ // size_t index = (size_t) idx;
//
- ASTContext &Ctx = getContext();
- const Expr *Base = E->IgnoreParenImpCasts();
- const Expr *Idx = nullptr;
-
- if (const auto *UO = dyn_cast<UnaryOperator>(Base);
- UO && UO->getOpcode() == UO_AddrOf) {
- Expr *SubExpr = UO->getSubExpr()->IgnoreParenImpCasts();
- if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(SubExpr)) {
- Base = ASE->getBase()->IgnoreParenImpCasts();
- Idx = ASE->getIdx()->IgnoreParenImpCasts();
-
- if (const auto *IL = dyn_cast<IntegerLiteral>(Idx)) {
- int64_t Val = IL->getValue().getSExtValue();
- if (Val < 0)
- return getDefaultBuiltinObjectSizeResult(Type, ResType);
-
- if (Val == 0)
- // The index is 0, so we don't need to take it into account.
- Idx = nullptr;
- }
- } else {
- // Potential pointer to another element in the struct.
- Base = SubExpr;
- }
- }
+ // size_t flexible_array_member_base_size = sizeof (*ptr->array);
+ // size_t flexible_array_member_size =
+ // count * flexible_array_member_base_size;
+ //
+ // size_t index_size = index * flexible_array_member_base_size;
+ //
+ // return flexible_array_member_size - index_size;
+ //
+ // 3) '&ptr->field':
+ //
+ // size_t count = (size_t) ptr->count;
+ // size_t sizeof_struct = sizeof (struct s);
+ //
+ // size_t flexible_array_member_base_size = sizeof (*ptr->array);
+ // size_t flexible_array_member_size =
+ // count * flexible_array_member_base_size;
+ //
+ // size_t field_offset = offsetof (struct s, field);
+ // size_t offset_diff = struct_size - field_offset;
+ //
+ // return flexible_array_member_size + offset_diff;
+ //
+ // 4) '&ptr->field_array[idx]':
+ //
+ // size_t count = (size_t) ptr->count;
+ // size_t index = (size_t) idx;
+ // size_t sizeof_struct = sizeof (struct s);
+ //
+ // size_t flexible_array_member_base_size = sizeof (*ptr->array);
+ // size_t flexible_array_member_size =
+ // count * flexible_array_member_base_size;
+ //
+ // size_t field_base_size = sizeof (*ptr->field_array);
+ // size_t field_offset = offsetof (struct s, field)
+ // field_offset += index * field_base_size;
+ //
+ // size_t offset_diff = sizeof_struct - field_offset;
+ //
+ // return offset_diff + flexible_array_member_size;
- // Get the flexible array member Decl.
- const RecordDecl *OuterRD = nullptr;
- const FieldDecl *FAMDecl = nullptr;
- if (const auto *ME = dyn_cast<MemberExpr>(Base)) {
- // Check if \p Base is referencing the FAM itself.
- const ValueDecl *VD = ME->getMemberDecl();
- OuterRD = VD->getDeclContext()->getOuterLexicalRecordContext();
- FAMDecl = dyn_cast<FieldDecl>(VD);
- if (!FAMDecl)
- return nullptr;
- } else if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) {
- // Check if we're pointing to the whole struct.
- QualType Ty = DRE->getDecl()->getType();
- if (Ty->isPointerType())
- Ty = Ty->getPointeeType();
- OuterRD = Ty->getAsRecordDecl();
-
- // If we have a situation like this:
- //
- // struct union_of_fams {
- // int flags;
- // union {
- // signed char normal_field;
- // struct {
- // int count1;
- // int arr1[] __counted_by(count1);
- // };
- // struct {
- // signed char count2;
- // int arr2[] __counted_by(count2);
- // };
- // };
- // };
- //
- // We don't know which 'count' to use in this scenario:
- //
- // size_t get_size(struct union_of_fams *p) {
- // return __builtin_dynamic_object_size(p, 1);
- // }
- //
- // Instead of calculating a wrong number, we give up.
- if (OuterRD && CountCountedByAttrs(OuterRD) > 1)
- return nullptr;
- }
+ QualType CountTy = CountFD->getType();
+ bool IsSigned = CountTy->isSignedIntegerType();
- if (!OuterRD)
- return nullptr;
+ QualType FlexibleArrayMemberTy = FlexibleArrayMemberFD->getType();
+ QualType FieldTy = FD->getType();
- // We call FindFlexibleArrayMemberAndOffset even if FAMDecl is non-null to
- // get its offset.
- uint64_t Offset = 0;
- FAMDecl =
- FindFlexibleArrayMemberFieldAndOffset(Ctx, OuterRD, FAMDecl, Offset);
- Offset = Ctx.toCharUnitsFromBits(Offset).getQuantity();
+ // Explicit cast because otherwise the CharWidth will promote an i32's into
+ // u64's leading to overflows..
+ int64_t CharWidth = static_cast<int64_t>(CGM.getContext().getCharWidth());
- if (!FAMDecl || !FAMDecl->getType()->isCountAttributedType())
- // No flexible array member found or it doesn't have the "counted_by"
- // attribute.
+ // size_t count = (size_t) ptr->count;
+ Value *Count = EmitLoadOfCountedByField(ME, FlexibleArrayMemberFD, CountFD);
+ if (!Count)
return nullptr;
+ Count = Builder.CreateIntCast(Count, ResType, IsSigned, "count");
- const FieldDecl *CountedByFD = FAMDecl->findCountedByField();
- if (!CountedByFD)
- // Can't find the field referenced by the "counted_by" attribute.
- return nullptr;
-
- if (isa<DeclRefExpr>(Base))
- // The whole struct is specificed in the __bdos. The calculation of the
- // whole size of the structure can be done in two ways:
- //
- // 1) sizeof(struct S) + count * sizeof(typeof(fam))
- // 2) offsetof(struct S, fam) + count * sizeof(typeof(fam))
- //
- // The first will add additional padding after the end of the array,
- // allocation while the second method is more precise, but not quite
- // expected from programmers. See
- // https://lore.kernel.org/lkml/ZvV6X5FPBBW7CO1f@archlinux/ for a
- // discussion of the topic.
- //
- // GCC isn't (currently) able to calculate __bdos on a pointer to the whole
- // structure. Therefore, because of the above issue, we'll choose to match
- // what GCC does for consistency's sake.
- return nullptr;
+ // size_t index = (size_t) ptr->index;
+ Value *Index = nullptr;
+ if (Idx) {
+ bool IdxSigned = Idx->getType()->isSignedIntegerType();
+ Index = EmitAnyExprToTemp(Idx).getScalarVal();
+ Index = Builder.CreateIntCast(Index, ResType, IdxSigned, "index");
+ }
+
+ // size_t sizeof_struct = sizeof (struct s);
+ llvm::StructType *StructTy = getTypes().getCGRecordLayout(RD).getLLVMType();
+ const llvm::DataLayout &Layout = Builder.GetInsertBlock()->getDataLayout();
+ TypeSize Size = Layout.getTypeSizeInBits(StructTy);
+ Value *SizeofStruct =
+ llvm::ConstantInt::get(ResType, Size.getKnownMinValue() / CharWidth);
+
+ // size_t field_offset = offsetof (struct s, field);
+ Value *FieldOffset = nullptr;
+ if (FlexibleArrayMemberFD != FD) {
+ int64_t Offset = 0;
+ GetFieldOffset(Ctx, RD, FD, Offset);
+ FieldOffset = llvm::ConstantInt::get(ResType, Offset / CharWidth, IsSigned);
+ }
+
+ // size_t flexible_array_member_base_size = sizeof (*ptr->array);
+ const ArrayType *ArrayTy = Ctx.getAsArrayType(FlexibleArrayMemberTy);
+ CharUnits BaseSize = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
+ auto *FlexibleArrayMemberBaseSize =
+ llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned);
+
+ // size_t flexible_array_member_size =
+ // count * flexible_array_member_base_size;
+ Value *FlexibleArrayMemberSize =
+ Builder.CreateMul(Count, FlexibleArrayMemberBaseSize,
+ "flexible_array_member_size", !IsSigned, IsSigned);
+
+ auto CheckForNegative = [&](Value *Res) {
+ Value *Cmp = Builder.CreateIsNotNeg(Res);
+ if (Index)
+ Cmp = Builder.CreateAnd(Builder.CreateIsNotNeg(Index), Cmp);
+ return Builder.CreateSelect(Cmp, Res,
+ ConstantInt::get(ResType, 0, IsSigned));
+ };
- // Build a load of the counted_by field.
- bool IsSigned = CountedByFD->getType()->isSignedIntegerType();
- Value *CountedByInst = EmitLoadOfCountedByField(Base, FAMDecl, CountedByFD);
- if (!CountedByInst)
- return getDefaultBuiltinObjectSizeResult(Type, ResType);
+ if (FlexibleArrayMemberFD == FD) {
+ if (Idx) { // Option (2) '&ptr->array[idx]'
+ // size_t index_size = index * flexible_array_member_base_size;
+ Value *IndexSize = Builder.CreateMul(FlexibleArrayMemberBaseSize, Index,
+ "index_size", !IsSigned, IsSigned);
- CountedByInst = Builder.CreateIntCast(CountedByInst, ResType, IsSigned);
+ // return flexible_array_member_size - index_size;
+ return CheckForNegative(Builder.CreateSub(
+ FlexibleArrayMemberSize, IndexSize, "result", !IsSigned, IsSigned));
+ }
+ } else {
+ if (Idx) { // Option (4) '&ptr->field_array[idx]'
+ // size_t field_base_size = sizeof (*ptr->field_array);
+ const ArrayType *ArrayTy = Ctx.getAsArrayType(FieldTy);
+ CharUnits BaseSize = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
+ auto *FieldBaseSize =
+ llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned);
+
+ // field_offset += index * field_base_size;
+ Value *Mul = Builder.CreateMul(Index, FieldBaseSize, "field_offset",
+ !IsSigned, IsSigned);
+ FieldOffset = Builder.CreateAdd(FieldOffset, Mul);
+
+ // size_t offset_diff = flexible_array_member_offset - field_offset;
+ Value *OffsetDiff = Builder.CreateSub(SizeofStruct, FieldOffset,
+ "offset_diff", !IsSigned, IsSigned);
+
+ // return offset_diff + flexible_array_member_size;
+ return CheckForNegative(
+ Builder.CreateAdd(FlexibleArrayMemberSize, OffsetDiff, "result"));
+ } else { // Option (3) '&ptr->field'
+ // size_t offset_diff = flexible_array_member_offset - field_offset;
+ Value *OffsetDiff = Builder.CreateSub(SizeofStruct, FieldOffset,
+ "offset_diff", !IsSigned, IsSigned);
+
+ // return flexible_array_member_size + offset_diff;
+ return CheckForNegative(
+ Builder.CreateAdd(FlexibleArrayMemberSize, OffsetDiff, "result"));
+ }
+ }
- // Build a load of the index and subtract it from the count.
- Value *IdxInst = nullptr;
- if (Idx) {
- if (Idx->HasSideEffects(getContext()))
- // We can't have side-effects.
- return getDefaultBuiltinObjectSizeResult(Type, ResType);
+ // Option (1) 'ptr->array'
- bool IdxSigned = Idx->getType()->isSignedIntegerType();
- IdxInst = EmitAnyExprToTemp(Idx).getScalarVal();
- IdxInst = Builder.CreateIntCast(IdxInst, ResType, IdxSigned);
-
- // We go ahead with the calculation here. If the index turns out to be
- // negative, we'll catch it at the end.
- CountedByInst =
- Builder.CreateSub(CountedByInst, IdxInst, "", !IsSigned, IsSigned);
- }
-
- // Calculate how large the flexible array member is in bytes.
- const ArrayType *ArrayTy = Ctx.getAsArrayType(FAMDecl->getType());
- CharUnits Size = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
- llvm::Constant *ElemSize =
- llvm::ConstantInt::get(ResType, Size.getQuantity(), IsSigned);
- Value *Res =
- Builder.CreateMul(CountedByInst, ElemSize, "", !IsSigned, IsSigned);
- Res = Builder.CreateIntCast(Res, ResType, IsSigned);
-
- // A negative \p IdxInst or \p CountedByInst me...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/122198
More information about the cfe-commits
mailing list