[clang] [Clang][objectsize] Generate object size calculation for sub-objects (PR #86858)

2024-05-22 Thread Bill Wendling via cfe-commits

bwendling wrote:

I think I addressed your concerns. PTAL.

https://github.com/llvm/llvm-project/pull/86858
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [BoundsSafety] Allow 'counted_by' attribute on pointers in structs in C (PR #90786)

2024-05-17 Thread Bill Wendling via cfe-commits

bwendling wrote:

Thank you. I wrote to the author. I hope he'll be able to come up with a change 
on his end. Or at least an explanation that makes sense :-)

https://github.com/llvm/llvm-project/pull/90786
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [BoundsSafety] Allow 'counted_by' attribute on pointers in structs in C (PR #90786)

2024-05-17 Thread Bill Wendling via cfe-commits

bwendling wrote:

Ah! I see what you mean. I'll bring this up with the developer. (Actually, that 
construct makes me nervous about their code in general...)

https://github.com/llvm/llvm-project/pull/90786
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][objectsize] Generate object size calculation for sub-objects (PR #86858)

2024-05-17 Thread Bill Wendling via cfe-commits

https://github.com/bwendling updated 
https://github.com/llvm/llvm-project/pull/86858

>From 31af119d614ef2108b5404f9c9387ec45aa1bfef Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Thu, 21 Mar 2024 15:07:31 -0700
Subject: [PATCH 1/6] [Clang][objectsize] Generate object size calculation for
 sub-objects

The second argument of __builtin_dynamic_object_size controls whether it
returns the size of the whole object or the closest surrounding object.
For this struct:

  struct s {
int  foo;
char bar[2][40];
int  baz;
int  qux;
  };

  int main(int argc, char **argv) {
struct s f;

  #define report(x) printf(#x ": %zu\n", x)

argc = 1;
report(__builtin_dynamic_object_size(f.bar[argc], 0));
report(__builtin_dynamic_object_size(f.bar[argc], 1));
return 0;
  }

should return:

  __builtin_dynamic_object_size(f.bar[argc], 0): 48
  __builtin_dynamic_object_size(f.bar[argc], 1): 40

determined by the least significant bit of the TYPE.

The LLVM IR isn't sufficient to determine what could be considered a
"sub-object". However, the front-end does have enough information to
determine the size of a sub-object and the offset into that sub-object.

We try therefore to convert the intrinsic into a calculation in the
front-end so that we can avoid the information issue..
---
 clang/lib/CodeGen/CGBuiltin.cpp | 138 +-
 clang/lib/CodeGen/CodeGenFunction.h |   6 +
 clang/test/CodeGen/object-size-sub-object.c | 280 
 3 files changed, 418 insertions(+), 6 deletions(-)
 create mode 100644 clang/test/CodeGen/object-size-sub-object.c

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 2eaceeba61770..be055f34c4492 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -26,6 +26,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/OSLog.h"
 #include "clang/AST/OperationKinds.h"
+#include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/TargetBuiltins.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/TargetOptions.h"
@@ -1052,6 +1053,128 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr 
*E, unsigned Type,
   return Builder.CreateSelect(Cmp, Res, ConstantInt::get(ResType, 0, 
IsSigned));
 }
 
+namespace {
+
+struct ObjectSizeVisitor
+: public ConstStmtVisitor {
+  const Expr *Visit(const Expr *E) {
+return ConstStmtVisitor::Visit(E);
+  }
+
+  const Expr *VisitStmt(const Stmt *S) { return nullptr; }
+
+  const Expr *VisitDeclRefExpr(const DeclRefExpr *E) { return E; }
+  const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
+  const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { return E; 
}
+
+  const Expr *VisitCastExpr(const CastExpr *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitParenExpr(const ParenExpr *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryAddrOf(const clang::UnaryOperator *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryDeref(const clang::UnaryOperator *E) {
+return Visit(E->getSubExpr());
+  }
+};
+
+} // end anonymous namespace
+
+/// tryToCalculateSubObjectSize - It may be possible to calculate the
+/// sub-object size of an array and skip the generation of the llvm.objectsize
+/// intrinsic. This avoids the complication in conveying the sub-object's
+/// information to the backend. This calculation works for an N-dimentional
+/// array.
+///
+/// Note that this function supports only Row-Major arrays. The generalized
+/// calculation of the offset of an element in Row-Major form:
+///
+/// .-  -.
+///   d |d   |
+///  ---|  - |
+/// offset = \  |   | |  |
+///  /  |   | |  N_j |  m_i
+///  ---|   | |  |
+/// i = 1   | j = i + 1  |
+/// `-  -'
+///
+/// where d is the number of dimensions; m_i is the index of an element in
+/// dimension i; and N_i is the size of dimention i.
+///
+/// Examples:
+/// 2D: offset = m_2 + (N_2 * m_1)
+/// 3D: offset = m_3 + (N_3 * m_2) + (N_3 * N_2 * m_1)
+llvm::Value *
+CodeGenFunction::tryToCalculateSubObjectSize(const Expr *E, unsigned Type,
+ llvm::IntegerType *ResType) {
+  if ((Type & 0x01) != 1)
+// Only support sub-object calculation.
+return nullptr;
+
+  const Expr *ObjectBase = ObjectSizeVisitor().Visit(E);
+  if (!ObjectBase)
+return nullptr;
+
+  // Collect the sizes and indices from the array.
+  ASTContext  = getContext();
+  SmallVector, 4> Dims;
+  while (const auto *ASE = dyn_cast(ObjectBase)) {
+const Expr *Base = ASE;
+const Expr *Idx = ASE->getIdx();
+
+if (Idx->HasSideEffects(Ctx))
+  return nullptr;
+
+uint64_t BaseSize = Ctx.getTypeSizeInChars(Base->getType()).getQuantity();
+Value *IdxSize = EmitScalarExpr(Idx);
+
+

[clang] [Clang][objectsize] Generate object size calculation for sub-objects (PR #86858)

2024-05-17 Thread Bill Wendling via cfe-commits


@@ -1052,6 +1053,165 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr 
*E, unsigned Type,
   return Builder.CreateSelect(Cmp, Res, ConstantInt::get(ResType, 0, 
IsSigned));
 }
 
+namespace {
+
+class ObjectSizeVisitor
+: public ConstStmtVisitor {
+  bool SkipASE;
+
+public:
+  ObjectSizeVisitor(bool SkipASE = false) : SkipASE(SkipASE) {}
+
+  const Expr *Visit(const Expr *E) {
+return ConstStmtVisitor::Visit(E);
+  }
+
+  const Expr *VisitStmt(const Stmt *S) { return nullptr; }
+
+  const Expr *VisitDeclRefExpr(const DeclRefExpr *E) { return E; }
+  const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
+  const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+return SkipASE ? Visit(E->getBase()) : E;
+  }
+
+  const Expr *VisitCastExpr(const CastExpr *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitParenExpr(const ParenExpr *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryAddrOf(const clang::UnaryOperator *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryDeref(const clang::UnaryOperator *E) {
+return Visit(E->getSubExpr());

bwendling wrote:

It's a bit aggressive, but I think it's okay. We're interested in only two 
situations: a __bdos on an array index, and finding the base expression to test 
if it's a flexible array member. However, it does return `0` for this:

```c
struct foo {
int ***f;
};

extern struct foo *x;

__builtin_dynamic_object_size(*(x->f[37]), 1)
```

I'm not sure if that's correct. I'll make it a bit less aggressive.

https://github.com/llvm/llvm-project/pull/86858
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][objectsize] Generate object size calculation for sub-objects (PR #86858)

2024-05-17 Thread Bill Wendling via cfe-commits


@@ -1052,6 +1053,165 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr 
*E, unsigned Type,
   return Builder.CreateSelect(Cmp, Res, ConstantInt::get(ResType, 0, 
IsSigned));
 }
 
+namespace {
+
+class ObjectSizeVisitor
+: public ConstStmtVisitor {
+  bool SkipASE;
+
+public:
+  ObjectSizeVisitor(bool SkipASE = false) : SkipASE(SkipASE) {}
+
+  const Expr *Visit(const Expr *E) {
+return ConstStmtVisitor::Visit(E);
+  }
+
+  const Expr *VisitStmt(const Stmt *S) { return nullptr; }
+
+  const Expr *VisitDeclRefExpr(const DeclRefExpr *E) { return E; }
+  const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
+  const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+return SkipASE ? Visit(E->getBase()) : E;
+  }
+
+  const Expr *VisitCastExpr(const CastExpr *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitParenExpr(const ParenExpr *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryAddrOf(const clang::UnaryOperator *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryDeref(const clang::UnaryOperator *E) {
+return Visit(E->getSubExpr());
+  }
+};
+
+} // end anonymous namespace
+
+/// getLastDecl - Return the last FieldDecl in the struct.
+static const FieldDecl *getLastDecl(const RecordDecl *RD) {
+  const Decl *LastDecl = nullptr;
+  for (const Decl *D : RD->decls())
+if (isa(D) || isa(D))
+  LastDecl = D;
+
+  if (const auto *LastRD = dyn_cast(LastDecl)) {
+LastDecl = getLastDecl(LastRD);
+  } else if (const auto *LastFD = dyn_cast(LastDecl)) {
+QualType Ty = LastFD->getType();
+if (Ty->isPointerType())
+  Ty = Ty->getPointeeType();
+
+if (const RecordDecl *Rec = Ty->getAsRecordDecl())
+  // The last FieldDecl is a structure. Look into that struct to find its
+  // last FieldDecl.
+  LastDecl = getLastDecl(Rec);
+  }
+
+  return dyn_cast_if_present(LastDecl);
+}
+
+/// tryToCalculateSubObjectSize - It may be possible to calculate the
+/// sub-object size of an array and skip the generation of the llvm.objectsize
+/// intrinsic. This avoids the complication in conveying the sub-object's
+/// information to the backend. This calculation works for an N-dimentional
+/// array.
+llvm::Value *
+CodeGenFunction::tryToCalculateSubObjectSize(const Expr *E, unsigned Type,
+ llvm::IntegerType *ResType) {
+  if ((Type & 0x01) != 1)
+// Only support sub-object calculation.
+return nullptr;
+
+  const Expr *ObjectRef = ObjectSizeVisitor().Visit(E);
+  if (!ObjectRef)
+return nullptr;
+
+  QualType ObjectRefType = ObjectRef->getType();
+  if (ObjectRefType->isPointerType())
+ObjectRefType = ObjectRefType->getPointeeType();
+
+  // Collect the base and index from the array.
+  QualType ObjectBaseRefTy;
+  const Expr *ArrayIdx = nullptr;
+
+  if (const auto *ASE = dyn_cast(ObjectRef)) {
+ArrayIdx = ASE->getIdx()->IgnoreParenImpCasts();
+
+const Expr *ArrayRefBase = ASE->getBase()->IgnoreParenImpCasts();
+if (isa(ArrayRefBase)) {
+  ObjectBaseRefTy = ArrayRefBase->getType();
+  if (ObjectBaseRefTy->isPointerType())
+ObjectBaseRefTy = ObjectBaseRefTy->getPointeeType();
+}
+  }
+
+  ASTContext  = getContext();
+  if (!ArrayIdx || ArrayIdx->HasSideEffects(Ctx))
+return nullptr;
+
+  // Check to see if the Decl is a flexible array member. Processing of the
+  // 'counted_by' attribute is done by now. So we don't have any information on
+  // its size, so return MAX_INT.
+  //
+  // Rerun the visitor to find the base expr: MemberExpr or DeclRefExpr.
+  ObjectRef = ObjectSizeVisitor(true).Visit(ObjectRef);
+  if (!ObjectRef)
+return nullptr;
+
+  if (const auto *ME = dyn_cast(ObjectRef)) {
+if (const auto *FD = dyn_cast(ME->getMemberDecl())) {
+  const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
+  getLangOpts().getStrictFlexArraysLevel();
+  const RecordDecl *OuterRD =
+  FD->getParent()->getOuterLexicalRecordContext();
+  const FieldDecl *LastFD = getLastDecl(OuterRD);
+
+  if (LastFD == FD && Decl::isFlexibleArrayMemberLike(
+  Ctx, FD, FD->getType(), StrictFlexArraysLevel,
+  /*IgnoreTemplateOrMacroSubstitution=*/true))
+return ConstantInt::get(ResType, -1, /*isSigned=*/true);
+}
+  }
+
+  if (ObjectBaseRefTy.isNull()) {
+ObjectBaseRefTy = ObjectRef->getType();
+if (ObjectBaseRefTy->isPointerType())
+  ObjectBaseRefTy = ObjectBaseRefTy->getPointeeType();
+  }
+
+  // Generate the calculation:
+  //
+  // S Object[n_1][n_2]...[n_m]; /* M-dimentional array */
+  //
+  // ObjectRef = Object[n_1]...[n_x]; /* 0 < x < m */
+  // ObjectBaseRef = Object[n_1]...[n_{x-1}];
+  //
+  // ArrayRefSize = sizeof( typeof( ObjectRef ) );
+  // ArrayRefBaseSize = sizeof( typeof( ObjectBaseRef ) );
+  //
+  // Size = ArrayRefSize - 

[clang] [Clang][objectsize] Generate object size calculation for sub-objects (PR #86858)

2024-05-17 Thread Bill Wendling via cfe-commits


@@ -1052,6 +1053,165 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr 
*E, unsigned Type,
   return Builder.CreateSelect(Cmp, Res, ConstantInt::get(ResType, 0, 
IsSigned));
 }
 
+namespace {
+
+class ObjectSizeVisitor
+: public ConstStmtVisitor {
+  bool SkipASE;
+
+public:
+  ObjectSizeVisitor(bool SkipASE = false) : SkipASE(SkipASE) {}
+
+  const Expr *Visit(const Expr *E) {
+return ConstStmtVisitor::Visit(E);
+  }
+
+  const Expr *VisitStmt(const Stmt *S) { return nullptr; }
+
+  const Expr *VisitDeclRefExpr(const DeclRefExpr *E) { return E; }
+  const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
+  const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+return SkipASE ? Visit(E->getBase()) : E;
+  }
+
+  const Expr *VisitCastExpr(const CastExpr *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitParenExpr(const ParenExpr *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryAddrOf(const clang::UnaryOperator *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryDeref(const clang::UnaryOperator *E) {
+return Visit(E->getSubExpr());
+  }
+};
+
+} // end anonymous namespace
+
+/// getLastDecl - Return the last FieldDecl in the struct.
+static const FieldDecl *getLastDecl(const RecordDecl *RD) {
+  const Decl *LastDecl = nullptr;
+  for (const Decl *D : RD->decls())
+if (isa(D) || isa(D))

bwendling wrote:

This was due to a misunderstanding by me, that you cleared up in a previous PR. 
I'll remove it.

https://github.com/llvm/llvm-project/pull/86858
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][objectsize] Generate object size calculation for sub-objects (PR #86858)

2024-05-17 Thread Bill Wendling via cfe-commits

https://github.com/bwendling updated 
https://github.com/llvm/llvm-project/pull/86858

>From 31af119d614ef2108b5404f9c9387ec45aa1bfef Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Thu, 21 Mar 2024 15:07:31 -0700
Subject: [PATCH 1/5] [Clang][objectsize] Generate object size calculation for
 sub-objects

The second argument of __builtin_dynamic_object_size controls whether it
returns the size of the whole object or the closest surrounding object.
For this struct:

  struct s {
int  foo;
char bar[2][40];
int  baz;
int  qux;
  };

  int main(int argc, char **argv) {
struct s f;

  #define report(x) printf(#x ": %zu\n", x)

argc = 1;
report(__builtin_dynamic_object_size(f.bar[argc], 0));
report(__builtin_dynamic_object_size(f.bar[argc], 1));
return 0;
  }

should return:

  __builtin_dynamic_object_size(f.bar[argc], 0): 48
  __builtin_dynamic_object_size(f.bar[argc], 1): 40

determined by the least significant bit of the TYPE.

The LLVM IR isn't sufficient to determine what could be considered a
"sub-object". However, the front-end does have enough information to
determine the size of a sub-object and the offset into that sub-object.

We try therefore to convert the intrinsic into a calculation in the
front-end so that we can avoid the information issue..
---
 clang/lib/CodeGen/CGBuiltin.cpp | 138 +-
 clang/lib/CodeGen/CodeGenFunction.h |   6 +
 clang/test/CodeGen/object-size-sub-object.c | 280 
 3 files changed, 418 insertions(+), 6 deletions(-)
 create mode 100644 clang/test/CodeGen/object-size-sub-object.c

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 2eaceeba61770..be055f34c4492 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -26,6 +26,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/OSLog.h"
 #include "clang/AST/OperationKinds.h"
+#include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/TargetBuiltins.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/TargetOptions.h"
@@ -1052,6 +1053,128 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr 
*E, unsigned Type,
   return Builder.CreateSelect(Cmp, Res, ConstantInt::get(ResType, 0, 
IsSigned));
 }
 
+namespace {
+
+struct ObjectSizeVisitor
+: public ConstStmtVisitor {
+  const Expr *Visit(const Expr *E) {
+return ConstStmtVisitor::Visit(E);
+  }
+
+  const Expr *VisitStmt(const Stmt *S) { return nullptr; }
+
+  const Expr *VisitDeclRefExpr(const DeclRefExpr *E) { return E; }
+  const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
+  const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { return E; 
}
+
+  const Expr *VisitCastExpr(const CastExpr *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitParenExpr(const ParenExpr *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryAddrOf(const clang::UnaryOperator *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryDeref(const clang::UnaryOperator *E) {
+return Visit(E->getSubExpr());
+  }
+};
+
+} // end anonymous namespace
+
+/// tryToCalculateSubObjectSize - It may be possible to calculate the
+/// sub-object size of an array and skip the generation of the llvm.objectsize
+/// intrinsic. This avoids the complication in conveying the sub-object's
+/// information to the backend. This calculation works for an N-dimentional
+/// array.
+///
+/// Note that this function supports only Row-Major arrays. The generalized
+/// calculation of the offset of an element in Row-Major form:
+///
+/// .-  -.
+///   d |d   |
+///  ---|  - |
+/// offset = \  |   | |  |
+///  /  |   | |  N_j |  m_i
+///  ---|   | |  |
+/// i = 1   | j = i + 1  |
+/// `-  -'
+///
+/// where d is the number of dimensions; m_i is the index of an element in
+/// dimension i; and N_i is the size of dimention i.
+///
+/// Examples:
+/// 2D: offset = m_2 + (N_2 * m_1)
+/// 3D: offset = m_3 + (N_3 * m_2) + (N_3 * N_2 * m_1)
+llvm::Value *
+CodeGenFunction::tryToCalculateSubObjectSize(const Expr *E, unsigned Type,
+ llvm::IntegerType *ResType) {
+  if ((Type & 0x01) != 1)
+// Only support sub-object calculation.
+return nullptr;
+
+  const Expr *ObjectBase = ObjectSizeVisitor().Visit(E);
+  if (!ObjectBase)
+return nullptr;
+
+  // Collect the sizes and indices from the array.
+  ASTContext  = getContext();
+  SmallVector, 4> Dims;
+  while (const auto *ASE = dyn_cast(ObjectBase)) {
+const Expr *Base = ASE;
+const Expr *Idx = ASE->getIdx();
+
+if (Idx->HasSideEffects(Ctx))
+  return nullptr;
+
+uint64_t BaseSize = Ctx.getTypeSizeInChars(Base->getType()).getQuantity();
+Value *IdxSize = EmitScalarExpr(Idx);
+
+

[clang] [BoundsSafety] Allow 'counted_by' attribute on pointers in structs in C (PR #90786)

2024-05-17 Thread Bill Wendling via cfe-commits

bwendling wrote:

This seems to have broken the Linux build:

https://github.com/llvm/llvm-project/commit/0ec3b972e58bcbcdc1bebe1696ea37f2931287c3
 breaks the build for Linux, added by 
https://git.kernel.org/linus/781d41fed19caf900c8405064676813dc9921d32:

https://paste.debian.net/plainh/b192bcd1

https://github.com/llvm/llvm-project/pull/90786
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix for merging PR #89456 into llvm 18.X (PR #90118)

2024-05-14 Thread Bill Wendling via cfe-commits

https://github.com/bwendling closed 
https://github.com/llvm/llvm-project/pull/90118
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [BoundsSafety] Allow 'counted_by' attribute on pointers in structs in C (PR #90786)

2024-05-13 Thread Bill Wendling via cfe-commits

bwendling wrote:

> > It's not a lie, because the contents of a pointer don't contribute to the 
> > size of the struct containing that pointer.
> 
> Consider this example. It tries to illustrate why putting `__counted_by()` on 
> a pointer to a structs containing flexible array members doesn't make sense.
> 
> ```c
> struct HasFAM {
> int count;
> char buffer[] __counted_by(count); // This is OK
> };
> 
> struct BufferOfFAMS {
> int count;
> struct HasFAM* fams __counted_by(count); // This is invalid
> };
> 
> struct BufferOfFAMS* setup(void) {
> const int numFams = 2;
> const int famSizes[] = { 8, 16};
> 
> struct BufferOfFAMS *f = (struct BufferOfFAMS *)malloc(
> sizeof(struct BufferOfFAMS) + (sizeof(struct HasFam *) * numFams));
> 
> f->count = numFams;
> 
> size_t famsBufferSize = 0;
> for (int i=0; i < numFams; ++i) {
> famsBufferSize += sizeof(struct HasFAM) + sizeof(char)* famSizes[i];
> }
> f->fams = (struct HasFAM*) malloc(famsBufferSize);
> memset(f->fams, 0, famsBufferSize);
> 
> size_t byteOffset = 0;
> for (int i=0; i < numFams; ++i) {
> struct HasFAM* cur = (struct HasFAM*) (((char*)f->fams) + byteOffset);
> cur->count = famSizes[i];
> byteOffset = sizeof(struct HasFAM) + (sizeof(char) * famSizes[i]);
> }
> return f;
> }
> 
> int main(void) {
> // How would we compute the bounds of f::fams here??
> // `sizeof(struct HasFAM) * f->count` is WRONG. It's too small but this
> // is what writing `__counted_by(count)` on `HasFAM::buffer` means.
> //
> // It's actually
> // `(sizeof(struct HasFAM) * f->count) + (sizeof(char) * (8 + 16))`
> //
> // This means we can't use the `__counted_by()` attribute on
> // `BufferOfFAMS::fams` to compute its bounds. But allowing the bounds
> // to be computed is the whole point of the attribute.
> struct BufferOfFAMS* f = setup();
> 
> // Similary doing any kind of indexing on the pointer 
> // is extremely problematic for exactly the same reason.
> // 
> // The address is completely wrong because the offset is computed using
> // `sizeof(struct HasFAM)` which won't include the array at the end.
> //
> // So `bogus_ptr` points to the first byte of the first `HasFAM::buffer`,
> // instead of the second `struct HasFAM`.
> struct HasFAM* bogus_ptr = >fams[1];
> return 0;
> }
> ```

I agree that it doesn't make sense, but not every struct will have a flexible 
array member, of course. :-)

I guess as long as there's a followup with the support @kees mentioned above 
then I have no issues with this PR also.

https://github.com/llvm/llvm-project/pull/90786
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [BoundsSafety] Allow 'counted_by' attribute on pointers in structs in C (PR #90786)

2024-05-10 Thread Bill Wendling via cfe-commits

bwendling wrote:

@rapidsna @delcypher @apple-fcloutier @kees:

Okay, I think I see what the complication is. Are you trying to prevent the use 
case of someone writing something like:

```c
struct bar;

struct foo {
  size_t count;
  struct bar *ptr __counted_by(count);
};
```

where `ptr` is a pointer to one large space where that the user splits up into 
`count` number of `struct bar` objects?

```c
struct foo *alloc_foo(size_t count) {
  struct foo *p = malloc(sizeof(struct foo));

  p->count;
  p->ptr = malloc(sizeof(struct bar) * count); // struct bar can't be 
incomplete here
  return p;
}
```


https://github.com/llvm/llvm-project/pull/90786
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [BoundsSafety] Allow 'counted_by' attribute on pointers in structs in C (PR #90786)

2024-05-10 Thread Bill Wendling via cfe-commits

bwendling wrote:

@apple-fcloutier:

> think that there's room to allow `__counted_by` on incomplete types so that a 
> TU where it's complete could use it (and we have use cases where that would 
> be handy), but our implementation doesn't support it at this time. This can 
> be added without disruptions at a later time. FWIW, the point of 
> bounds-checking an index is moot at least while the type is incomplete, since 
> it's an error to dereference a pointer to an incomplete type. Aside from 
> indexing, operations that would cast the pointer (such as `memset(x->foo, 0, 
> some_value)`, assuming `memset(void *__sized_by(n), int, size_t n)`) would 
> still have to be illegal when `struct foo` is incomplete because there's no 
> way to know how many bytes we have at x->foo without `sizeof(struct foo)`.

What I'm thinking is something like:

```c
a.c:
struct foo;

struct bar {
  size_t count;
  struct foo *ptr __counted_by(count);
};

struct bar *alloc_bar(size_t num_elems) {
  struct bar *p = malloc(sizeof(bar));

  p->count = num_elems;
  p->ptr = malloc(sizeof(struct foo *) * num_elems);
  return p;
}

/* later on, or in another TU */

struct foo {
  /* fields */
};

void bork(size_t num_elems) {
  struct bar *p = alloc_bar(num_elems);

  for (size_t i = 0; i < num_elems; ++i) {
p->ptr[i] = alloc_foo();
  }

  /* some use of p */
}
}
```

I was incorrect about `void *`. It's valid to cast any pointer to `void *` and 
back to the original type.

> For structs with a flexible array member, the reason is that sizeof(struct 
> bar) is a lie. How would we reconcile, for instance, a count of 1 (implying 
> there's like 4 bytes at x->bar) with a x->bar->a of 10 (implying that 
> x->bar->fam[8] is in bounds)? How do we feel that x->bar[0]->fam[0] aliases 
> with x->bar[1]->a?

It's not a lie, because the contents of a pointer don't contribute to the size 
of the struct containing that pointer.

https://github.com/llvm/llvm-project/pull/90786
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [BoundsSafety] Allow 'counted_by' attribute on pointers in structs in C (PR #90786)

2024-05-09 Thread Bill Wendling via cfe-commits

bwendling wrote:

> Note the attribute is prevented on pointee types where the size isn't known 
> at compile time. In particular pointee types that are:
> 
> * Incomplete (e.g. `void`) and sizeless types
> * Function types (e.g. the pointee of a function pointer)
> * Struct types with a flexible array member

I've been thinking about this restriction. Why is this necessary? My assumption 
was that applying `counted_by` to a pointer causes a bounds check on an index 
into the __pointer__ rather than its underlying type. So something like:

```c
struct foo;
struct bar {
  int a;
  int fam[] __counted_by(a);
};

struct x {
void *p __counted_by(count);   // void * is treated like char *, I 
think.
struct foo *f __counted_by(count); // sizeof(f) is the size of a general 
pointer.
struct bar *b __counted_by(count); // a list of pointers to 'struct bar's 
should be okay.
int count;
};
```

https://github.com/llvm/llvm-project/pull/90786
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][objectsize] Generate object size calculation for sub-objects (PR #86858)

2024-05-06 Thread Bill Wendling via cfe-commits

bwendling wrote:

Ping again.

https://github.com/llvm/llvm-project/pull/86858
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [BoundsSafety] Allow 'counted_by' attribute on pointers in structs in C (PR #90786)

2024-05-03 Thread Bill Wendling via cfe-commits


@@ -335,6 +336,22 @@ Attribute Changes in Clang
 - Clang now warns that the ``exclude_from_explicit_instantiation`` attribute
   is ignored when applied to a local class or a member thereof.
 
+- The ``counted_by`` attribute can now be late parsed in C when

bwendling wrote:

I don't have a strong opinion either. :-) It's fine to keep the blurb in.

https://github.com/llvm/llvm-project/pull/90786
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [BoundsSafety] Allow 'counted_by' attribute on pointers in structs in C (PR #90786)

2024-05-03 Thread Bill Wendling via cfe-commits


@@ -6534,6 +6536,15 @@ def err_counted_by_attr_refer_to_union : Error<
   "'counted_by' argument cannot refer to a union member">;
 def note_flexible_array_counted_by_attr_field : Note<
   "field %0 declared here">;
+def err_counted_by_attr_pointee_unknown_size : Error<
+  "'counted_by' cannot be applied a pointer with pointee with unknown size "
+  "because %0 is %select{"
+"an incomplete type|"  // CountedByInvalidPointeeTypeKind::INCOMPLETE
+"a sizeless type|" // CountedByInvalidPointeeTypeKind::SIZELESS
+"a function type|" // CountedByInvalidPointeeTypeKind::FUNCTION

bwendling wrote:

I think that as long as it's a pointer we're okay, at least w.r.t. the 
`counted_by` attribute. We know the size of pointers at least. :-)

https://github.com/llvm/llvm-project/pull/90786
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [BoundsSafety] Allow 'counted_by' attribute on pointers in structs in C (PR #90786)

2024-05-03 Thread Bill Wendling via cfe-commits


@@ -631,6 +631,18 @@ bool Type::isStructureType() const {
   return false;
 }
 
+bool Type::isStructureTypeWithFlexibleArrayMember() const {
+  const auto *RT = getAs();
+  if (!RT)
+return false;
+  const auto *Decl = RT->getDecl();
+  if (!Decl->isStruct())
+return false;
+  if (!Decl->hasFlexibleArrayMember())
+return false;
+  return true;

bwendling wrote:

Maybe? The `isFlexibleArrayMemberLike` methods are more in depth analysis of 
the struct and checks against the `-fstrict-flex-arrays=` flag, so it's a more 
expensive call. But if the `hasFlexibleArrayMember` is always set "correctly," 
then it's probably sufficient.

https://github.com/llvm/llvm-project/pull/90786
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [BoundsSafety] Allow 'counted_by' attribute on pointers in structs in C (PR #90786)

2024-05-03 Thread Bill Wendling via cfe-commits


@@ -6534,6 +6536,15 @@ def err_counted_by_attr_refer_to_union : Error<
   "'counted_by' argument cannot refer to a union member">;
 def note_flexible_array_counted_by_attr_field : Note<
   "field %0 declared here">;
+def err_counted_by_attr_pointee_unknown_size : Error<
+  "'counted_by' cannot be applied a pointer with pointee with unknown size "
+  "because %0 is %select{"
+"an incomplete type|"  // CountedByInvalidPointeeTypeKind::INCOMPLETE
+"a sizeless type|" // CountedByInvalidPointeeTypeKind::SIZELESS
+"a function type|" // CountedByInvalidPointeeTypeKind::FUNCTION

bwendling wrote:

> A "function type" and "function pointer type" are different.

Ah! my mistake. :-)

https://github.com/llvm/llvm-project/pull/90786
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [BoundsSafety] Allow 'counted_by' attribute on pointers in structs in C (PR #90786)

2024-05-03 Thread Bill Wendling via cfe-commits


@@ -335,6 +336,22 @@ Attribute Changes in Clang
 - Clang now warns that the ``exclude_from_explicit_instantiation`` attribute
   is ignored when applied to a local class or a member thereof.
 
+- The ``counted_by`` attribute can now be late parsed in C when

bwendling wrote:

If it doesn't have a use yet, maybe you don't need to add it in the release 
notes?

https://github.com/llvm/llvm-project/pull/90786
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [BoundsSafety] Allow 'counted_by' attribute on pointers in structs in C (PR #90786)

2024-05-03 Thread Bill Wendling via cfe-commits

https://github.com/bwendling edited 
https://github.com/llvm/llvm-project/pull/90786
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [BoundsSafety] Allow 'counted_by' attribute on pointers in structs in C (PR #90786)

2024-05-03 Thread Bill Wendling via cfe-commits


@@ -3282,6 +3282,19 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes 
,
   }
 }
 
+void Parser::DistributeCLateParsedAttrs(Decl *Dcl,
+LateParsedAttrList *LateAttrs) {
+  assert(Dcl);

bwendling wrote:

Could you add a string to the assert?

https://github.com/llvm/llvm-project/pull/90786
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [BoundsSafety] Allow 'counted_by' attribute on pointers in structs in C (PR #90786)

2024-05-03 Thread Bill Wendling via cfe-commits


@@ -8588,31 +8588,71 @@ static const RecordDecl 
*GetEnclosingNamedOrTopAnonRecord(const FieldDecl *FD) {
   return RD;
 }
 
-static bool
-CheckCountExpr(Sema , FieldDecl *FD, Expr *E,
-   llvm::SmallVectorImpl ) {
+enum class CountedByInvalidPointeeTypeKind {
+  INCOMPLETE,
+  SIZELESS,
+  FUNCTION,
+  FLEXIBLE_ARRAY_MEMBER,
+  VALID,
+};
+
+static bool CheckCountedByAttrOnField(
+Sema , FieldDecl *FD, Expr *E,
+llvm::SmallVectorImpl ) {
+  // Check the context the attribute is used in
+
   if (FD->getParent()->isUnion()) {
 S.Diag(FD->getBeginLoc(), diag::err_counted_by_attr_in_union)
 << FD->getSourceRange();
 return true;
   }
 
-  if (!E->getType()->isIntegerType() || E->getType()->isBooleanType()) {
-S.Diag(E->getBeginLoc(), diag::err_counted_by_attr_argument_not_integer)
-<< E->getSourceRange();
+  const auto FieldTy = FD->getType();
+  if (!FieldTy->isArrayType() && !FieldTy->isPointerType()) {
+S.Diag(FD->getBeginLoc(),
+   diag::err_counted_by_attr_not_on_ptr_or_flexible_array_member)
+<< FD->getLocation();
 return true;
   }
 
   LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
   LangOptions::StrictFlexArraysLevelKind::IncompleteOnly;
-
-  if (!Decl::isFlexibleArrayMemberLike(S.getASTContext(), FD, FD->getType(),
+  if (FieldTy->isArrayType() &&
+  !Decl::isFlexibleArrayMemberLike(S.getASTContext(), FD, FieldTy,
StrictFlexArraysLevel, true)) {
-// The "counted_by" attribute must be on a flexible array member.
-SourceRange SR = FD->getLocation();
-S.Diag(SR.getBegin(),
-   diag::err_counted_by_attr_not_on_flexible_array_member)
-<< SR;
+S.Diag(FD->getBeginLoc(),
+   diag::err_counted_by_attr_on_array_not_flexible_array_member)
+<< FD->getLocation();
+return true;
+  }
+
+  if (FieldTy->isPointerType()) {

bwendling wrote:

> @isanbard Is the above code pattern something you actually want to support? 
> In -fbounds-safety we disallow it because it means computing the bounds of 
> Arr is not constant time because the size of Has_VLA is not a compile time 
> constant. To compute the bounds of Arr at runtime it would require walking 
> every Has_VLA object in Arr to get its count field. That seems expensive and 
> is also at risk of running into a race condition (i.e. the size of a VLA 
> changes while the bounds are being computed).

Is it even valid C? I *suppose* it could be valid if `struct Has_VLA` wasn't 
allocated with extra bytes, i.e. `count` is 0 and `buffer` has no size.

But that's a horrible use case and I think it's fine to flag it as an error.

https://github.com/llvm/llvm-project/pull/90786
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [BoundsSafety] Allow 'counted_by' attribute on pointers in structs in C (PR #90786)

2024-05-03 Thread Bill Wendling via cfe-commits


@@ -631,6 +631,18 @@ bool Type::isStructureType() const {
   return false;
 }
 
+bool Type::isStructureTypeWithFlexibleArrayMember() const {
+  const auto *RT = getAs();
+  if (!RT)
+return false;
+  const auto *Decl = RT->getDecl();
+  if (!Decl->isStruct())
+return false;
+  if (!Decl->hasFlexibleArrayMember())
+return false;
+  return true;

bwendling wrote:

The last three lines could be simplified as:

```c
return Decl->hasFlexibleArrayMember();
```

https://github.com/llvm/llvm-project/pull/90786
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [BoundsSafety] Allow 'counted_by' attribute on pointers in structs in C (PR #90786)

2024-05-03 Thread Bill Wendling via cfe-commits


@@ -6534,6 +6536,15 @@ def err_counted_by_attr_refer_to_union : Error<
   "'counted_by' argument cannot refer to a union member">;
 def note_flexible_array_counted_by_attr_field : Note<
   "field %0 declared here">;
+def err_counted_by_attr_pointee_unknown_size : Error<
+  "'counted_by' cannot be applied a pointer with pointee with unknown size "
+  "because %0 is %select{"
+"an incomplete type|"  // CountedByInvalidPointeeTypeKind::INCOMPLETE
+"a sizeless type|" // CountedByInvalidPointeeTypeKind::SIZELESS
+"a function type|" // CountedByInvalidPointeeTypeKind::FUNCTION

bwendling wrote:

I'm a bit confused why a function type is excluded. Isn't it just a pointer? 
@kees can correct me, but I think the point of `counted_by` on a pointer is 
that it could be a list of pointers, and we don't want to allow someone to 
access beyond that list:

```c
struct s {
  int count;
  int *ptr __counted_by(count);
};

struct s *alloc(size_t num_elems) {
  struct s *p = malloc(sizeof(struct s));

  p->count = num_elems;
  p->ptr = calloc(sizeof(int), num_elems);
  return p;
}
```

If that's the case, then any pointer should be okay.

https://github.com/llvm/llvm-project/pull/90786
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [BoundsSafety] Allow 'counted_by' attribute on pointers in structs in C (PR #90786)

2024-05-03 Thread Bill Wendling via cfe-commits


@@ -335,6 +336,22 @@ Attribute Changes in Clang
 - Clang now warns that the ``exclude_from_explicit_instantiation`` attribute
   is ignored when applied to a local class or a member thereof.
 
+- The ``counted_by`` attribute can now be late parsed in C when

bwendling wrote:

You should mention that `counted_by` was extended to work with pointers in 
structs first. Otherwise, "last parsing" of the attribute doesn't make a lot of 
sense since a flexible array member is at the end of a struct.

https://github.com/llvm/llvm-project/pull/90786
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)

2024-05-02 Thread Bill Wendling via cfe-commits

bwendling wrote:

The code looks fine to me. But you should wait for @efriedma-quic to chime in 
as he had concerns over the feature.

https://github.com/llvm/llvm-project/pull/86618
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][objectsize] Generate object size calculation for sub-objects (PR #86858)

2024-04-29 Thread Bill Wendling via cfe-commits

bwendling wrote:

Another ping...

https://github.com/llvm/llvm-project/pull/86858
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix for merging PR #89456 into llvm 18.X (PR #90118)

2024-04-25 Thread Bill Wendling via cfe-commits

bwendling wrote:

Does it matter if it's just a cherry-pick?

https://github.com/llvm/llvm-project/pull/90118
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Handle structs with inner structs and no fields (PR #89126)

2024-04-25 Thread Bill Wendling via cfe-commits

bwendling wrote:

@tstellar PR https://github.com/llvm/llvm-project/pull/90118 is the fix here.

https://github.com/llvm/llvm-project/pull/89126
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix for merging PR #89456 into llvm 18.X (PR #90118)

2024-04-25 Thread Bill Wendling via cfe-commits

https://github.com/bwendling created 
https://github.com/llvm/llvm-project/pull/90118

Fix #89126 for the 18.X branch.

>From cb0d1c0b15cea9c6a50a127fed9a6ad49f2c1d8f Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Thu, 25 Apr 2024 13:37:07 -0700
Subject: [PATCH] Fix for merging PR #89456 into llvm 18.X

---
 clang/test/CodeGen/attr-counted-by-pr88931.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/CodeGen/attr-counted-by-pr88931.c 
b/clang/test/CodeGen/attr-counted-by-pr88931.c
index cc3d751c7c6d83..520ebd09973284 100644
--- a/clang/test/CodeGen/attr-counted-by-pr88931.c
+++ b/clang/test/CodeGen/attr-counted-by-pr88931.c
@@ -14,7 +14,7 @@ void init(void * 
__attribute__((pass_dynamic_object_size(0;
 // CHECK-LABEL: define dso_local void @test1(
 // CHECK-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:[[ARRAY:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 4
+// CHECK-NEXT:[[ARRAY:%.*]] = getelementptr inbounds [[STRUCT_BAR:%.*]], 
ptr [[P]], i64 0, i32 1
 // CHECK-NEXT:tail call void @init(ptr noundef nonnull [[ARRAY]], i64 
noundef -1) #[[ATTR2:[0-9]+]]
 // CHECK-NEXT:ret void
 //

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix for merging PR #89456 into llvm 18.X (PR #90118)

2024-04-25 Thread Bill Wendling via cfe-commits

https://github.com/bwendling milestoned 
https://github.com/llvm/llvm-project/pull/90118
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Improve testing for the flexible array member (PR #89462)

2024-04-24 Thread Bill Wendling via cfe-commits

https://github.com/bwendling closed 
https://github.com/llvm/llvm-project/pull/89462
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][objectsize] Generate object size calculation for sub-objects (PR #86858)

2024-04-22 Thread Bill Wendling via cfe-commits

bwendling wrote:

Friendly ping 2: Electric Boogaloo

https://github.com/llvm/llvm-project/pull/86858
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)

2024-04-22 Thread Bill Wendling via cfe-commits


@@ -4077,6 +4077,9 @@ class BinaryOperator : public Expr {
   static unsigned sizeOfTrailingObjects(bool HasFPFeatures) {
 return HasFPFeatures * sizeof(FPOptionsOverride);
   }
+
+  /// Do one of the subexpressions have the wraps attribute?

bwendling wrote:

s/Do/Does/

https://github.com/llvm/llvm-project/pull/86618
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)

2024-04-22 Thread Bill Wendling via cfe-commits


@@ -4249,6 +4270,10 @@ Value *ScalarExprEmitter::EmitFixedPointBinOp(const 
BinOpInfo ) {
 Value *ScalarExprEmitter::EmitSub(const BinOpInfo ) {
   // The LHS is always a pointer if either side is.
   if (!op.LHS->getType()->isPointerTy()) {
+if ((op.Ty->isSignedIntegerOrEnumerationType() ||

bwendling wrote:

Same question here, re-early creation of subtraction.

https://github.com/llvm/llvm-project/pull/86618
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)

2024-04-22 Thread Bill Wendling via cfe-commits


@@ -2831,6 +2840,9 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const 
UnaryOperator *E, LValue LV,
   } else if (type->isIntegerType()) {
 QualType promotedType;
 bool canPerformLossyDemotionCheck = false;
+BinOpInfo Ops = (createBinOpInfoFromIncDec(

bwendling wrote:

You probably don't need parens around the `createBinOpInforFromIncDec` call.

https://github.com/llvm/llvm-project/pull/86618
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)

2024-04-22 Thread Bill Wendling via cfe-commits


@@ -4455,6 +4455,14 @@ void Sema::AddAlignValueAttr(Decl *D, const 
AttributeCommonInfo , Expr *E) {
   D->addAttr(::new (Context) AlignValueAttr(Context, CI, E));
 }
 
+static void handleWrapsAttr(Sema , Decl *D, const ParsedAttr ) {
+  S.AddWrapsAttr(D, AL);
+}
+
+void Sema::AddWrapsAttr(Decl *D, const AttributeCommonInfo ) {

bwendling wrote:

It looks like this is called only by `handleWrapsAttr`. Maybe just inline it?

https://github.com/llvm/llvm-project/pull/86618
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)

2024-04-22 Thread Bill Wendling via cfe-commits


@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -triple x86_64-pc-linux-gnu
+// expected-no-diagnostics
+typedef int __attribute__((wraps)) wrapping_int;
+
+void foo(void) {
+  const wrapping_int A = 1;
+  int D = 2147483647 + A;

bwendling wrote:

How about instead:

```c
int foo(void) {
  const wrapping_int A = 1;
  return 2147483647 + A;
}
```

https://github.com/llvm/llvm-project/pull/86618
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)

2024-04-22 Thread Bill Wendling via cfe-commits


@@ -4093,6 +4109,11 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo ) {
   op.RHS->getType()->isPointerTy())
 return emitPointerArithmetic(CGF, op, CodeGenFunction::NotSubtraction);
 
+  if ((op.Ty->isSignedIntegerOrEnumerationType() ||

bwendling wrote:

Is this early-exit necessary, or does the following processing not work?

https://github.com/llvm/llvm-project/pull/86618
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)

2024-04-22 Thread Bill Wendling via cfe-commits


@@ -156,6 +156,10 @@ struct BinOpInfo {
 }
 return false;
   }
+
+  /// Does the BinaryOperator have the wraps attribute?
+  /// If so, we can ellide overflow sanitizer checks.

bwendling wrote:

s/ellide/elide/

https://github.com/llvm/llvm-project/pull/86618
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Improve testing for the flexible array member (PR #89462)

2024-04-22 Thread Bill Wendling via cfe-commits

https://github.com/bwendling updated 
https://github.com/llvm/llvm-project/pull/89462

>From 2a6b3356a977132459bed84fb4e4add631e181cb Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Fri, 19 Apr 2024 15:06:34 -0700
Subject: [PATCH 1/2] [Clang][NFC] Improve testing for the flexible array
 member

Testing for the name of the flexible array member isn't as robust as
testing the FieldDecl pointers.
---
 clang/lib/CodeGen/CGBuiltin.cpp | 21 -
 clang/lib/CodeGen/CodeGenFunction.h | 12 ++--
 2 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 4ab844d206e48a..0d2b5e1b5120ae 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -822,8 +822,9 @@ CodeGenFunction::evaluateOrEmitBuiltinObjectSize(const Expr 
*E, unsigned Type,
   return ConstantInt::get(ResType, ObjectSize, /*isSigned=*/true);
 }
 
-const FieldDecl *CodeGenFunction::FindFlexibleArrayMemberField(
-ASTContext , const RecordDecl *RD, StringRef Name, uint64_t ) {
+const FieldDecl *CodeGenFunction::FindFlexibleArrayMemberFieldAndOffset(
+ASTContext , const RecordDecl *RD, const FieldDecl *FAMDecl,
+uint64_t ) {
   const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
   getLangOpts().getStrictFlexArraysLevel();
   uint32_t FieldNo = 0;
@@ -832,7 +833,7 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
 return nullptr;
 
   for (const FieldDecl *FD : RD->fields()) {
-if ((Name.empty() || FD->getNameAsString() == Name) &&
+if ((!FAMDecl || FD == FAMDecl) &&
 Decl::isFlexibleArrayMemberLike(
 Ctx, FD, FD->getType(), StrictFlexArraysLevel,
 /*IgnoreTemplateOrMacroSubstitution=*/true)) {
@@ -843,8 +844,8 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
 
 QualType Ty = FD->getType();
 if (Ty->isRecordType()) {
-  if (const FieldDecl *Field = FindFlexibleArrayMemberField(
-  Ctx, Ty->getAsRecordDecl(), Name, Offset)) {
+  if (const FieldDecl *Field = FindFlexibleArrayMemberFieldAndOffset(
+  Ctx, Ty->getAsRecordDecl(), FAMDecl, Offset)) {
 const ASTRecordLayout  = Ctx.getASTRecordLayout(RD);
 Offset += Layout.getFieldOffset(FieldNo);
 return Field;
@@ -930,12 +931,12 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr 
*E, unsigned Type,
 
   // Get the flexible array member Decl.
   const RecordDecl *OuterRD = nullptr;
-  std::string FAMName;
+  const FieldDecl *FAMDecl = nullptr;
   if (const auto *ME = dyn_cast(Base)) {
 // Check if \p Base is referencing the FAM itself.
 const ValueDecl *VD = ME->getMemberDecl();
 OuterRD = VD->getDeclContext()->getOuterLexicalRecordContext();
-FAMName = VD->getNameAsString();
+FAMDecl = dyn_cast(VD);
   } else if (const auto *DRE = dyn_cast(Base)) {
 // Check if we're pointing to the whole struct.
 QualType Ty = DRE->getDecl()->getType();
@@ -974,9 +975,11 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr 
*E, unsigned Type,
   if (!OuterRD)
 return nullptr;
 
+  // We call FindFlexibleArrayMemberAndOffset even if FAMDecl is non-null to
+  // get its offset.
   uint64_t Offset = 0;
-  const FieldDecl *FAMDecl =
-  FindFlexibleArrayMemberField(Ctx, OuterRD, FAMName, Offset);
+  FAMDecl =
+  FindFlexibleArrayMemberFieldAndOffset(Ctx, OuterRD, FAMDecl, Offset);
   Offset = Ctx.toCharUnitsFromBits(Offset).getQuantity();
 
   if (!FAMDecl || !FAMDecl->getType()->isCountAttributedType())
diff --git a/clang/lib/CodeGen/CodeGenFunction.h 
b/clang/lib/CodeGen/CodeGenFunction.h
index ff1873325d409f..a751649cdb597a 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3204,12 +3204,12 @@ class CodeGenFunction : public CodeGenTypeCache {
llvm::Value *Index, QualType IndexType,
QualType IndexedType, bool Accessed);
 
-  // Find a struct's flexible array member. It may be embedded inside multiple
-  // sub-structs, but must still be the last field.
-  const FieldDecl *FindFlexibleArrayMemberField(ASTContext ,
-const RecordDecl *RD,
-StringRef Name,
-uint64_t );
+  // Find a struct's flexible array member and get its offset. It may be
+  // embedded inside multiple sub-structs, but must still be the last field.
+  const FieldDecl *
+  FindFlexibleArrayMemberFieldAndOffset(ASTContext , const RecordDecl *RD,
+const FieldDecl *FAMDecl,
+uint64_t );
 
   /// Find the FieldDecl specified in a FAM's "counted_by" attribute. Returns
   /// \p nullptr if either the attribute or the field doesn't exist.

>From a12d8a360b00823fac57e43dd6a05dbe3ee91b53 Mon 

[clang] [Clang] Improve testing for the flexible array member (PR #89462)

2024-04-19 Thread Bill Wendling via cfe-commits


@@ -930,12 +931,12 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr 
*E, unsigned Type,
 
   // Get the flexible array member Decl.
   const RecordDecl *OuterRD = nullptr;
-  std::string FAMName;
+  const FieldDecl *FAMDecl = nullptr;
   if (const auto *ME = dyn_cast(Base)) {
 // Check if \p Base is referencing the FAM itself.
 const ValueDecl *VD = ME->getMemberDecl();
 OuterRD = VD->getDeclContext()->getOuterLexicalRecordContext();
-FAMName = VD->getNameAsString();
+FAMDecl = dyn_cast(VD);

bwendling wrote:

Wouldn't hurt. Done.

https://github.com/llvm/llvm-project/pull/89462
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Improve testing for the flexible array member (PR #89462)

2024-04-19 Thread Bill Wendling via cfe-commits

https://github.com/bwendling updated 
https://github.com/llvm/llvm-project/pull/89462

>From 2a6b3356a977132459bed84fb4e4add631e181cb Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Fri, 19 Apr 2024 15:06:34 -0700
Subject: [PATCH 1/2] [Clang][NFC] Improve testing for the flexible array
 member

Testing for the name of the flexible array member isn't as robust as
testing the FieldDecl pointers.
---
 clang/lib/CodeGen/CGBuiltin.cpp | 21 -
 clang/lib/CodeGen/CodeGenFunction.h | 12 ++--
 2 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 4ab844d206e48a..0d2b5e1b5120ae 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -822,8 +822,9 @@ CodeGenFunction::evaluateOrEmitBuiltinObjectSize(const Expr 
*E, unsigned Type,
   return ConstantInt::get(ResType, ObjectSize, /*isSigned=*/true);
 }
 
-const FieldDecl *CodeGenFunction::FindFlexibleArrayMemberField(
-ASTContext , const RecordDecl *RD, StringRef Name, uint64_t ) {
+const FieldDecl *CodeGenFunction::FindFlexibleArrayMemberFieldAndOffset(
+ASTContext , const RecordDecl *RD, const FieldDecl *FAMDecl,
+uint64_t ) {
   const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
   getLangOpts().getStrictFlexArraysLevel();
   uint32_t FieldNo = 0;
@@ -832,7 +833,7 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
 return nullptr;
 
   for (const FieldDecl *FD : RD->fields()) {
-if ((Name.empty() || FD->getNameAsString() == Name) &&
+if ((!FAMDecl || FD == FAMDecl) &&
 Decl::isFlexibleArrayMemberLike(
 Ctx, FD, FD->getType(), StrictFlexArraysLevel,
 /*IgnoreTemplateOrMacroSubstitution=*/true)) {
@@ -843,8 +844,8 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
 
 QualType Ty = FD->getType();
 if (Ty->isRecordType()) {
-  if (const FieldDecl *Field = FindFlexibleArrayMemberField(
-  Ctx, Ty->getAsRecordDecl(), Name, Offset)) {
+  if (const FieldDecl *Field = FindFlexibleArrayMemberFieldAndOffset(
+  Ctx, Ty->getAsRecordDecl(), FAMDecl, Offset)) {
 const ASTRecordLayout  = Ctx.getASTRecordLayout(RD);
 Offset += Layout.getFieldOffset(FieldNo);
 return Field;
@@ -930,12 +931,12 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr 
*E, unsigned Type,
 
   // Get the flexible array member Decl.
   const RecordDecl *OuterRD = nullptr;
-  std::string FAMName;
+  const FieldDecl *FAMDecl = nullptr;
   if (const auto *ME = dyn_cast(Base)) {
 // Check if \p Base is referencing the FAM itself.
 const ValueDecl *VD = ME->getMemberDecl();
 OuterRD = VD->getDeclContext()->getOuterLexicalRecordContext();
-FAMName = VD->getNameAsString();
+FAMDecl = dyn_cast(VD);
   } else if (const auto *DRE = dyn_cast(Base)) {
 // Check if we're pointing to the whole struct.
 QualType Ty = DRE->getDecl()->getType();
@@ -974,9 +975,11 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr 
*E, unsigned Type,
   if (!OuterRD)
 return nullptr;
 
+  // We call FindFlexibleArrayMemberAndOffset even if FAMDecl is non-null to
+  // get its offset.
   uint64_t Offset = 0;
-  const FieldDecl *FAMDecl =
-  FindFlexibleArrayMemberField(Ctx, OuterRD, FAMName, Offset);
+  FAMDecl =
+  FindFlexibleArrayMemberFieldAndOffset(Ctx, OuterRD, FAMDecl, Offset);
   Offset = Ctx.toCharUnitsFromBits(Offset).getQuantity();
 
   if (!FAMDecl || !FAMDecl->getType()->isCountAttributedType())
diff --git a/clang/lib/CodeGen/CodeGenFunction.h 
b/clang/lib/CodeGen/CodeGenFunction.h
index ff1873325d409f..a751649cdb597a 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3204,12 +3204,12 @@ class CodeGenFunction : public CodeGenTypeCache {
llvm::Value *Index, QualType IndexType,
QualType IndexedType, bool Accessed);
 
-  // Find a struct's flexible array member. It may be embedded inside multiple
-  // sub-structs, but must still be the last field.
-  const FieldDecl *FindFlexibleArrayMemberField(ASTContext ,
-const RecordDecl *RD,
-StringRef Name,
-uint64_t );
+  // Find a struct's flexible array member and get its offset. It may be
+  // embedded inside multiple sub-structs, but must still be the last field.
+  const FieldDecl *
+  FindFlexibleArrayMemberFieldAndOffset(ASTContext , const RecordDecl *RD,
+const FieldDecl *FAMDecl,
+uint64_t );
 
   /// Find the FieldDecl specified in a FAM's "counted_by" attribute. Returns
   /// \p nullptr if either the attribute or the field doesn't exist.

>From a12d8a360b00823fac57e43dd6a05dbe3ee91b53 Mon 

[clang] [Clang] Improve testing for the flexible array member (PR #89462)

2024-04-19 Thread Bill Wendling via cfe-commits

bwendling wrote:

A quick look at `Decl` seems like it would require adding a 
`PrevInContextAndBits`, which would increase the size by `sizeof(Decl *)`. I 
might be able to massage a way to make it work, but it's probably not worth it.

https://github.com/llvm/llvm-project/pull/89462
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Improve testing for the flexible array member (PR #89462)

2024-04-19 Thread Bill Wendling via cfe-commits

bwendling wrote:

Would changing the `decl_iterator` into a bidirectional iterator be acceptable? 
That way I could grab the last `FieldDecl` to check if it's a FAM rather than 
iterating through unnecessary `Decls`...

https://github.com/llvm/llvm-project/pull/89462
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Improve testing for the flexible array member (PR #89462)

2024-04-19 Thread Bill Wendling via cfe-commits

https://github.com/bwendling edited 
https://github.com/llvm/llvm-project/pull/89462
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][NFC] Improve testing for the flexible array member (PR #89462)

2024-04-19 Thread Bill Wendling via cfe-commits

bwendling wrote:

> Strictly speaking, I don't think this is NFC. Consider, for example:
> 
> ```
> struct S {
>   struct X { int array[1]; } x;
>   struct Y { int count; int array[] __attribute__((__counted_by__(count))); } 
> y;
> };
> void f(void* __attribute__((pass_dynamic_object_size(0;
> void g(struct S* s) { f(s->y.array); }
> ```

Hmm.. Yeah, this change makes it more accurate. I'll remove the tag.

https://github.com/llvm/llvm-project/pull/89462
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][NFC] Improve testing for the flexible array member (PR #89462)

2024-04-19 Thread Bill Wendling via cfe-commits

bwendling wrote:

> Does this still work for cases where there are multiple flexible arrays? e.g.
> 
> ```
> struct weird_protocol {
> unsigned int cmd_type;
> unsigned int data_len;
> union {
> struct cmd_one one[];
> struct cmd_two two[];
> struct cmd_three three[];
> unsigned char raw_bytes[];
> };
> };
> ```

Ah! One of your heresies. :-)

The current code probably doesn't support this (I'll check). This PR shouldn't 
change this. I'll have to revisit this code to make sure that it can be 
supported.

https://github.com/llvm/llvm-project/pull/89462
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][NFC] Improve testing for the flexible array member (PR #89462)

2024-04-19 Thread Bill Wendling via cfe-commits

https://github.com/bwendling created 
https://github.com/llvm/llvm-project/pull/89462

Testing for the name of the flexible array member isn't as robust as testing 
the FieldDecl pointers.

>From 2a6b3356a977132459bed84fb4e4add631e181cb Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Fri, 19 Apr 2024 15:06:34 -0700
Subject: [PATCH] [Clang][NFC] Improve testing for the flexible array member

Testing for the name of the flexible array member isn't as robust as
testing the FieldDecl pointers.
---
 clang/lib/CodeGen/CGBuiltin.cpp | 21 -
 clang/lib/CodeGen/CodeGenFunction.h | 12 ++--
 2 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 4ab844d206e48a..0d2b5e1b5120ae 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -822,8 +822,9 @@ CodeGenFunction::evaluateOrEmitBuiltinObjectSize(const Expr 
*E, unsigned Type,
   return ConstantInt::get(ResType, ObjectSize, /*isSigned=*/true);
 }
 
-const FieldDecl *CodeGenFunction::FindFlexibleArrayMemberField(
-ASTContext , const RecordDecl *RD, StringRef Name, uint64_t ) {
+const FieldDecl *CodeGenFunction::FindFlexibleArrayMemberFieldAndOffset(
+ASTContext , const RecordDecl *RD, const FieldDecl *FAMDecl,
+uint64_t ) {
   const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
   getLangOpts().getStrictFlexArraysLevel();
   uint32_t FieldNo = 0;
@@ -832,7 +833,7 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
 return nullptr;
 
   for (const FieldDecl *FD : RD->fields()) {
-if ((Name.empty() || FD->getNameAsString() == Name) &&
+if ((!FAMDecl || FD == FAMDecl) &&
 Decl::isFlexibleArrayMemberLike(
 Ctx, FD, FD->getType(), StrictFlexArraysLevel,
 /*IgnoreTemplateOrMacroSubstitution=*/true)) {
@@ -843,8 +844,8 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
 
 QualType Ty = FD->getType();
 if (Ty->isRecordType()) {
-  if (const FieldDecl *Field = FindFlexibleArrayMemberField(
-  Ctx, Ty->getAsRecordDecl(), Name, Offset)) {
+  if (const FieldDecl *Field = FindFlexibleArrayMemberFieldAndOffset(
+  Ctx, Ty->getAsRecordDecl(), FAMDecl, Offset)) {
 const ASTRecordLayout  = Ctx.getASTRecordLayout(RD);
 Offset += Layout.getFieldOffset(FieldNo);
 return Field;
@@ -930,12 +931,12 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr 
*E, unsigned Type,
 
   // Get the flexible array member Decl.
   const RecordDecl *OuterRD = nullptr;
-  std::string FAMName;
+  const FieldDecl *FAMDecl = nullptr;
   if (const auto *ME = dyn_cast(Base)) {
 // Check if \p Base is referencing the FAM itself.
 const ValueDecl *VD = ME->getMemberDecl();
 OuterRD = VD->getDeclContext()->getOuterLexicalRecordContext();
-FAMName = VD->getNameAsString();
+FAMDecl = dyn_cast(VD);
   } else if (const auto *DRE = dyn_cast(Base)) {
 // Check if we're pointing to the whole struct.
 QualType Ty = DRE->getDecl()->getType();
@@ -974,9 +975,11 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr 
*E, unsigned Type,
   if (!OuterRD)
 return nullptr;
 
+  // We call FindFlexibleArrayMemberAndOffset even if FAMDecl is non-null to
+  // get its offset.
   uint64_t Offset = 0;
-  const FieldDecl *FAMDecl =
-  FindFlexibleArrayMemberField(Ctx, OuterRD, FAMName, Offset);
+  FAMDecl =
+  FindFlexibleArrayMemberFieldAndOffset(Ctx, OuterRD, FAMDecl, Offset);
   Offset = Ctx.toCharUnitsFromBits(Offset).getQuantity();
 
   if (!FAMDecl || !FAMDecl->getType()->isCountAttributedType())
diff --git a/clang/lib/CodeGen/CodeGenFunction.h 
b/clang/lib/CodeGen/CodeGenFunction.h
index ff1873325d409f..a751649cdb597a 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3204,12 +3204,12 @@ class CodeGenFunction : public CodeGenTypeCache {
llvm::Value *Index, QualType IndexType,
QualType IndexedType, bool Accessed);
 
-  // Find a struct's flexible array member. It may be embedded inside multiple
-  // sub-structs, but must still be the last field.
-  const FieldDecl *FindFlexibleArrayMemberField(ASTContext ,
-const RecordDecl *RD,
-StringRef Name,
-uint64_t );
+  // Find a struct's flexible array member and get its offset. It may be
+  // embedded inside multiple sub-structs, but must still be the last field.
+  const FieldDecl *
+  FindFlexibleArrayMemberFieldAndOffset(ASTContext , const RecordDecl *RD,
+const FieldDecl *FAMDecl,
+uint64_t );
 
   /// Find the FieldDecl specified in a FAM's "counted_by" attribute. Returns
   /// \p nullptr if 

[clang] [Clang] Handle structs with inner structs and no fields (PR #89126)

2024-04-19 Thread Bill Wendling via cfe-commits


@@ -826,29 +826,32 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
 ASTContext , const RecordDecl *RD, StringRef Name, uint64_t ) {
   const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
   getLangOpts().getStrictFlexArraysLevel();
-  unsigned FieldNo = 0;
-  bool IsUnion = RD->isUnion();
+  uint32_t FieldNo = 0;
 
-  for (const Decl *D : RD->decls()) {
-if (const auto *Field = dyn_cast(D);
-Field && (Name.empty() || Field->getNameAsString() == Name) &&
+  if (RD->isImplicit())
+return nullptr;
+
+  for (const FieldDecl *FD : RD->fields()) {
+if ((Name.empty() || FD->getNameAsString() == Name) &&

bwendling wrote:

I think I did it this way to support searching from either a pointer to the 
whole struct or pointer to the FAM. I suppose running this when we know we're 
pointing to the FAM is a bit redundant. And yes, using a `FieldDecl` pointer 
instead is almost certainly better here.

I think what I want to do though is rework some of the code so that we support 
`__builtin_dynamic_object_size` for more than just pointing to either the FAM 
or struct. I'll make that change as well.

https://github.com/llvm/llvm-project/pull/89126
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Loop over FieldDecls instead of all Decls (PR #89453)

2024-04-19 Thread Bill Wendling via cfe-commits

https://github.com/bwendling closed 
https://github.com/llvm/llvm-project/pull/89453
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Loop over FieldDecls instead of all Decls (PR #89453)

2024-04-19 Thread Bill Wendling via cfe-commits

https://github.com/bwendling created 
https://github.com/llvm/llvm-project/pull/89453

Only FieldDecls are of importance here. A struct defined within another struct 
has the same semantics as if it were defined outside of the struct. So there's 
no need to look into RecordDecls that aren't a field.

>From f6fe986fa23df709d502311d9db2e1b4de47bb67 Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Fri, 19 Apr 2024 13:45:38 -0700
Subject: [PATCH] [Clang] Loop over FieldDecls instead of all Decls

Only FieldDecls are of importance here. A struct defined within another
struct has the same semantics as if it were defined outside of the
struct. So there's no need to look into RecordDecls that aren't a field.
---
 clang/lib/CodeGen/CGBuiltin.cpp | 11 +--
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 4319501035e257..4ab844d206e48a 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -861,14 +861,13 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
 static unsigned CountCountedByAttrs(const RecordDecl *RD) {
   unsigned Num = 0;
 
-  for (const Decl *D : RD->decls()) {
-if (const auto *FD = dyn_cast(D);
-FD && FD->getType()->isCountAttributedType()) {
+  for (const FieldDecl *FD : RD->fields()) {
+if (FD->getType()->isCountAttributedType())
   return ++Num;
-}
 
-if (const auto *Rec = dyn_cast(D))
-  Num += CountCountedByAttrs(Rec);
+QualType Ty = FD->getType();
+if (Ty->isRecordType())
+  Num += CountCountedByAttrs(Ty->getAsRecordDecl());
   }
 
   return Num;

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Handle structs with inner structs and no fields (PR #89126)

2024-04-19 Thread Bill Wendling via cfe-commits

https://github.com/bwendling closed 
https://github.com/llvm/llvm-project/pull/89126
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Handle structs with inner structs and no fields (PR #89126)

2024-04-19 Thread Bill Wendling via cfe-commits

https://github.com/bwendling updated 
https://github.com/llvm/llvm-project/pull/89126

>From 36ddb5811f11a1f6968705005713f34713026dbb Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Wed, 17 Apr 2024 12:23:02 -0700
Subject: [PATCH 1/8] [Clang] Handle structs with inner structs and no fields

A struct that declares an inner struct, but no fields, won't have a
field count. So getting the offset of the inner struct fails. This
happens in both C and C++:

  struct foo {
struct bar {
  int Quantizermatrix[];
};
  };

Here 'struct foo' has no fields.
---
 clang/lib/CodeGen/CGBuiltin.cpp   | 15 -
 clang/test/CodeGen/attr-counted-by-pr88931.c  | 22 +++
 .../test/CodeGen/attr-counted-by-pr88931.cpp  | 21 ++
 3 files changed, 57 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/CodeGen/attr-counted-by-pr88931.c
 create mode 100644 clang/test/CodeGen/attr-counted-by-pr88931.cpp

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index a05874e63c73c2..bee12c4469e7f7 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -829,6 +829,9 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
   unsigned FieldNo = 0;
   bool IsUnion = RD->isUnion();
 
+  if (RD->isImplicit())
+return nullptr;
+
   for (const Decl *D : RD->decls()) {
 if (const auto *Field = dyn_cast(D);
 Field && (Name.empty() || Field->getNameAsString() == Name) &&
@@ -844,7 +847,17 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
   if (const FieldDecl *Field =
   FindFlexibleArrayMemberField(Ctx, Record, Name, Offset)) {
 const ASTRecordLayout  = Ctx.getASTRecordLayout(RD);
-Offset += Layout.getFieldOffset(FieldNo);
+if (Layout.getFieldCount()) {
+  // A struct that holds only an inner struct won't have any fields. 
E.g.
+  //
+  // struct foo {
+  // struct bar {
+  // int count;
+  // int array[];
+  // };
+  // };
+  Offset += Layout.getFieldOffset(FieldNo);
+}
 return Field;
   }
 
diff --git a/clang/test/CodeGen/attr-counted-by-pr88931.c 
b/clang/test/CodeGen/attr-counted-by-pr88931.c
new file mode 100644
index 00..baa1bbc8397456
--- /dev/null
+++ b/clang/test/CodeGen/attr-counted-by-pr88931.c
@@ -0,0 +1,22 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 4
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 
-Wno-missing-declarations -emit-llvm -o - %s | FileCheck %s
+
+struct foo {
+  struct bar {
+int count;
+int array[] __attribute__((counted_by(count)));
+  };
+};
+
+void init(void * __attribute__((pass_dynamic_object_size(0;
+
+// CHECK-LABEL: define dso_local void @test1(
+// CHECK-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:[[ARRAY:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 4
+// CHECK-NEXT:tail call void @init(ptr noundef nonnull [[ARRAY]], i64 
noundef -1) #[[ATTR2:[0-9]+]]
+// CHECK-NEXT:ret void
+//
+void test1(struct bar *p) {
+  init(p->array);
+}
diff --git a/clang/test/CodeGen/attr-counted-by-pr88931.cpp 
b/clang/test/CodeGen/attr-counted-by-pr88931.cpp
new file mode 100644
index 00..2a8cc1d07e50d9
--- /dev/null
+++ b/clang/test/CodeGen/attr-counted-by-pr88931.cpp
@@ -0,0 +1,21 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 4
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -Wall -emit-llvm -o - 
%s | FileCheck %s
+
+struct foo {
+  struct bar {
+int array[];
+bar();
+  };
+};
+
+void init(void * __attribute__((pass_dynamic_object_size(0;
+
+// CHECK-LABEL: define dso_local void @_ZN3foo3barC1Ev(
+// CHECK-SAME: ptr noundef nonnull align 4 dereferenceable(1) [[THIS:%.*]]) 
unnamed_addr #[[ATTR0:[0-9]+]] align 2 {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:tail call void @_Z4initPvU25pass_dynamic_object_size0(ptr 
noundef nonnull [[THIS]], i64 noundef -1) #[[ATTR2:[0-9]+]]
+// CHECK-NEXT:ret void
+//
+foo::bar::bar() {
+  init(array);
+}

>From fbb22e6aa21961763c3eb1ca45d44e6c8add1ceb Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Wed, 17 Apr 2024 12:32:27 -0700
Subject: [PATCH 2/8] Reformat

---
 clang/lib/CodeGen/CGBuiltin.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index bee12c4469e7f7..e7d2b84da8bc4d 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -848,7 +848,8 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
   FindFlexibleArrayMemberField(Ctx, Record, Name, Offset)) {
 const ASTRecordLayout  = Ctx.getASTRecordLayout(RD);
 if 

[clang] [Clang] Handle structs with inner structs and no fields (PR #89126)

2024-04-19 Thread Bill Wendling via cfe-commits

https://github.com/bwendling edited 
https://github.com/llvm/llvm-project/pull/89126
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Handle structs with inner structs and no fields (PR #89126)

2024-04-19 Thread Bill Wendling via cfe-commits


@@ -0,0 +1,22 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 4
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 
-Wno-missing-declarations -emit-llvm -o - %s | FileCheck %s
+
+struct foo {
+  struct bar {
+int count;
+int array[] __attribute__((counted_by(count)));

bwendling wrote:

I see what you mean. I'd like to leave it for a followup, since this change is 
meant to fix an ICE.

https://github.com/llvm/llvm-project/pull/89126
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Handle structs with inner structs and no fields (PR #89126)

2024-04-19 Thread Bill Wendling via cfe-commits

https://github.com/bwendling updated 
https://github.com/llvm/llvm-project/pull/89126

>From 36ddb5811f11a1f6968705005713f34713026dbb Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Wed, 17 Apr 2024 12:23:02 -0700
Subject: [PATCH 1/8] [Clang] Handle structs with inner structs and no fields

A struct that declares an inner struct, but no fields, won't have a
field count. So getting the offset of the inner struct fails. This
happens in both C and C++:

  struct foo {
struct bar {
  int Quantizermatrix[];
};
  };

Here 'struct foo' has no fields.
---
 clang/lib/CodeGen/CGBuiltin.cpp   | 15 -
 clang/test/CodeGen/attr-counted-by-pr88931.c  | 22 +++
 .../test/CodeGen/attr-counted-by-pr88931.cpp  | 21 ++
 3 files changed, 57 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/CodeGen/attr-counted-by-pr88931.c
 create mode 100644 clang/test/CodeGen/attr-counted-by-pr88931.cpp

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index a05874e63c73c2..bee12c4469e7f7 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -829,6 +829,9 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
   unsigned FieldNo = 0;
   bool IsUnion = RD->isUnion();
 
+  if (RD->isImplicit())
+return nullptr;
+
   for (const Decl *D : RD->decls()) {
 if (const auto *Field = dyn_cast(D);
 Field && (Name.empty() || Field->getNameAsString() == Name) &&
@@ -844,7 +847,17 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
   if (const FieldDecl *Field =
   FindFlexibleArrayMemberField(Ctx, Record, Name, Offset)) {
 const ASTRecordLayout  = Ctx.getASTRecordLayout(RD);
-Offset += Layout.getFieldOffset(FieldNo);
+if (Layout.getFieldCount()) {
+  // A struct that holds only an inner struct won't have any fields. 
E.g.
+  //
+  // struct foo {
+  // struct bar {
+  // int count;
+  // int array[];
+  // };
+  // };
+  Offset += Layout.getFieldOffset(FieldNo);
+}
 return Field;
   }
 
diff --git a/clang/test/CodeGen/attr-counted-by-pr88931.c 
b/clang/test/CodeGen/attr-counted-by-pr88931.c
new file mode 100644
index 00..baa1bbc8397456
--- /dev/null
+++ b/clang/test/CodeGen/attr-counted-by-pr88931.c
@@ -0,0 +1,22 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 4
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 
-Wno-missing-declarations -emit-llvm -o - %s | FileCheck %s
+
+struct foo {
+  struct bar {
+int count;
+int array[] __attribute__((counted_by(count)));
+  };
+};
+
+void init(void * __attribute__((pass_dynamic_object_size(0;
+
+// CHECK-LABEL: define dso_local void @test1(
+// CHECK-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:[[ARRAY:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 4
+// CHECK-NEXT:tail call void @init(ptr noundef nonnull [[ARRAY]], i64 
noundef -1) #[[ATTR2:[0-9]+]]
+// CHECK-NEXT:ret void
+//
+void test1(struct bar *p) {
+  init(p->array);
+}
diff --git a/clang/test/CodeGen/attr-counted-by-pr88931.cpp 
b/clang/test/CodeGen/attr-counted-by-pr88931.cpp
new file mode 100644
index 00..2a8cc1d07e50d9
--- /dev/null
+++ b/clang/test/CodeGen/attr-counted-by-pr88931.cpp
@@ -0,0 +1,21 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 4
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -Wall -emit-llvm -o - 
%s | FileCheck %s
+
+struct foo {
+  struct bar {
+int array[];
+bar();
+  };
+};
+
+void init(void * __attribute__((pass_dynamic_object_size(0;
+
+// CHECK-LABEL: define dso_local void @_ZN3foo3barC1Ev(
+// CHECK-SAME: ptr noundef nonnull align 4 dereferenceable(1) [[THIS:%.*]]) 
unnamed_addr #[[ATTR0:[0-9]+]] align 2 {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:tail call void @_Z4initPvU25pass_dynamic_object_size0(ptr 
noundef nonnull [[THIS]], i64 noundef -1) #[[ATTR2:[0-9]+]]
+// CHECK-NEXT:ret void
+//
+foo::bar::bar() {
+  init(array);
+}

>From fbb22e6aa21961763c3eb1ca45d44e6c8add1ceb Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Wed, 17 Apr 2024 12:32:27 -0700
Subject: [PATCH 2/8] Reformat

---
 clang/lib/CodeGen/CGBuiltin.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index bee12c4469e7f7..e7d2b84da8bc4d 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -848,7 +848,8 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
   FindFlexibleArrayMemberField(Ctx, Record, Name, Offset)) {
 const ASTRecordLayout  = Ctx.getASTRecordLayout(RD);
 if 

[clang] [Clang] Handle structs with inner structs and no fields (PR #89126)

2024-04-19 Thread Bill Wendling via cfe-commits


@@ -0,0 +1,40 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 4
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 
-Wno-missing-declarations -emit-llvm -o - %s | FileCheck %s
+
+struct foo {
+  int x,y,z;
+  struct bar {
+int count;
+int array[] __attribute__((counted_by(count)));
+  };
+};
+
+void init(void * __attribute__((pass_dynamic_object_size(0;
+
+// CHECK-LABEL: define dso_local void @test1(
+// CHECK-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:[[ARRAY:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 4
+// CHECK-NEXT:tail call void @init(ptr noundef nonnull [[ARRAY]], i64 
noundef -1) #[[ATTR2:[0-9]+]]
+// CHECK-NEXT:ret void
+//
+void test1(struct bar *p) {
+  init(p->array);
+}
+
+struct mux {
+  int count;
+  int array[] __attribute__((counted_by(count)));
+};
+
+struct bux { struct mux x; };
+
+// CHECK-LABEL: define dso_local void @test2(
+// CHECK-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:tail call void @init(ptr noundef [[P]], i64 noundef -1) 
#[[ATTR2]]
+// CHECK-NEXT:ret void
+//
+void test2(struct foo *p) {

bwendling wrote:

Doh! Yes. Done.

https://github.com/llvm/llvm-project/pull/89126
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Handle structs with inner structs and no fields (PR #89126)

2024-04-18 Thread Bill Wendling via cfe-commits


@@ -0,0 +1,22 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 4
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 
-Wno-missing-declarations -emit-llvm -o - %s | FileCheck %s
+
+struct foo {
+  struct bar {
+int count;
+int array[] __attribute__((counted_by(count)));

bwendling wrote:

We can, if handling `struct bar` on its own. It's just there's seemingly no way 
in C to access the fields in `struct bar` from `struct foo`...

https://github.com/llvm/llvm-project/pull/89126
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Handle structs with inner structs and no fields (PR #89126)

2024-04-18 Thread Bill Wendling via cfe-commits

https://github.com/bwendling updated 
https://github.com/llvm/llvm-project/pull/89126

>From 36ddb5811f11a1f6968705005713f34713026dbb Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Wed, 17 Apr 2024 12:23:02 -0700
Subject: [PATCH 1/4] [Clang] Handle structs with inner structs and no fields

A struct that declares an inner struct, but no fields, won't have a
field count. So getting the offset of the inner struct fails. This
happens in both C and C++:

  struct foo {
struct bar {
  int Quantizermatrix[];
};
  };

Here 'struct foo' has no fields.
---
 clang/lib/CodeGen/CGBuiltin.cpp   | 15 -
 clang/test/CodeGen/attr-counted-by-pr88931.c  | 22 +++
 .../test/CodeGen/attr-counted-by-pr88931.cpp  | 21 ++
 3 files changed, 57 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/CodeGen/attr-counted-by-pr88931.c
 create mode 100644 clang/test/CodeGen/attr-counted-by-pr88931.cpp

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index a05874e63c73c2..bee12c4469e7f7 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -829,6 +829,9 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
   unsigned FieldNo = 0;
   bool IsUnion = RD->isUnion();
 
+  if (RD->isImplicit())
+return nullptr;
+
   for (const Decl *D : RD->decls()) {
 if (const auto *Field = dyn_cast(D);
 Field && (Name.empty() || Field->getNameAsString() == Name) &&
@@ -844,7 +847,17 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
   if (const FieldDecl *Field =
   FindFlexibleArrayMemberField(Ctx, Record, Name, Offset)) {
 const ASTRecordLayout  = Ctx.getASTRecordLayout(RD);
-Offset += Layout.getFieldOffset(FieldNo);
+if (Layout.getFieldCount()) {
+  // A struct that holds only an inner struct won't have any fields. 
E.g.
+  //
+  // struct foo {
+  // struct bar {
+  // int count;
+  // int array[];
+  // };
+  // };
+  Offset += Layout.getFieldOffset(FieldNo);
+}
 return Field;
   }
 
diff --git a/clang/test/CodeGen/attr-counted-by-pr88931.c 
b/clang/test/CodeGen/attr-counted-by-pr88931.c
new file mode 100644
index 00..baa1bbc8397456
--- /dev/null
+++ b/clang/test/CodeGen/attr-counted-by-pr88931.c
@@ -0,0 +1,22 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 4
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 
-Wno-missing-declarations -emit-llvm -o - %s | FileCheck %s
+
+struct foo {
+  struct bar {
+int count;
+int array[] __attribute__((counted_by(count)));
+  };
+};
+
+void init(void * __attribute__((pass_dynamic_object_size(0;
+
+// CHECK-LABEL: define dso_local void @test1(
+// CHECK-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:[[ARRAY:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 4
+// CHECK-NEXT:tail call void @init(ptr noundef nonnull [[ARRAY]], i64 
noundef -1) #[[ATTR2:[0-9]+]]
+// CHECK-NEXT:ret void
+//
+void test1(struct bar *p) {
+  init(p->array);
+}
diff --git a/clang/test/CodeGen/attr-counted-by-pr88931.cpp 
b/clang/test/CodeGen/attr-counted-by-pr88931.cpp
new file mode 100644
index 00..2a8cc1d07e50d9
--- /dev/null
+++ b/clang/test/CodeGen/attr-counted-by-pr88931.cpp
@@ -0,0 +1,21 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 4
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -Wall -emit-llvm -o - 
%s | FileCheck %s
+
+struct foo {
+  struct bar {
+int array[];
+bar();
+  };
+};
+
+void init(void * __attribute__((pass_dynamic_object_size(0;
+
+// CHECK-LABEL: define dso_local void @_ZN3foo3barC1Ev(
+// CHECK-SAME: ptr noundef nonnull align 4 dereferenceable(1) [[THIS:%.*]]) 
unnamed_addr #[[ATTR0:[0-9]+]] align 2 {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:tail call void @_Z4initPvU25pass_dynamic_object_size0(ptr 
noundef nonnull [[THIS]], i64 noundef -1) #[[ATTR2:[0-9]+]]
+// CHECK-NEXT:ret void
+//
+foo::bar::bar() {
+  init(array);
+}

>From fbb22e6aa21961763c3eb1ca45d44e6c8add1ceb Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Wed, 17 Apr 2024 12:32:27 -0700
Subject: [PATCH 2/4] Reformat

---
 clang/lib/CodeGen/CGBuiltin.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index bee12c4469e7f7..e7d2b84da8bc4d 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -848,7 +848,8 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
   FindFlexibleArrayMemberField(Ctx, Record, Name, Offset)) {
 const ASTRecordLayout  = Ctx.getASTRecordLayout(RD);
 if 

[clang] [Clang] Handle structs with inner structs and no fields (PR #89126)

2024-04-18 Thread Bill Wendling via cfe-commits

bwendling wrote:

> We should probably apply the same fix to CountCountedByAttrs.
> 
> Along those lines, we should be able to handle:
> 
> ```
> struct bar {
>   int count;
>   int array[] __attribute__((counted_by(count)));
> };
> struct foo { struct bar x; };
> void init(void * __attribute__((pass_dynamic_object_size(0;
> void test1(struct foo *p) {
>   init(p);
> }
> ```

I can support that. I'll add it as a testcase.

https://github.com/llvm/llvm-project/pull/89126
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Handle structs with inner structs and no fields (PR #89126)

2024-04-18 Thread Bill Wendling via cfe-commits

https://github.com/bwendling updated 
https://github.com/llvm/llvm-project/pull/89126

>From 36ddb5811f11a1f6968705005713f34713026dbb Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Wed, 17 Apr 2024 12:23:02 -0700
Subject: [PATCH 1/3] [Clang] Handle structs with inner structs and no fields

A struct that declares an inner struct, but no fields, won't have a
field count. So getting the offset of the inner struct fails. This
happens in both C and C++:

  struct foo {
struct bar {
  int Quantizermatrix[];
};
  };

Here 'struct foo' has no fields.
---
 clang/lib/CodeGen/CGBuiltin.cpp   | 15 -
 clang/test/CodeGen/attr-counted-by-pr88931.c  | 22 +++
 .../test/CodeGen/attr-counted-by-pr88931.cpp  | 21 ++
 3 files changed, 57 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/CodeGen/attr-counted-by-pr88931.c
 create mode 100644 clang/test/CodeGen/attr-counted-by-pr88931.cpp

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index a05874e63c73c2..bee12c4469e7f7 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -829,6 +829,9 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
   unsigned FieldNo = 0;
   bool IsUnion = RD->isUnion();
 
+  if (RD->isImplicit())
+return nullptr;
+
   for (const Decl *D : RD->decls()) {
 if (const auto *Field = dyn_cast(D);
 Field && (Name.empty() || Field->getNameAsString() == Name) &&
@@ -844,7 +847,17 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
   if (const FieldDecl *Field =
   FindFlexibleArrayMemberField(Ctx, Record, Name, Offset)) {
 const ASTRecordLayout  = Ctx.getASTRecordLayout(RD);
-Offset += Layout.getFieldOffset(FieldNo);
+if (Layout.getFieldCount()) {
+  // A struct that holds only an inner struct won't have any fields. 
E.g.
+  //
+  // struct foo {
+  // struct bar {
+  // int count;
+  // int array[];
+  // };
+  // };
+  Offset += Layout.getFieldOffset(FieldNo);
+}
 return Field;
   }
 
diff --git a/clang/test/CodeGen/attr-counted-by-pr88931.c 
b/clang/test/CodeGen/attr-counted-by-pr88931.c
new file mode 100644
index 00..baa1bbc8397456
--- /dev/null
+++ b/clang/test/CodeGen/attr-counted-by-pr88931.c
@@ -0,0 +1,22 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 4
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 
-Wno-missing-declarations -emit-llvm -o - %s | FileCheck %s
+
+struct foo {
+  struct bar {
+int count;
+int array[] __attribute__((counted_by(count)));
+  };
+};
+
+void init(void * __attribute__((pass_dynamic_object_size(0;
+
+// CHECK-LABEL: define dso_local void @test1(
+// CHECK-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:[[ARRAY:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 4
+// CHECK-NEXT:tail call void @init(ptr noundef nonnull [[ARRAY]], i64 
noundef -1) #[[ATTR2:[0-9]+]]
+// CHECK-NEXT:ret void
+//
+void test1(struct bar *p) {
+  init(p->array);
+}
diff --git a/clang/test/CodeGen/attr-counted-by-pr88931.cpp 
b/clang/test/CodeGen/attr-counted-by-pr88931.cpp
new file mode 100644
index 00..2a8cc1d07e50d9
--- /dev/null
+++ b/clang/test/CodeGen/attr-counted-by-pr88931.cpp
@@ -0,0 +1,21 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 4
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -Wall -emit-llvm -o - 
%s | FileCheck %s
+
+struct foo {
+  struct bar {
+int array[];
+bar();
+  };
+};
+
+void init(void * __attribute__((pass_dynamic_object_size(0;
+
+// CHECK-LABEL: define dso_local void @_ZN3foo3barC1Ev(
+// CHECK-SAME: ptr noundef nonnull align 4 dereferenceable(1) [[THIS:%.*]]) 
unnamed_addr #[[ATTR0:[0-9]+]] align 2 {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:tail call void @_Z4initPvU25pass_dynamic_object_size0(ptr 
noundef nonnull [[THIS]], i64 noundef -1) #[[ATTR2:[0-9]+]]
+// CHECK-NEXT:ret void
+//
+foo::bar::bar() {
+  init(array);
+}

>From fbb22e6aa21961763c3eb1ca45d44e6c8add1ceb Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Wed, 17 Apr 2024 12:32:27 -0700
Subject: [PATCH 2/3] Reformat

---
 clang/lib/CodeGen/CGBuiltin.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index bee12c4469e7f7..e7d2b84da8bc4d 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -848,7 +848,8 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
   FindFlexibleArrayMemberField(Ctx, Record, Name, Offset)) {
 const ASTRecordLayout  = Ctx.getASTRecordLayout(RD);
 if 

[clang] [Clang] Handle structs with inner structs and no fields (PR #89126)

2024-04-18 Thread Bill Wendling via cfe-commits


@@ -844,7 +847,18 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
   if (const FieldDecl *Field =

bwendling wrote:

I did several tests, and it looks like if there's an inner struct that's not 
accessible, that doesn't affect the offsets of fields outside of that inner 
struct.

```c
struct foo {
  struct inner_1 {
/* fields */
  };
  struct inner_2 {
int a;   /* __builtin_offsetof is 0 */
  };
  int b; /* __builtin_offsetof is 0 */
};
```

@efriedma-quic Do you have any thoughts?


https://github.com/llvm/llvm-project/pull/89126
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Handle structs with inner structs and no fields (PR #89126)

2024-04-18 Thread Bill Wendling via cfe-commits


@@ -844,7 +847,18 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
   if (const FieldDecl *Field =

bwendling wrote:

> FieldNo and Layout are referring to fields of "RD"; the "Field" found in the 
> recursive visit is a member of Record (or some subobject of Record). So the 
> code is doing math on completely unrelated offsets. Checking getFieldCount is 
> just masking the issue.

That's not the issue. What's happening is when an inner struct is 
declared/defined, we recurse within it to try to find the `Field` offset. If we 
do find it, then `Offset` has the offset value within `Record`. At this point, 
what we need is the offset up to the `RecordDecl`, but since those may or may 
not have a field number associated with them, we use the last `FieldNo` to get 
that offset.

A bit clearer:

```
struct foo {/* <- Passed in as RD */
  struct bar {  /* <- Not a field, so FieldNo isn't incremented. Recurse on 
struct bar */
int array[];/* <- FAM found at offset 0 of struct bar */
  };
/* <- Returning with the array FieldDecl, we want to add on 
any
  offset associated with the placement of the struct bar
  definition, but there are no FieldDecls, and so we 
can't
  call 'Layout.getFieldOffset()' */
};
```

This has obvious issues with virtual classes and the like, which is why C++ 
doesn't officially support FAMs (I believe it's an extension).

To be fair, I had the same question you had. I should document this better.

> Maybe instead of looking for RecordDecls, this code should be looking for 
> fields where the type of the field is an anonymous struct/union.

We want to look into all inner structs to find a FAM that may be lurking deep 
down within the bowels of the struct, which may involve non-anonymous structs.

https://github.com/llvm/llvm-project/pull/89126
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Handle structs with inner structs and no fields (PR #89126)

2024-04-17 Thread Bill Wendling via cfe-commits

https://github.com/bwendling updated 
https://github.com/llvm/llvm-project/pull/89126

>From 36ddb5811f11a1f6968705005713f34713026dbb Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Wed, 17 Apr 2024 12:23:02 -0700
Subject: [PATCH 1/2] [Clang] Handle structs with inner structs and no fields

A struct that declares an inner struct, but no fields, won't have a
field count. So getting the offset of the inner struct fails. This
happens in both C and C++:

  struct foo {
struct bar {
  int Quantizermatrix[];
};
  };

Here 'struct foo' has no fields.
---
 clang/lib/CodeGen/CGBuiltin.cpp   | 15 -
 clang/test/CodeGen/attr-counted-by-pr88931.c  | 22 +++
 .../test/CodeGen/attr-counted-by-pr88931.cpp  | 21 ++
 3 files changed, 57 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/CodeGen/attr-counted-by-pr88931.c
 create mode 100644 clang/test/CodeGen/attr-counted-by-pr88931.cpp

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index a05874e63c73c2..bee12c4469e7f7 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -829,6 +829,9 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
   unsigned FieldNo = 0;
   bool IsUnion = RD->isUnion();
 
+  if (RD->isImplicit())
+return nullptr;
+
   for (const Decl *D : RD->decls()) {
 if (const auto *Field = dyn_cast(D);
 Field && (Name.empty() || Field->getNameAsString() == Name) &&
@@ -844,7 +847,17 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
   if (const FieldDecl *Field =
   FindFlexibleArrayMemberField(Ctx, Record, Name, Offset)) {
 const ASTRecordLayout  = Ctx.getASTRecordLayout(RD);
-Offset += Layout.getFieldOffset(FieldNo);
+if (Layout.getFieldCount()) {
+  // A struct that holds only an inner struct won't have any fields. 
E.g.
+  //
+  // struct foo {
+  // struct bar {
+  // int count;
+  // int array[];
+  // };
+  // };
+  Offset += Layout.getFieldOffset(FieldNo);
+}
 return Field;
   }
 
diff --git a/clang/test/CodeGen/attr-counted-by-pr88931.c 
b/clang/test/CodeGen/attr-counted-by-pr88931.c
new file mode 100644
index 00..baa1bbc8397456
--- /dev/null
+++ b/clang/test/CodeGen/attr-counted-by-pr88931.c
@@ -0,0 +1,22 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 4
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 
-Wno-missing-declarations -emit-llvm -o - %s | FileCheck %s
+
+struct foo {
+  struct bar {
+int count;
+int array[] __attribute__((counted_by(count)));
+  };
+};
+
+void init(void * __attribute__((pass_dynamic_object_size(0;
+
+// CHECK-LABEL: define dso_local void @test1(
+// CHECK-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:[[ARRAY:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 4
+// CHECK-NEXT:tail call void @init(ptr noundef nonnull [[ARRAY]], i64 
noundef -1) #[[ATTR2:[0-9]+]]
+// CHECK-NEXT:ret void
+//
+void test1(struct bar *p) {
+  init(p->array);
+}
diff --git a/clang/test/CodeGen/attr-counted-by-pr88931.cpp 
b/clang/test/CodeGen/attr-counted-by-pr88931.cpp
new file mode 100644
index 00..2a8cc1d07e50d9
--- /dev/null
+++ b/clang/test/CodeGen/attr-counted-by-pr88931.cpp
@@ -0,0 +1,21 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 4
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -Wall -emit-llvm -o - 
%s | FileCheck %s
+
+struct foo {
+  struct bar {
+int array[];
+bar();
+  };
+};
+
+void init(void * __attribute__((pass_dynamic_object_size(0;
+
+// CHECK-LABEL: define dso_local void @_ZN3foo3barC1Ev(
+// CHECK-SAME: ptr noundef nonnull align 4 dereferenceable(1) [[THIS:%.*]]) 
unnamed_addr #[[ATTR0:[0-9]+]] align 2 {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:tail call void @_Z4initPvU25pass_dynamic_object_size0(ptr 
noundef nonnull [[THIS]], i64 noundef -1) #[[ATTR2:[0-9]+]]
+// CHECK-NEXT:ret void
+//
+foo::bar::bar() {
+  init(array);
+}

>From fbb22e6aa21961763c3eb1ca45d44e6c8add1ceb Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Wed, 17 Apr 2024 12:32:27 -0700
Subject: [PATCH 2/2] Reformat

---
 clang/lib/CodeGen/CGBuiltin.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index bee12c4469e7f7..e7d2b84da8bc4d 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -848,7 +848,8 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
   FindFlexibleArrayMemberField(Ctx, Record, Name, Offset)) {
 const ASTRecordLayout  = Ctx.getASTRecordLayout(RD);
 if 

[clang] [Clang] Handle structs with inner structs and no fields (PR #89126)

2024-04-17 Thread Bill Wendling via cfe-commits

https://github.com/bwendling created 
https://github.com/llvm/llvm-project/pull/89126

A struct that declares an inner struct, but no fields, won't have a field 
count. So getting the offset of the inner struct fails. This happens in both C 
and C++:

  struct foo {
struct bar {
  int Quantizermatrix[];
};
  };

Here 'struct foo' has no fields.

Fixes: https://github.com/llvm/llvm-project/issues/88931

>From 36ddb5811f11a1f6968705005713f34713026dbb Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Wed, 17 Apr 2024 12:23:02 -0700
Subject: [PATCH] [Clang] Handle structs with inner structs and no fields

A struct that declares an inner struct, but no fields, won't have a
field count. So getting the offset of the inner struct fails. This
happens in both C and C++:

  struct foo {
struct bar {
  int Quantizermatrix[];
};
  };

Here 'struct foo' has no fields.
---
 clang/lib/CodeGen/CGBuiltin.cpp   | 15 -
 clang/test/CodeGen/attr-counted-by-pr88931.c  | 22 +++
 .../test/CodeGen/attr-counted-by-pr88931.cpp  | 21 ++
 3 files changed, 57 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/CodeGen/attr-counted-by-pr88931.c
 create mode 100644 clang/test/CodeGen/attr-counted-by-pr88931.cpp

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index a05874e63c73c2..bee12c4469e7f7 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -829,6 +829,9 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
   unsigned FieldNo = 0;
   bool IsUnion = RD->isUnion();
 
+  if (RD->isImplicit())
+return nullptr;
+
   for (const Decl *D : RD->decls()) {
 if (const auto *Field = dyn_cast(D);
 Field && (Name.empty() || Field->getNameAsString() == Name) &&
@@ -844,7 +847,17 @@ const FieldDecl 
*CodeGenFunction::FindFlexibleArrayMemberField(
   if (const FieldDecl *Field =
   FindFlexibleArrayMemberField(Ctx, Record, Name, Offset)) {
 const ASTRecordLayout  = Ctx.getASTRecordLayout(RD);
-Offset += Layout.getFieldOffset(FieldNo);
+if (Layout.getFieldCount()) {
+  // A struct that holds only an inner struct won't have any fields. 
E.g.
+  //
+  // struct foo {
+  // struct bar {
+  // int count;
+  // int array[];
+  // };
+  // };
+  Offset += Layout.getFieldOffset(FieldNo);
+}
 return Field;
   }
 
diff --git a/clang/test/CodeGen/attr-counted-by-pr88931.c 
b/clang/test/CodeGen/attr-counted-by-pr88931.c
new file mode 100644
index 00..baa1bbc8397456
--- /dev/null
+++ b/clang/test/CodeGen/attr-counted-by-pr88931.c
@@ -0,0 +1,22 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 4
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 
-Wno-missing-declarations -emit-llvm -o - %s | FileCheck %s
+
+struct foo {
+  struct bar {
+int count;
+int array[] __attribute__((counted_by(count)));
+  };
+};
+
+void init(void * __attribute__((pass_dynamic_object_size(0;
+
+// CHECK-LABEL: define dso_local void @test1(
+// CHECK-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:[[ARRAY:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 4
+// CHECK-NEXT:tail call void @init(ptr noundef nonnull [[ARRAY]], i64 
noundef -1) #[[ATTR2:[0-9]+]]
+// CHECK-NEXT:ret void
+//
+void test1(struct bar *p) {
+  init(p->array);
+}
diff --git a/clang/test/CodeGen/attr-counted-by-pr88931.cpp 
b/clang/test/CodeGen/attr-counted-by-pr88931.cpp
new file mode 100644
index 00..2a8cc1d07e50d9
--- /dev/null
+++ b/clang/test/CodeGen/attr-counted-by-pr88931.cpp
@@ -0,0 +1,21 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 4
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -Wall -emit-llvm -o - 
%s | FileCheck %s
+
+struct foo {
+  struct bar {
+int array[];
+bar();
+  };
+};
+
+void init(void * __attribute__((pass_dynamic_object_size(0;
+
+// CHECK-LABEL: define dso_local void @_ZN3foo3barC1Ev(
+// CHECK-SAME: ptr noundef nonnull align 4 dereferenceable(1) [[THIS:%.*]]) 
unnamed_addr #[[ATTR0:[0-9]+]] align 2 {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:tail call void @_Z4initPvU25pass_dynamic_object_size0(ptr 
noundef nonnull [[THIS]], i64 noundef -1) #[[ATTR2:[0-9]+]]
+// CHECK-NEXT:ret void
+//
+foo::bar::bar() {
+  init(array);
+}

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)

2024-04-15 Thread Bill Wendling via cfe-commits


@@ -1822,28 +1822,101 @@ void WriteSemanticSpellingSwitch(const std::string 
,
   OS << "  }\n";
 }
 
+enum class LateAttrParseKind { Never = 0, Always = 1, ExperimentalOnly = 2 };
+
+static LateAttrParseKind getLateAttrParseKind(const Record *Attr) {
+  // This function basically does
+  // `Attr->getValueAsDef("LateParsed")->getValueAsInt("Mode")` but does
+  // a bunch of sanity checking to ensure that
+  // `LateAttrParseMode` in `Attr.td` is in sync with the `LateAttrParseKind`
+  // enum in this source file.
+
+  static constexpr StringRef LateParsedStr = "LateParsed";
+  static constexpr StringRef LateAttrParseKindStr = "LateAttrParseKind";
+  static constexpr StringRef KindFieldStr = "Kind";
+
+  auto *LAPK = Attr->getValueAsDef(LateParsedStr);
+
+  // Typecheck the `LateParsed` field.
+  SmallVector SuperClasses;
+  LAPK->getDirectSuperClasses(SuperClasses);
+  if (SuperClasses.size() != 1)
+PrintFatalError(Attr, "Field `" + llvm::Twine(LateParsedStr) +
+  "`should only have one super class");
+
+  if (SuperClasses[0]->getName().compare(LateAttrParseKindStr) != 0)
+PrintFatalError(Attr, "Field `" + llvm::Twine(LateParsedStr) +
+  "`should only have type `" +
+  llvm::Twine(LateAttrParseKindStr) +
+  "` but found type `" +
+  SuperClasses[0]->getName() + "`");
+
+  // Get Kind and verify the enum name matches the name in `Attr.td`.
+  unsigned Kind = LAPK->getValueAsInt(KindFieldStr);
+  switch (LateAttrParseKind(Kind)) {
+#define CASE(X)
\
+  case LateAttrParseKind::X:   
\
+if (LAPK->getName().compare("LateAttrParse" #X) != 0) {
\
+  PrintFatalError(Attr,
\
+  "Field `" + llvm::Twine(LateParsedStr) + "` set to `" +  
\
+  LAPK->getName() +
\
+  "` but this converts to `LateAttrParseKind::" +  
\
+  llvm::Twine(#X) + "`");  
\
+}  
\
+return LateAttrParseKind::X;
+
+CASE(Never)
+CASE(Always)
+CASE(ExperimentalOnly)
+#undef CASE
+  }
+
+  // The Kind value is completely invalid
+  auto KindValueStr = llvm::utostr(Kind);
+  PrintFatalError(Attr, "Field `" + llvm::Twine(LateParsedStr) + "` set to `" +
+LAPK->getName() + "` has unexpected `" +
+llvm::Twine(KindFieldStr) + "` value of " +
+KindValueStr);
+}
+
 // Emits the LateParsed property for attributes.
-static void emitClangAttrLateParsedList(RecordKeeper , raw_ostream 
) {
-  OS << "#if defined(CLANG_ATTR_LATE_PARSED_LIST)\n";
-  std::vector Attrs = Records.getAllDerivedDefinitions("Attr");
+static void emitClangAttrLateParsedListImpl(RecordKeeper ,
+raw_ostream ,
+LateAttrParseKind LateParseMode) {
+  std::vector Attrs = Records.getAllDerivedDefinitions("Attr");
 
   for (const auto *Attr : Attrs) {
-bool LateParsed = Attr->getValueAsBit("LateParsed");
+auto LateParsed = getLateAttrParseKind(Attr);

bwendling wrote:

Probably should combine this in the if statement. Also, please don't use `auto` 
if the type isn't obvious.

https://github.com/llvm/llvm-project/pull/88596
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [BoundsSafety] WIP: Make 'counted_by' work for pointer fields; late parsing for 'counted_by' on decl attr position (PR #87596)

2024-04-12 Thread Bill Wendling via cfe-commits


@@ -4997,7 +5087,11 @@ void Parser::ParseStructUnionBody(SourceLocation 
RecordLoc,
 
   ParsedAttributes attrs(AttrFactory);
   // If attributes exist after struct contents, parse them.
-  MaybeParseGNUAttributes(attrs);
+  MaybeParseGNUAttributes(attrs, );
+
+  assert(!getLangOpts().CPlusPlus);

bwendling wrote:

Is it possible to combine C++'s late parsing with your implementation? Or is 
there little overlap?

https://github.com/llvm/llvm-project/pull/87596
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [BoundsSafety] WIP: Make 'counted_by' work for pointer fields; late parsing for 'counted_by' on decl attr position (PR #87596)

2024-04-12 Thread Bill Wendling via cfe-commits




bwendling wrote:

FYI: I'm planning on having a separate 
`test/Sema/attr-counted-by-for-pointers.c` test file for pointers and rename 
the current file something like 
`test/Sema/attr-counted-by-for-flexible-array-members.c`.

https://github.com/llvm/llvm-project/pull/87596
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [BoundsSafety] WIP: Make 'counted_by' work for pointer fields; late parsing for 'counted_by' on decl attr position (PR #87596)

2024-04-12 Thread Bill Wendling via cfe-commits


@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#define __counted_by(f)  __attribute__((counted_by(f)))
+
+struct size_unknown;
+
+struct at_pointer {
+  int count;
+  struct size_unknown *__counted_by(count) buf; // 
expected-error{{'counted_by' cannot be applied to an sized type}}

bwendling wrote:

This should be fine, because `count` is declared before useunless I'm 
getting type attributes confused with field attributes.. Also, there's a 
grammar-o in the message: `to _an_ sized type`.

https://github.com/llvm/llvm-project/pull/87596
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)

2024-04-11 Thread Bill Wendling via cfe-commits

bwendling wrote:

> Forbidding usage in C++ probably avoids the worst of the canonical-type 
> issues, but there's still some potential for weird results. Particularly with 
> type merging; for example, if you write `a ? (wrap_int)x : 1`, is the result 
> a wrapping type?

I had a similar question in the general case: is the annotation contagious?

```
int foo(wrap_int x, int a, int b, int c) {
  if (x + a + b < c)
return 0;
  return 1;
}
```

The `x + a` is checked, but is that result checked when added to `b`?

https://github.com/llvm/llvm-project/pull/86618
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)

2024-04-11 Thread Bill Wendling via cfe-commits

bwendling wrote:

> Hi, I've made some changes and am looking for some more review on this PR:
> 
> * This attribute no longer supports C++ as there are other solutions for that 
> language [1](https://godbolt.org/z/7qPve6cWq) that allow for the same 
> fine-grained wrapping control without changing syntax patterns.
> * Add bypass for implicit-(un)signed-integer-truncation sanitizers
> * Rebased onto 
> [eec41d2](https://github.com/llvm/llvm-project/commit/eec41d2f8d81b546d7b97648cca6b2d656104bd3)

Does this list address all of @efriedma-quic's concerns about adding an 
attribute to a type?

https://github.com/llvm/llvm-project/pull/86618
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [lldb] [NFC][Clang] Improve const correctness for IdentifierInfo (PR #79365)

2024-04-10 Thread Bill Wendling via cfe-commits

https://github.com/bwendling closed 
https://github.com/llvm/llvm-project/pull/79365
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][objectsize] Generate object size calculation for sub-objects (PR #86858)

2024-04-10 Thread Bill Wendling via cfe-commits

bwendling wrote:

Friendly ping.

https://github.com/llvm/llvm-project/pull/86858
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][objectsize] Generate object size calculation for sub-objects (PR #86858)

2024-03-27 Thread Bill Wendling via cfe-commits

https://github.com/bwendling created 
https://github.com/llvm/llvm-project/pull/86858

The second argument of __builtin_dynamic_object_size controls whether it
returns the size of the whole object or the closest surrounding object.
For this struct:

  struct s {
int  foo;
char bar[2][40];
int  baz;
int  qux;
  };

  int main(int argc, char **argv) {
struct s f;

  #define report(x) printf(#x ": %zu\n", x)

argc = 1;
report(__builtin_dynamic_object_size(f.bar[argc], 0));
report(__builtin_dynamic_object_size(f.bar[argc], 1));
return 0;
  }

should return:

  __builtin_dynamic_object_size(f.bar[argc], 0): 48
  __builtin_dynamic_object_size(f.bar[argc], 1): 40

determined by the least significant bit of the TYPE.

The LLVM IR isn't sufficient to determine what could be considered a
"sub-object". However, the front-end does have enough information to
determine the size of a sub-object and the offset into that sub-object.

Therefore to convert the intrinsic into a calculation in the front-end
so that we can avoid the information issue.

>From 31af119d614ef2108b5404f9c9387ec45aa1bfef Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Thu, 21 Mar 2024 15:07:31 -0700
Subject: [PATCH 1/5] [Clang][objectsize] Generate object size calculation for
 sub-objects

The second argument of __builtin_dynamic_object_size controls whether it
returns the size of the whole object or the closest surrounding object.
For this struct:

  struct s {
int  foo;
char bar[2][40];
int  baz;
int  qux;
  };

  int main(int argc, char **argv) {
struct s f;

  #define report(x) printf(#x ": %zu\n", x)

argc = 1;
report(__builtin_dynamic_object_size(f.bar[argc], 0));
report(__builtin_dynamic_object_size(f.bar[argc], 1));
return 0;
  }

should return:

  __builtin_dynamic_object_size(f.bar[argc], 0): 48
  __builtin_dynamic_object_size(f.bar[argc], 1): 40

determined by the least significant bit of the TYPE.

The LLVM IR isn't sufficient to determine what could be considered a
"sub-object". However, the front-end does have enough information to
determine the size of a sub-object and the offset into that sub-object.

We try therefore to convert the intrinsic into a calculation in the
front-end so that we can avoid the information issue..
---
 clang/lib/CodeGen/CGBuiltin.cpp | 138 +-
 clang/lib/CodeGen/CodeGenFunction.h |   6 +
 clang/test/CodeGen/object-size-sub-object.c | 280 
 3 files changed, 418 insertions(+), 6 deletions(-)
 create mode 100644 clang/test/CodeGen/object-size-sub-object.c

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 2eaceeba617700..be055f34c4492d 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -26,6 +26,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/OSLog.h"
 #include "clang/AST/OperationKinds.h"
+#include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/TargetBuiltins.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/TargetOptions.h"
@@ -1052,6 +1053,128 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr 
*E, unsigned Type,
   return Builder.CreateSelect(Cmp, Res, ConstantInt::get(ResType, 0, 
IsSigned));
 }
 
+namespace {
+
+struct ObjectSizeVisitor
+: public ConstStmtVisitor {
+  const Expr *Visit(const Expr *E) {
+return ConstStmtVisitor::Visit(E);
+  }
+
+  const Expr *VisitStmt(const Stmt *S) { return nullptr; }
+
+  const Expr *VisitDeclRefExpr(const DeclRefExpr *E) { return E; }
+  const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
+  const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { return E; 
}
+
+  const Expr *VisitCastExpr(const CastExpr *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitParenExpr(const ParenExpr *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryAddrOf(const clang::UnaryOperator *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryDeref(const clang::UnaryOperator *E) {
+return Visit(E->getSubExpr());
+  }
+};
+
+} // end anonymous namespace
+
+/// tryToCalculateSubObjectSize - It may be possible to calculate the
+/// sub-object size of an array and skip the generation of the llvm.objectsize
+/// intrinsic. This avoids the complication in conveying the sub-object's
+/// information to the backend. This calculation works for an N-dimentional
+/// array.
+///
+/// Note that this function supports only Row-Major arrays. The generalized
+/// calculation of the offset of an element in Row-Major form:
+///
+/// .-  -.
+///   d |d   |
+///  ---|  - |
+/// offset = \  |   | |  |
+///  /  |   | |  N_j |  m_i
+///  ---|   | |  |
+/// i = 1   | j = i + 1  |
+/// `-  -'
+///
+/// where d is the number of dimensions; m_i is the 

[clang] [Clang] Convert __builtin_dynamic_object_size into a calculation (PR #80256)

2024-03-19 Thread Bill Wendling via cfe-commits

https://github.com/bwendling updated 
https://github.com/llvm/llvm-project/pull/80256

>From d08abc7a9454557ffa43fc14611177f2c4e7fba4 Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Wed, 31 Jan 2024 13:07:53 -0800
Subject: [PATCH] [Clang] Convert __builtin_dynamic_object_size into a
 calculation

If we're able to, we convert a call to __builtin_dynamic_object_size
into a calculation. This is a cleaner implementation, and has the
potential to improve optimizations and, especially, inlining, because
optimizing around an 'llvm.objectsize' call isn't trivial.
---
 clang/lib/CodeGen/CGBuiltin.cpp | 155 ++--
 clang/lib/CodeGen/CGExpr.cpp|  13 +--
 clang/lib/CodeGen/CodeGenFunction.h |   6 ++
 3 files changed, 162 insertions(+), 12 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index f3ab5ad7b08ec8..2c109821de43cd 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -26,6 +26,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/OSLog.h"
 #include "clang/AST/OperationKinds.h"
+#include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/TargetBuiltins.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/TargetOptions.h"
@@ -1051,6 +1052,145 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr 
*E, unsigned Type,
   return Builder.CreateSelect(Cmp, Res, ConstantInt::get(ResType, 0, 
IsSigned));
 }
 
+namespace {
+
+/// \p StructBaseExpr returns the base \p Expr with a structure or union type.
+struct StructBaseExpr : public ConstStmtVisitor {
+  StructBaseExpr() = default;
+
+  
//======//
+  //Visitor Methods
+  
//======//
+
+  const Expr *VisitStmt(const Stmt *S) { return nullptr; }
+
+  const Expr *Visit(const Expr *E) {
+QualType Ty = E->getType();
+if (Ty->isStructureType() || Ty->isUnionType())
+  return E;
+
+return ConstStmtVisitor::Visit(E);
+  }
+
+  const Expr *VisitDeclRefExpr(const DeclRefExpr *E) { return E; }
+
+  const Expr *VisitMemberExpr(const MemberExpr *E) {
+return Visit(E->getBase());
+  }
+  const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+return Visit(E->getBase());
+  }
+  const Expr *VisitCastExpr(const CastExpr *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitParenExpr(const ParenExpr *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryAddrOf(const clang::UnaryOperator *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryDeref(const clang::UnaryOperator *E) {
+return Visit(E->getSubExpr());
+  }
+};
+
+} // end anonymous namespace
+
+/// The offset of a field from the beginning of the record.
+llvm::Value *
+CodeGenFunction::tryEmitObjectSizeCalculation(const Expr *E, unsigned Type,
+  llvm::IntegerType *ResType) {
+  if ((Type & 0x01) != 0)
+// We handle only the whole object size.
+return nullptr;
+
+  E = E->IgnoreParenImpCasts();
+
+  const Expr *Base = StructBaseExpr().Visit(E);
+  if (!Base)
+return nullptr;
+
+  const RecordDecl *RD = Base->getType()->getAsRecordDecl();
+  if (!RD)
+return nullptr;
+
+  // Get the full size of the struct.
+  ASTContext  = getContext();
+  const RecordDecl *OuterRD = RD->getOuterLexicalRecordContext();
+  const clang::Type *RT = OuterRD->getTypeForDecl();
+  CharUnits RecordSize = Ctx.getTypeSizeInChars(RT);
+
+  Value *Res = nullptr;
+
+  if (const auto *U = dyn_cast(E);
+  U && (U->getOpcode() == UO_AddrOf || U->getOpcode() == UO_Deref))
+E = U->getSubExpr()->IgnoreParenImpCasts();
+
+  if (const auto *ASE = dyn_cast(E)) {
+const Expr *Idx = ASE->getIdx();
+Base = ASE->getBase()->IgnoreParenImpCasts();
+
+if (const auto *ME = dyn_cast(Base);
+ME && ME->getType()->isConstantArrayType()) {
+  // The simple case:
+  //
+  // struct s {
+  // int arr[42];
+  // char c;
+  // /* others */
+  // };
+  //
+  // __builtin_dynamic_object_size(>arr[idx], 0);
+  //
+  // We can translate the __builtin_dynamic_object_call into:
+  //
+  // sizeof(struct s) - offsetof(arr) - (idx * sizeof(int))
+  //
+  bool IsSigned = Idx->getType()->isSignedIntegerType();
+  Value *IdxInst = EmitAnyExprToTemp(Idx).getScalarVal();
+  IdxInst = Builder.CreateIntCast(IdxInst, ResType, IsSigned);
+
+  const ConstantArrayType *CAT = cast(ME->getType());
+  CharUnits ElemSize = Ctx.getTypeSizeInChars(CAT->getElementType());
+  Value *ElemSizeInst = Builder.getInt32(ElemSize.getQuantity());
+  ElemSizeInst = Builder.CreateIntCast(ElemSizeInst, ResType, IsSigned);
+
+  // idx * sizeof()
+  Res = Builder.CreateMul(IdxInst, ElemSizeInst, "", !IsSigned, IsSigned);
+
+ 

[clang] [NFC][IdentifierInfo] Use llvm::Bitfield for the bitfield (PR #79366)

2024-03-19 Thread Bill Wendling via cfe-commits

https://github.com/bwendling closed 
https://github.com/llvm/llvm-project/pull/79366
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [Clang] Correct __builtin_dynamic_object_size for subobject types (PR #83204)

2024-03-12 Thread Bill Wendling via cfe-commits


@@ -26996,18 +26996,38 @@ class, structure, array, or other object.
 Arguments:
 ""
 
-The ``llvm.objectsize`` intrinsic takes four arguments. The first argument is a
-pointer to or into the ``object``. The second argument determines whether
-``llvm.objectsize`` returns 0 (if true) or -1 (if false) when the object size 
is
-unknown. The third argument controls how ``llvm.objectsize`` acts when ``null``
-in address space 0 is used as its pointer argument. If it's ``false``,
-``llvm.objectsize`` reports 0 bytes available when given ``null``. Otherwise, 
if
-the ``null`` is in a non-zero address space or if ``true`` is given for the
-third argument of ``llvm.objectsize``, we assume its size is unknown. The 
fourth
-argument to ``llvm.objectsize`` determines if the value should be evaluated at
-runtime.
+The ``llvm.objectsize`` intrinsic takes six arguments:
+
+- The first argument is a pointer to or into the ``object``.
+- The second argument controls which value to return when the size is unknown:
+
+  - If it's ``false``, ``llvm.objectsize`` returns ``-1``.
+  - If it's ``true``, ``llvm.objectsize`` returns ``0``.
+
+- The third argument controls how ``llvm.objectsize`` acts when ``null`` in
+  address space 0 is used as its pointer argument:
+
+  - If it's ``false``, ``llvm.objectsize`` reports 0 bytes available when given
+``null``.
+  - If it's ``true``, or the ``null`` pointer is in a non-zero address space,
+the size is assumed to be unknown.
+
+- The fourth argument to ``llvm.objectsize`` determines if the value should be
+  evaluated at runtime.
+- The fifth argument controls which size ``llvm.objectsize`` returns:
+
+  - If it's ``false``, ``llvm.objectsize`` returns the size of the closest
+surrounding subobject.
+  - If it's ``true``, ``llvm.objectsize`` returns the size of the whole object.
+
+- If non-zero, the sixth and seventh arguments encode the size and offset
+  information, respectively, of the original subobject's layout and is used
+  when the fifth argument is ``false``.
+- The seventh argument encodes the offset information of the original
+  subobject's layout and is used when the fifth argument is ``false``.

bwendling wrote:

> in some simple test cases it does appear to work.

Please don't be insulting. I didn't just run a couple of "simple" tests and 
called it a day. I had many rather convoluted examples and they all worked.

> Sorry, that was a typo in my example: the call in h() should be f().

Okay. This patch generates the correct answer (modified so it's calculated by 
the middle end):

```
$  clang -O2 ~/llvm/a.c && ./a.out
&((char *)>n)[idx]:
__builtin_dynamic_object_size(&((char *)>n)[idx], 1) = 3

&((char *)>n)[idx]:
__builtin_dynamic_object_size(&((char *)>n)[idx], 1) = 3
```

> I mean, pass a pointer to the start of the subobject. For example, for 
> p->arr[i], you'd pass in >arr.

I don't think that's necessary. If we're given the original size and the middle 
end is calculating the final size, it may be sufficient to ignore the offset 
all together for sub-objects. I'll see if it works.

https://github.com/llvm/llvm-project/pull/83204
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [Clang] Correct __builtin_dynamic_object_size for subobject types (PR #83204)

2024-03-12 Thread Bill Wendling via cfe-commits


@@ -26996,18 +26996,38 @@ class, structure, array, or other object.
 Arguments:
 ""
 
-The ``llvm.objectsize`` intrinsic takes four arguments. The first argument is a
-pointer to or into the ``object``. The second argument determines whether
-``llvm.objectsize`` returns 0 (if true) or -1 (if false) when the object size 
is
-unknown. The third argument controls how ``llvm.objectsize`` acts when ``null``
-in address space 0 is used as its pointer argument. If it's ``false``,
-``llvm.objectsize`` reports 0 bytes available when given ``null``. Otherwise, 
if
-the ``null`` is in a non-zero address space or if ``true`` is given for the
-third argument of ``llvm.objectsize``, we assume its size is unknown. The 
fourth
-argument to ``llvm.objectsize`` determines if the value should be evaluated at
-runtime.
+The ``llvm.objectsize`` intrinsic takes six arguments:
+
+- The first argument is a pointer to or into the ``object``.
+- The second argument controls which value to return when the size is unknown:
+
+  - If it's ``false``, ``llvm.objectsize`` returns ``-1``.
+  - If it's ``true``, ``llvm.objectsize`` returns ``0``.
+
+- The third argument controls how ``llvm.objectsize`` acts when ``null`` in
+  address space 0 is used as its pointer argument:
+
+  - If it's ``false``, ``llvm.objectsize`` reports 0 bytes available when given
+``null``.
+  - If it's ``true``, or the ``null`` pointer is in a non-zero address space,
+the size is assumed to be unknown.
+
+- The fourth argument to ``llvm.objectsize`` determines if the value should be
+  evaluated at runtime.
+- The fifth argument controls which size ``llvm.objectsize`` returns:
+
+  - If it's ``false``, ``llvm.objectsize`` returns the size of the closest
+surrounding subobject.
+  - If it's ``true``, ``llvm.objectsize`` returns the size of the whole object.
+
+- If non-zero, the sixth and seventh arguments encode the size and offset
+  information, respectively, of the original subobject's layout and is used
+  when the fifth argument is ``false``.
+- The seventh argument encodes the offset information of the original
+  subobject's layout and is used when the fifth argument is ``false``.

bwendling wrote:

You really need to make up your mind. First you tell me that I can't use LLVM's 
IR to determine the subobject, even though I did and it worked just fine, and 
now you're saying that I can't use the front-end's knowledge about the 
structure. In your example, you've explicitly lied to the compiler about the 
types being passed in. Unlike in GCC, we don't do any inlining in the 
front-end, so we can't properly handle this. I have no clue what you mean by 
pass a "pointer to `p->n` to the intrinsic" as that's already the first 
argument in the intrinsic.

https://github.com/llvm/llvm-project/pull/83204
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [Clang] Correct __builtin_dynamic_object_size for subobject types (PR #83204)

2024-03-12 Thread Bill Wendling via cfe-commits


@@ -26996,18 +26996,38 @@ class, structure, array, or other object.
 Arguments:
 ""
 
-The ``llvm.objectsize`` intrinsic takes four arguments. The first argument is a
-pointer to or into the ``object``. The second argument determines whether
-``llvm.objectsize`` returns 0 (if true) or -1 (if false) when the object size 
is
-unknown. The third argument controls how ``llvm.objectsize`` acts when ``null``
-in address space 0 is used as its pointer argument. If it's ``false``,
-``llvm.objectsize`` reports 0 bytes available when given ``null``. Otherwise, 
if
-the ``null`` is in a non-zero address space or if ``true`` is given for the
-third argument of ``llvm.objectsize``, we assume its size is unknown. The 
fourth
-argument to ``llvm.objectsize`` determines if the value should be evaluated at
-runtime.
+The ``llvm.objectsize`` intrinsic takes six arguments:
+
+- The first argument is a pointer to or into the ``object``.
+- The second argument controls which value to return when the size is unknown:
+
+  - If it's ``false``, ``llvm.objectsize`` returns ``-1``.
+  - If it's ``true``, ``llvm.objectsize`` returns ``0``.
+
+- The third argument controls how ``llvm.objectsize`` acts when ``null`` in
+  address space 0 is used as its pointer argument:
+
+  - If it's ``false``, ``llvm.objectsize`` reports 0 bytes available when given
+``null``.
+  - If it's ``true``, or the ``null`` pointer is in a non-zero address space,
+the size is assumed to be unknown.
+
+- The fourth argument to ``llvm.objectsize`` determines if the value should be
+  evaluated at runtime.
+- The fifth argument controls which size ``llvm.objectsize`` returns:
+
+  - If it's ``false``, ``llvm.objectsize`` returns the size of the closest
+surrounding subobject.
+  - If it's ``true``, ``llvm.objectsize`` returns the size of the whole object.
+
+- If non-zero, the sixth and seventh arguments encode the size and offset
+  information, respectively, of the original subobject's layout and is used
+  when the fifth argument is ``false``.
+- The seventh argument encodes the offset information of the original
+  subobject's layout and is used when the fifth argument is ``false``.

bwendling wrote:

I'm not passing a difference between two pointers; it's the offset from the 
start of the outermost `RecordDecl` to the object. The LLVM intrinsic 
recursively walks back through the instructions (that define the pointer) to 
try to calculate the value. It's rather convoluted and hard to read, because it 
involves two visitor classes called one from another. Eventually, it returns a 
Size / Offset pair (Offset from the start of the structure). At that point, I 
use the extra information I added to determine if those values are within the 
range of the sub-object. If it's outside of that range, I return 0. Otherwise, 
I calculate the remaining size after adjusting the offset (i.e. the offset is 
adjusted to be from the beginning of the sub-object rather than the start of 
the structure).

https://github.com/llvm/llvm-project/pull/83204
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [Clang] Correct __builtin_dynamic_object_size for subobject types (PR #83204)

2024-03-11 Thread Bill Wendling via cfe-commits


@@ -1052,11 +1053,143 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const 
Expr *E, unsigned Type,
   return Builder.CreateSelect(Cmp, Res, ConstantInt::get(ResType, 0, 
IsSigned));
 }
 
+namespace {
+
+/// SubobjectFinder - A simple visitor to find the "sub-object" pointed to by a
+/// __builtin_dynamic_object_size call. Information gathered from the
+/// sub-object is used by the back-end to determine the correct size when the
+/// 'TYPE' of the __bdos call has the least significant bit set (i.e. asking
+/// for the sub-object size).
+///
+/// The expectation is that we'll eventually hit one of three expression types:
+///
+///   1. DeclRefExpr - This is the expression for the base of the structure.
+///   2. MemberExpr - This is the field in the structure.
+///   3. CompoundLiteralExpr - This is for people who create something
+///  heretical like (struct foo has a flexible array member):
+///
+///(struct foo){ 1, 2 }.blah[idx];
+///
+/// All other expressions can be correctly handled with the current code.
+struct SubobjectFinder
+: public ConstStmtVisitor {
+  SubobjectFinder() = default;
+
+  
//======//
+  //Visitor Methods
+  
//======//
+
+  const Expr *VisitStmt(const Stmt *S) { return nullptr; }
+
+  const Expr *VisitDeclRefExpr(const DeclRefExpr *E) { return E; }
+  const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
+  const Expr *VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
+return E;
+  }
+
+  const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+return Visit(E->getBase());
+  }
+  const Expr *VisitCastExpr(const CastExpr *E) {

bwendling wrote:

It seems to. See https://godbolt.org/z/4xaY4191o for an example (the `&((char 
*))[argc]` example looks through them.

https://github.com/llvm/llvm-project/pull/83204
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [Clang] Correct __builtin_dynamic_object_size for subobject types (PR #83204)

2024-03-11 Thread Bill Wendling via cfe-commits


@@ -26996,18 +26996,38 @@ class, structure, array, or other object.
 Arguments:
 ""
 
-The ``llvm.objectsize`` intrinsic takes four arguments. The first argument is a
-pointer to or into the ``object``. The second argument determines whether
-``llvm.objectsize`` returns 0 (if true) or -1 (if false) when the object size 
is
-unknown. The third argument controls how ``llvm.objectsize`` acts when ``null``
-in address space 0 is used as its pointer argument. If it's ``false``,
-``llvm.objectsize`` reports 0 bytes available when given ``null``. Otherwise, 
if
-the ``null`` is in a non-zero address space or if ``true`` is given for the
-third argument of ``llvm.objectsize``, we assume its size is unknown. The 
fourth
-argument to ``llvm.objectsize`` determines if the value should be evaluated at
-runtime.
+The ``llvm.objectsize`` intrinsic takes six arguments:
+
+- The first argument is a pointer to or into the ``object``.
+- The second argument controls which value to return when the size is unknown:
+
+  - If it's ``false``, ``llvm.objectsize`` returns ``-1``.
+  - If it's ``true``, ``llvm.objectsize`` returns ``0``.
+
+- The third argument controls how ``llvm.objectsize`` acts when ``null`` in
+  address space 0 is used as its pointer argument:
+
+  - If it's ``false``, ``llvm.objectsize`` reports 0 bytes available when given
+``null``.
+  - If it's ``true``, or the ``null`` pointer is in a non-zero address space,
+the size is assumed to be unknown.
+
+- The fourth argument to ``llvm.objectsize`` determines if the value should be
+  evaluated at runtime.
+- The fifth argument controls which size ``llvm.objectsize`` returns:
+
+  - If it's ``false``, ``llvm.objectsize`` returns the size of the closest
+surrounding subobject.
+  - If it's ``true``, ``llvm.objectsize`` returns the size of the whole object.
+
+- If non-zero, the sixth and seventh arguments encode the size and offset
+  information, respectively, of the original subobject's layout and is used
+  when the fifth argument is ``false``.
+- The seventh argument encodes the offset information of the original
+  subobject's layout and is used when the fifth argument is ``false``.

bwendling wrote:

A lot of your review seems to be based on this differing of opinion of what to 
do when indexing outside of the object currently being pointed to. Let's get 
this sorted out before I make changes...

https://github.com/llvm/llvm-project/pull/83204
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [Clang] Correct __builtin_dynamic_object_size for subobject types (PR #83204)

2024-03-11 Thread Bill Wendling via cfe-commits


@@ -26996,18 +26996,38 @@ class, structure, array, or other object.
 Arguments:
 ""
 
-The ``llvm.objectsize`` intrinsic takes four arguments. The first argument is a
-pointer to or into the ``object``. The second argument determines whether
-``llvm.objectsize`` returns 0 (if true) or -1 (if false) when the object size 
is
-unknown. The third argument controls how ``llvm.objectsize`` acts when ``null``
-in address space 0 is used as its pointer argument. If it's ``false``,
-``llvm.objectsize`` reports 0 bytes available when given ``null``. Otherwise, 
if
-the ``null`` is in a non-zero address space or if ``true`` is given for the
-third argument of ``llvm.objectsize``, we assume its size is unknown. The 
fourth
-argument to ``llvm.objectsize`` determines if the value should be evaluated at
-runtime.
+The ``llvm.objectsize`` intrinsic takes six arguments:
+
+- The first argument is a pointer to or into the ``object``.
+- The second argument controls which value to return when the size is unknown:
+
+  - If it's ``false``, ``llvm.objectsize`` returns ``-1``.
+  - If it's ``true``, ``llvm.objectsize`` returns ``0``.
+
+- The third argument controls how ``llvm.objectsize`` acts when ``null`` in
+  address space 0 is used as its pointer argument:
+
+  - If it's ``false``, ``llvm.objectsize`` reports 0 bytes available when given
+``null``.
+  - If it's ``true``, or the ``null`` pointer is in a non-zero address space,
+the size is assumed to be unknown.
+
+- The fourth argument to ``llvm.objectsize`` determines if the value should be
+  evaluated at runtime.
+- The fifth argument controls which size ``llvm.objectsize`` returns:
+
+  - If it's ``false``, ``llvm.objectsize`` returns the size of the closest
+surrounding subobject.
+  - If it's ``true``, ``llvm.objectsize`` returns the size of the whole object.
+
+- If non-zero, the sixth and seventh arguments encode the size and offset
+  information, respectively, of the original subobject's layout and is used
+  when the fifth argument is ``false``.
+- The seventh argument encodes the offset information of the original
+  subobject's layout and is used when the fifth argument is ``false``.

bwendling wrote:

> I think the information you're passing in here isn't quite what we'd want. If 
> I'm reading the code correctly, the offset you're passing in is the field 
> offset relative to the immediately-enclosing record type, which doesn't give 
> us any information about either where the pointer is within the subobject, or 
> where the subobject is within the complete object, so this doesn't seem like 
> it can be enough information to produce a correct result.

That's the information which leads to the correct calculation. If you have a 
pointer like this:

```c
struct S {
  int a;
  char c[234];
  int b;
};

void foo(struct S *ptr) {
  size_t x = __builtin_dynamic_object_size(ptr->a[22], 1);
/* ... */
}
```

the value of `x` should be `0`. See https://godbolt.org/z/4xaY4191o for a list 
of examples that show this behavior (at least in GCC). Notice that this applies 
for the sub-object type only. If the __bdos value is `0`, then your behavior is 
the correct behavior.
   

https://github.com/llvm/llvm-project/pull/83204
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [Clang] Correct __builtin_dynamic_object_size for subobject types (PR #83204)

2024-03-11 Thread Bill Wendling via cfe-commits

bwendling wrote:

Another ping.

https://github.com/llvm/llvm-project/pull/83204
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [Clang] Correct __builtin_dynamic_object_size for subobject types (PR #83204)

2024-03-05 Thread Bill Wendling via cfe-commits

bwendling wrote:

Friendly ping.

https://github.com/llvm/llvm-project/pull/83204
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [Clang] Correct __builtin_dynamic_object_size for subobject types (PR #83204)

2024-02-27 Thread Bill Wendling via cfe-commits

https://github.com/bwendling edited 
https://github.com/llvm/llvm-project/pull/83204
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [Clang] Correct __builtin_dynamic_object_size for subobject types (PR #83204)

2024-02-27 Thread Bill Wendling via cfe-commits

bwendling wrote:

The first PR attempt was here: https://github.com/llvm/llvm-project/pull/78526

It was NACK'ed because it used the LLVM IR representation of the structure, 
which wasn't appropriate. To solve that issue, I chose to expand the 
`llvm.objectsize()` builtin to contain the size and offset of the sub-object, 
which is determined in the front-end.

Note that there are many other things wrong with our 
`__builtin_{dynamic_}object_size` implementations. For one, they perform loads 
of the pointer which isn't necessary and contrary to the idea that the builtins 
don't allow for side-effects. I'll be addressing those issues in future patches.

https://github.com/llvm/llvm-project/pull/83204
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Sanitizer: Support -fwrapv with -fsanitize=signed-integer-overflow (PR #82432)

2024-02-21 Thread Bill Wendling via cfe-commits

https://github.com/bwendling closed 
https://github.com/llvm/llvm-project/pull/82432
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Sanitizer: Support -fwrapv with -fsanitize=signed-integer-overflow (PR #82432)

2024-02-21 Thread Bill Wendling via cfe-commits

https://github.com/bwendling approved this pull request.


https://github.com/llvm/llvm-project/pull/82432
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 7fa8585 - [NFC][clang] Remove trailing whitespaces

2024-02-21 Thread Bill Wendling via cfe-commits

Author: Bill Wendling
Date: 2024-02-21T12:21:35-08:00
New Revision: 7fa8585fdefd98dd73940c74165aa55da1175f02

URL: 
https://github.com/llvm/llvm-project/commit/7fa8585fdefd98dd73940c74165aa55da1175f02
DIFF: 
https://github.com/llvm/llvm-project/commit/7fa8585fdefd98dd73940c74165aa55da1175f02.diff

LOG: [NFC][clang] Remove trailing whitespaces

Added: 


Modified: 
clang/lib/InstallAPI/FileList.cpp

Removed: 




diff  --git a/clang/lib/InstallAPI/FileList.cpp 
b/clang/lib/InstallAPI/FileList.cpp
index baa524db5d7f8f..8a01248659b7d7 100644
--- a/clang/lib/InstallAPI/FileList.cpp
+++ b/clang/lib/InstallAPI/FileList.cpp
@@ -22,13 +22,13 @@ InstallAPI JSON Input Format specification.
 {
   "headers" : [  # Required: Key must exist.
 {# Optional: May contain 0 or more 
header inputs.
-  "path" : "/usr/include/mach-o/dlfn.h", # Required: Path should point to 
destination 
+  "path" : "/usr/include/mach-o/dlfn.h", # Required: Path should point to 
destination
  #   location where 
applicable.
   "type" : "public", # Required: Maps to HeaderType 
for header.
   "language": "c++"  # Optional: Language mode for 
header.
 }
   ],
-  "version" : "3"# Required: Version 3 supports 
language mode 
+  "version" : "3"# Required: Version 3 supports 
language mode
  & project header 
input.
 }
 */



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Convert __builtin_dynamic_object_size into a calculation (PR #80256)

2024-02-05 Thread Bill Wendling via cfe-commits


@@ -1051,6 +1052,145 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr 
*E, unsigned Type,
   return Builder.CreateSelect(Cmp, Res, ConstantInt::get(ResType, 0, 
IsSigned));
 }
 
+namespace {
+
+/// \p StructBaseExpr returns the base \p Expr with a structure or union type.
+struct StructBaseExpr : public ConstStmtVisitor {
+  StructBaseExpr() = default;
+
+  
//======//
+  //Visitor Methods
+  
//======//
+
+  const Expr *VisitStmt(const Stmt *S) { return nullptr; }
+
+  const Expr *Visit(const Expr *E) {
+QualType Ty = E->getType();
+if (Ty->isStructureType() || Ty->isUnionType())
+  return E;
+
+return ConstStmtVisitor::Visit(E);
+  }
+
+  const Expr *VisitDeclRefExpr(const DeclRefExpr *E) { return E; }
+
+  const Expr *VisitMemberExpr(const MemberExpr *E) {
+return Visit(E->getBase());
+  }
+  const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+return Visit(E->getBase());
+  }
+  const Expr *VisitCastExpr(const CastExpr *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitParenExpr(const ParenExpr *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryAddrOf(const clang::UnaryOperator *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryDeref(const clang::UnaryOperator *E) {
+return Visit(E->getSubExpr());
+  }
+};
+
+} // end anonymous namespace
+
+/// The offset of a field from the beginning of the record.
+llvm::Value *
+CodeGenFunction::tryEmitObjectSizeCalculation(const Expr *E, unsigned Type,
+  llvm::IntegerType *ResType) {
+  if ((Type & 0x01) != 0)
+// We handle only the whole object size.
+return nullptr;
+
+  E = E->IgnoreParenImpCasts();
+
+  const Expr *Base = StructBaseExpr().Visit(E);
+  if (!Base)
+return nullptr;
+
+  const RecordDecl *RD = Base->getType()->getAsRecordDecl();
+  if (!RD)
+return nullptr;
+
+  // Get the full size of the struct.
+  ASTContext  = getContext();
+  const RecordDecl *OuterRD = RD->getOuterLexicalRecordContext();
+  const clang::Type *RT = OuterRD->getTypeForDecl();
+  CharUnits RecordSize = Ctx.getTypeSizeInChars(RT);
+
+  Value *Res = nullptr;
+
+  if (const auto *U = dyn_cast(E);
+  U && (U->getOpcode() == UO_AddrOf || U->getOpcode() == UO_Deref))
+E = U->getSubExpr()->IgnoreParenImpCasts();
+
+  if (const auto *ASE = dyn_cast(E)) {
+const Expr *Idx = ASE->getIdx();
+Base = ASE->getBase()->IgnoreParenImpCasts();
+
+if (const auto *ME = dyn_cast(Base);
+ME && ME->getType()->isConstantArrayType()) {
+  // The simple case:
+  //
+  // struct s {
+  // int arr[42];
+  // char c;
+  // /* others */
+  // };
+  //
+  // __builtin_dynamic_object_size(>arr[idx], 0);
+  //
+  // We can translate the __builtin_dynamic_object_call into:
+  //
+  // sizeof(struct s) - offsetof(arr) - (idx * sizeof(int))
+  //

bwendling wrote:

This PR isn't dealing with the sub-object issue from the previous PR. This just 
mimics the current behavior of the intrinsic. I'll be extending it to 
sub-objects further on. The point about type 2 returning zero if the argument 
can point to multiple objects is messy on the GCC side of things. It's there 
because of how GCC's internal representation, but doesn't appear to apply to 
Clang.

https://github.com/llvm/llvm-project/pull/80256
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Convert __builtin_dynamic_object_size into a calculation (PR #80256)

2024-02-05 Thread Bill Wendling via cfe-commits

https://github.com/bwendling edited 
https://github.com/llvm/llvm-project/pull/80256
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Convert __builtin_dynamic_object_size into a calculation (PR #80256)

2024-02-05 Thread Bill Wendling via cfe-commits

https://github.com/bwendling edited 
https://github.com/llvm/llvm-project/pull/80256
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Convert __builtin_dynamic_object_size into a calculation (PR #80256)

2024-02-05 Thread Bill Wendling via cfe-commits


@@ -1051,6 +1052,145 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr 
*E, unsigned Type,
   return Builder.CreateSelect(Cmp, Res, ConstantInt::get(ResType, 0, 
IsSigned));
 }
 
+namespace {
+
+/// \p StructBaseExpr returns the base \p Expr with a structure or union type.
+struct StructBaseExpr : public ConstStmtVisitor {
+  StructBaseExpr() = default;
+
+  
//======//
+  //Visitor Methods
+  
//======//
+
+  const Expr *VisitStmt(const Stmt *S) { return nullptr; }
+
+  const Expr *Visit(const Expr *E) {
+QualType Ty = E->getType();
+if (Ty->isStructureType() || Ty->isUnionType())
+  return E;
+
+return ConstStmtVisitor::Visit(E);
+  }
+
+  const Expr *VisitDeclRefExpr(const DeclRefExpr *E) { return E; }
+
+  const Expr *VisitMemberExpr(const MemberExpr *E) {
+return Visit(E->getBase());
+  }
+  const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+return Visit(E->getBase());
+  }
+  const Expr *VisitCastExpr(const CastExpr *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitParenExpr(const ParenExpr *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryAddrOf(const clang::UnaryOperator *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryDeref(const clang::UnaryOperator *E) {
+return Visit(E->getSubExpr());
+  }

bwendling wrote:

The Visitor is only to get the structure that the member resides in. The thing 
about `__builtin_dynamic_object_size(p, 0)` is that we're not trying to 
calculate what `p` points to, but the size of the struct from p to the end. 
It's counter-intuitive, but it's not (currently) supported to ask `__bdos` the 
size of what `p` points to is.

https://github.com/llvm/llvm-project/pull/80256
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Convert __builtin_dynamic_object_size into a calculation (PR #80256)

2024-01-31 Thread Bill Wendling via cfe-commits

bwendling wrote:

This is a first step in improving our `__bdos` implementation. It doesn't 
address the "sub-object" discussion from the previous PR 
(https://github.com/llvm/llvm-project/pull/78526), that will come later on. 
This patch takes care of a common use of `__bdos` that can't be calculated by 
the front-end (i.e. performing a __bdos on an array with an variable index). 
I'll be expanding the cases this can handle in the future.

https://github.com/llvm/llvm-project/pull/80256
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Convert __builtin_dynamic_object_size into a calculation (PR #80256)

2024-01-31 Thread Bill Wendling via cfe-commits

https://github.com/bwendling created 
https://github.com/llvm/llvm-project/pull/80256

If we're able to, we convert a call to __builtin_dynamic_object_size into a 
calculation. This is a cleaner implementation, and has the potential to improve 
optimizations and, especially, inlining, because optimizing around an 
'llvm.objectsize' call isn't trivial.

>From d08abc7a9454557ffa43fc14611177f2c4e7fba4 Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Wed, 31 Jan 2024 13:07:53 -0800
Subject: [PATCH] [Clang] Convert __builtin_dynamic_object_size into a
 calculation

If we're able to, we convert a call to __builtin_dynamic_object_size
into a calculation. This is a cleaner implementation, and has the
potential to improve optimizations and, especially, inlining, because
optimizing around an 'llvm.objectsize' call isn't trivial.
---
 clang/lib/CodeGen/CGBuiltin.cpp | 155 ++--
 clang/lib/CodeGen/CGExpr.cpp|  13 +--
 clang/lib/CodeGen/CodeGenFunction.h |   6 ++
 3 files changed, 162 insertions(+), 12 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index f3ab5ad7b08ec..2c109821de43c 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -26,6 +26,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/OSLog.h"
 #include "clang/AST/OperationKinds.h"
+#include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/TargetBuiltins.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/TargetOptions.h"
@@ -1051,6 +1052,145 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr 
*E, unsigned Type,
   return Builder.CreateSelect(Cmp, Res, ConstantInt::get(ResType, 0, 
IsSigned));
 }
 
+namespace {
+
+/// \p StructBaseExpr returns the base \p Expr with a structure or union type.
+struct StructBaseExpr : public ConstStmtVisitor {
+  StructBaseExpr() = default;
+
+  
//======//
+  //Visitor Methods
+  
//======//
+
+  const Expr *VisitStmt(const Stmt *S) { return nullptr; }
+
+  const Expr *Visit(const Expr *E) {
+QualType Ty = E->getType();
+if (Ty->isStructureType() || Ty->isUnionType())
+  return E;
+
+return ConstStmtVisitor::Visit(E);
+  }
+
+  const Expr *VisitDeclRefExpr(const DeclRefExpr *E) { return E; }
+
+  const Expr *VisitMemberExpr(const MemberExpr *E) {
+return Visit(E->getBase());
+  }
+  const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+return Visit(E->getBase());
+  }
+  const Expr *VisitCastExpr(const CastExpr *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitParenExpr(const ParenExpr *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryAddrOf(const clang::UnaryOperator *E) {
+return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryDeref(const clang::UnaryOperator *E) {
+return Visit(E->getSubExpr());
+  }
+};
+
+} // end anonymous namespace
+
+/// The offset of a field from the beginning of the record.
+llvm::Value *
+CodeGenFunction::tryEmitObjectSizeCalculation(const Expr *E, unsigned Type,
+  llvm::IntegerType *ResType) {
+  if ((Type & 0x01) != 0)
+// We handle only the whole object size.
+return nullptr;
+
+  E = E->IgnoreParenImpCasts();
+
+  const Expr *Base = StructBaseExpr().Visit(E);
+  if (!Base)
+return nullptr;
+
+  const RecordDecl *RD = Base->getType()->getAsRecordDecl();
+  if (!RD)
+return nullptr;
+
+  // Get the full size of the struct.
+  ASTContext  = getContext();
+  const RecordDecl *OuterRD = RD->getOuterLexicalRecordContext();
+  const clang::Type *RT = OuterRD->getTypeForDecl();
+  CharUnits RecordSize = Ctx.getTypeSizeInChars(RT);
+
+  Value *Res = nullptr;
+
+  if (const auto *U = dyn_cast(E);
+  U && (U->getOpcode() == UO_AddrOf || U->getOpcode() == UO_Deref))
+E = U->getSubExpr()->IgnoreParenImpCasts();
+
+  if (const auto *ASE = dyn_cast(E)) {
+const Expr *Idx = ASE->getIdx();
+Base = ASE->getBase()->IgnoreParenImpCasts();
+
+if (const auto *ME = dyn_cast(Base);
+ME && ME->getType()->isConstantArrayType()) {
+  // The simple case:
+  //
+  // struct s {
+  // int arr[42];
+  // char c;
+  // /* others */
+  // };
+  //
+  // __builtin_dynamic_object_size(>arr[idx], 0);
+  //
+  // We can translate the __builtin_dynamic_object_call into:
+  //
+  // sizeof(struct s) - offsetof(arr) - (idx * sizeof(int))
+  //
+  bool IsSigned = Idx->getType()->isSignedIntegerType();
+  Value *IdxInst = EmitAnyExprToTemp(Idx).getScalarVal();
+  IdxInst = Builder.CreateIntCast(IdxInst, ResType, IsSigned);
+
+  const ConstantArrayType *CAT = cast(ME->getType());
+  CharUnits ElemSize = 

[llvm] [clang] [Clang] Correct __builtin_dynamic_object_size for subobject types (PR #78526)

2024-01-31 Thread Bill Wendling via cfe-commits

https://github.com/bwendling closed 
https://github.com/llvm/llvm-project/pull/78526
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [Clang] Correct __builtin_dynamic_object_size for subobject types (PR #78526)

2024-01-25 Thread Bill Wendling via cfe-commits

bwendling wrote:

> > ```c
> > struct x {
> > int a;
> > char foo[2][40];
> > int b;
> > int c;
> > };
> > 
> > size_t f(struct x *p, int idx) {
> > return __builtin_dynamic_object_size(>foo[idx], 1);
> > }
> > ```
> 
> If I'm following correctly, the return here is 0, 40, or 80, depending on the 
> value of idx? That's not a constant, but the computation is entirely 
> syntactic; it doesn't matter what "p" actually points to. So clang can lower 
> the builtin itself. Currently it doesn't, I think, because all the relevant 
> code is in ExprConstant, but the code could be adapted.

Right. That's what I want to add to the front-end.

> The problem, really, is that we can't easily extend that approach to stuff 
> like the following:
> 
> ```c
> size_t f(struct x *p, int idx) {
> char *c = >foo[idx];
> return __builtin_dynamic_object_size(c, 1);
> }
> ```

Yup! I've been forbidden from doing this in the back-end, so I have to jump 
through hoops now and do partial solutions and hope that it works for most 
people and that when we get it wrong it doesn't hurt security (spoilers: it 
will).

https://github.com/llvm/llvm-project/pull/78526
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [Clang] Correct __builtin_dynamic_object_size for subobject types (PR #78526)

2024-01-24 Thread Bill Wendling via cfe-commits

bwendling wrote:

> > maybe we could add the subtype as part of the llvm.objectsize intrinsic and 
> > use that instead of grappling with the whole object's type
> 
> I'm not sure I follow; if you know the object's type, doesn't that mean you 
> also know its size?

Not necessarily. If you have something like this:

```c
struct x {
int a;
char foo[2][40];
int b;
int c;
};

size_t f(struct x *p, int idx) {
return __builtin_dynamic_object_size(>foo[idx], 1);
}
```

But in general, it would be tricky for something like:

```c
__builtin_dynamic_object_size(&((char *)p)[idx], 1);
```

which I'm not sure if that's something GCC can handle. The documentation says 
that if the pointer can point to multiple objects, then we can return the whole 
object value (or something to that affect).

> > (I don't readily know of any transformation that changes a structure's 
> > layout. Does it exist?)
> 
> Any such transform has to reason about all the uses, so the llvm.objectsize 
> call itself would prevent the transform from happening.

Bon! :-)

https://github.com/llvm/llvm-project/pull/78526
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


  1   2   3   4   5   >