https://github.com/amaanq updated 
https://github.com/llvm/llvm-project/pull/228309

>From 9073e8a8e729ea0bc7c5334b6f888c6d98208312 Mon Sep 17 00:00:00 2001
From: Amaan Qureshi <[email protected]>
Date: Thu, 1 Oct 2026 21:36:18 -0400
Subject: [PATCH] [Clang][counted_by] Load the count through unions by byte
 offset

`getGEPIndicesToField()` indexed into a union with 0 and kept walking the
counter's struct field numbers, but the union's IR type is its largest
member, so the count was loaded from inside that member instead.

In Linux, `landlock_domain` hits this and FORTIFY panics on every nested
`landlock_restrict_self()` on kernel 7.3.0-rc5-next as of this writing.

Assisted-by: Claude
---
 clang/lib/CodeGen/CGExpr.cpp                  | 82 ++++++-------------
 .../CodeGen/attr-counted-by-issue200014.c     | 22 ++---
 .../CodeGen/attr-counted-by-nested-structs.c  |  8 +-
 .../CodeGen/attr-counted-by-union-storage.c   | 34 ++++++++
 clang/test/CodeGen/builtin-counted-by-ref.c   | 32 ++++----
 5 files changed, 89 insertions(+), 89 deletions(-)
 create mode 100644 clang/test/CodeGen/attr-counted-by-union-storage.c

diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 8acf4b95f3e77..48ec98d346fb4 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1064,8 +1064,8 @@ static llvm::Value *getArrayIndexingBound(CodeGenFunction 
&CGF,
 
 /// Returns true if \p Field is reachable from \p RD either as a direct field 
or
 /// through a chain of nested record fields (including anonymous
-/// structs/unions). This mirrors the GEP path that getGEPIndicesToField 
builds,
-/// and is used to identify the right anchor expression in Base.
+/// structs/unions). This mirrors the path that getFieldOffsetInBits walks, and
+/// is used to identify the right anchor expression in Base.
 static bool RecordContainsField(const RecordDecl *RD, const FieldDecl *Field) {
   for (const FieldDecl *FD : RD->fields()) {
     if (FD == Field)
@@ -1192,34 +1192,28 @@ class StructAccessBase
 
 } // end anonymous namespace
 
-using RecIndicesTy = SmallVector<llvm::Value *, 8>;
+/// The offset of a field from the beginning of the record.
+static bool getFieldOffsetInBits(CodeGenFunction &CGF, const RecordDecl *RD,
+                                 const FieldDecl *Field, int64_t &Offset) {
+  ASTContext &Ctx = CGF.getContext();
+  const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
+  unsigned FieldNo = 0;
 
-static bool getGEPIndicesToField(CodeGenFunction &CGF, const RecordDecl *RD,
-                                 const FieldDecl *Field,
-                                 RecIndicesTy &Indices) {
-  const CGRecordLayout &Layout = CGF.CGM.getTypes().getCGRecordLayout(RD);
-  int64_t FieldNo = -1;
   for (const FieldDecl *FD : RD->fields()) {
-    if (!Layout.containsFieldDecl(FD))
-      // This could happen if the field has a struct type that's empty. I don't
-      // know why either.
-      continue;
-
-    FieldNo = Layout.getLLVMFieldNo(FD);
     if (FD == Field) {
-      Indices.emplace_back(CGF.Builder.getInt32(FieldNo));
+      Offset += Layout.getFieldOffset(FieldNo);
       return true;
     }
 
     QualType Ty = FD->getType();
-    if (Ty->isRecordType()) {
-      if (getGEPIndicesToField(CGF, Ty->getAsRecordDecl(), Field, Indices)) {
-        if (RD->isUnion())
-          FieldNo = 0;
-        Indices.emplace_back(CGF.Builder.getInt32(FieldNo));
+    if (Ty->isRecordType())
+      if (getFieldOffsetInBits(CGF, Ty->getAsRecordDecl(), Field, Offset)) {
+        Offset += Layout.getFieldOffset(FieldNo);
         return true;
       }
-    }
+
+    if (!RD->isUnion())
+      ++FieldNo;
   }
 
   return false;
@@ -1228,8 +1222,8 @@ static bool getGEPIndicesToField(CodeGenFunction &CGF, 
const RecordDecl *RD,
 llvm::Value *CodeGenFunction::GetCountedByFieldExprGEP(
     const Expr *Base, const FieldDecl *FAMDecl, const FieldDecl *CountDecl) {
   // Walk Base to find the deepest sub-expression whose struct type 
transitively
-  // contains CountDecl. This is our GEP anchor — getGEPIndicesToField then
-  // builds the field indices from that struct down to CountDecl, handling any
+  // contains CountDecl. This is our GEP anchor — getFieldOffsetInBits then
+  // computes the offset from that struct down to CountDecl, handling any
   // intermediate nesting without requiring us to pre-compute a RecordDecl from
   // Base's type or from CountDecl's parent chain.
   const Expr *StructBase = StructAccessBase(CountDecl).Visit(Base);
@@ -1258,16 +1252,15 @@ llvm::Value *CodeGenFunction::GetCountedByFieldExprGEP(
     return nullptr;
   }
 
-  RecIndicesTy Indices;
-  getGEPIndicesToField(*this, RD, CountDecl, Indices);
-  if (Indices.empty())
+  // Struct GEP indices can't reach a count inside a union, because the union
+  // lowers to its largest member and the indices would walk that one instead.
+  int64_t Offset = 0;
+  if (!getFieldOffsetInBits(*this, RD, CountDecl, Offset))
     return nullptr;
 
-  Indices.push_back(Builder.getInt32(0));
-  CanQualType T = CGM.getContext().getCanonicalTagType(RD);
-  return Builder.CreateInBoundsGEP(ConvertType(T), Res,
-                                   RecIndicesTy(llvm::reverse(Indices)),
-                                   "counted_by.gep");
+  return Builder.CreateInBoundsGEP(
+      Int8Ty, Res, Builder.getSize(getContext().toCharUnitsFromBits(Offset)),
+      "counted_by.gep");
 }
 
 /// This method is typically called in contexts where we can't generate
@@ -5007,33 +5000,6 @@ struct StructFieldAccess
 
 } // end anonymous namespace
 
-/// The offset of a field from the beginning of the record.
-static bool getFieldOffsetInBits(CodeGenFunction &CGF, const RecordDecl *RD,
-                                 const FieldDecl *Field, int64_t &Offset) {
-  ASTContext &Ctx = CGF.getContext();
-  const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
-  unsigned FieldNo = 0;
-
-  for (const FieldDecl *FD : RD->fields()) {
-    if (FD == Field) {
-      Offset += Layout.getFieldOffset(FieldNo);
-      return true;
-    }
-
-    QualType Ty = FD->getType();
-    if (Ty->isRecordType())
-      if (getFieldOffsetInBits(CGF, Ty->getAsRecordDecl(), Field, Offset)) {
-        Offset += Layout.getFieldOffset(FieldNo);
-        return true;
-      }
-
-    if (!RD->isUnion())
-      ++FieldNo;
-  }
-
-  return false;
-}
-
 /// Returns the relative offset difference between \p FD1 and \p FD2.
 /// \code
 ///   offsetof(struct foo, FD1) - offsetof(struct foo, FD2)
diff --git a/clang/test/CodeGen/attr-counted-by-issue200014.c 
b/clang/test/CodeGen/attr-counted-by-issue200014.c
index e514ba1815229..6b672fdee0bf9 100644
--- a/clang/test/CodeGen/attr-counted-by-issue200014.c
+++ b/clang/test/CodeGen/attr-counted-by-issue200014.c
@@ -84,7 +84,7 @@ extern size_t sink;
 // FRONTEND-NEXT:    store i64 [[TMP1]], ptr @sink, align 8
 // FRONTEND-NEXT:    [[FAM1:%.*]] = getelementptr inbounds nuw 
[[STRUCT_ANNOTATED_FLEX]], ptr [[AF]], i32 0, i32 2
 // FRONTEND-NEXT:    [[ARRAYDECAY2:%.*]] = getelementptr inbounds [0 x i8], 
ptr [[FAM1]], i64 0, i64 0
-// FRONTEND-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds 
[[STRUCT_ANNOTATED_FLEX]], ptr [[AF]], i32 0, i32 0
+// FRONTEND-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr 
[[AF]], i64 0
 // FRONTEND-NEXT:    [[COUNTED_BY_LOAD:%.*]] = load i64, ptr 
[[COUNTED_BY_GEP]], align 4
 // FRONTEND-NEXT:    [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = mul nuw i64 
[[COUNTED_BY_LOAD]], 1
 // FRONTEND-NEXT:    [[TMP2:%.*]] = icmp sgt i64 
[[FLEXIBLE_ARRAY_MEMBER_SIZE]], -1
@@ -98,7 +98,7 @@ extern size_t sink;
 // O2-NEXT:    call void @llvm.lifetime.start.p0(ptr nonnull [[AF]]) 
#[[ATTR6:[0-9]+]]
 // O2-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw i8, ptr [[AF]], i64 9
 // O2-NEXT:    [[TMP1:%.*]] = ptrtoint ptr [[TMP0]] to i64
-// O2-NEXT:    store i64 [[TMP1]], ptr @sink, align 8, !tbaa 
[[LONG_TBAA5:![0-9]+]]
+// O2-NEXT:    store i64 [[TMP1]], ptr @sink, align 8, !tbaa 
[[LONG_TBAA6:![0-9]+]]
 // O2-NEXT:    [[TMP2:%.*]] = call i64 @llvm.smax.i64(i64 [[N]], i64 0)
 // O2-NEXT:    call void @llvm.lifetime.end.p0(ptr nonnull [[AF]]) #[[ATTR6]]
 // O2-NEXT:    ret i64 [[TMP2]]
@@ -129,7 +129,7 @@ size_t local_fam(size_t n) {
 // FRONTEND-NEXT:    store i64 [[TMP1]], ptr @sink, align 8
 // FRONTEND-NEXT:    [[FAM1:%.*]] = getelementptr inbounds nuw 
[[STRUCT_ANNOTATED_FLEX]], ptr [[AF]], i32 0, i32 2
 // FRONTEND-NEXT:    [[ARRAYIDX2:%.*]] = getelementptr inbounds [0 x i8], ptr 
[[FAM1]], i64 0, i64 2
-// FRONTEND-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds 
[[STRUCT_ANNOTATED_FLEX]], ptr [[AF]], i32 0, i32 0
+// FRONTEND-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr 
[[AF]], i64 0
 // FRONTEND-NEXT:    [[COUNTED_BY_LOAD:%.*]] = load i64, ptr 
[[COUNTED_BY_GEP]], align 4
 // FRONTEND-NEXT:    [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = mul nuw i64 
[[COUNTED_BY_LOAD]], 1
 // FRONTEND-NEXT:    [[RESULT:%.*]] = sub nuw i64 
[[FLEXIBLE_ARRAY_MEMBER_SIZE]], 2
@@ -145,7 +145,7 @@ size_t local_fam(size_t n) {
 // O2-NEXT:    call void @llvm.lifetime.start.p0(ptr nonnull [[AF]]) #[[ATTR6]]
 // O2-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i8, ptr [[AF]], 
i64 11
 // O2-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[ARRAYIDX]] to i64
-// O2-NEXT:    store i64 [[TMP0]], ptr @sink, align 8, !tbaa [[LONG_TBAA5]]
+// O2-NEXT:    store i64 [[TMP0]], ptr @sink, align 8, !tbaa [[LONG_TBAA6]]
 // O2-NEXT:    [[RESULT:%.*]] = add i64 [[N]], -2
 // O2-NEXT:    [[TMP1:%.*]] = call i64 @llvm.smax.i64(i64 [[RESULT]], i64 0)
 // O2-NEXT:    call void @llvm.lifetime.end.p0(ptr nonnull [[AF]]) #[[ATTR6]]
@@ -185,7 +185,7 @@ size_t local_subscript(size_t n) {
 // O2-NEXT:    call void @llvm.lifetime.start.p0(ptr nonnull [[AF]]) #[[ATTR6]]
 // O2-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw i8, ptr [[AF]], i64 9
 // O2-NEXT:    [[TMP1:%.*]] = ptrtoint ptr [[TMP0]] to i64
-// O2-NEXT:    store i64 [[TMP1]], ptr @sink, align 8, !tbaa [[LONG_TBAA5]]
+// O2-NEXT:    store i64 [[TMP1]], ptr @sink, align 8, !tbaa [[LONG_TBAA6]]
 // O2-NEXT:    call void @llvm.lifetime.end.p0(ptr nonnull [[AF]]) #[[ATTR6]]
 // O2-NEXT:    ret i64 7
 //
@@ -274,7 +274,7 @@ size_t global_addrof(void) {
 // FRONTEND-NEXT:  [[ENTRY:.*:]]
 // FRONTEND-NEXT:    [[FAM:%.*]] = getelementptr inbounds nuw 
[[STRUCT_ANNOTATED_FLEX:%.*]], ptr [[P]], i32 0, i32 2
 // FRONTEND-NEXT:    [[ARRAYDECAY:%.*]] = getelementptr inbounds [0 x i8], ptr 
[[FAM]], i64 0, i64 0
-// FRONTEND-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds 
[[STRUCT_ANNOTATED_FLEX]], ptr [[P]], i32 0, i32 0
+// FRONTEND-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr 
[[P]], i64 0
 // FRONTEND-NEXT:    [[COUNTED_BY_LOAD:%.*]] = load i64, ptr 
[[COUNTED_BY_GEP]], align 4
 // FRONTEND-NEXT:    [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = mul nuw i64 
[[COUNTED_BY_LOAD]], 1
 // FRONTEND-NEXT:    [[TMP0:%.*]] = icmp sgt i64 
[[FLEXIBLE_ARRAY_MEMBER_SIZE]], -1
@@ -300,7 +300,7 @@ size_t ptr_fam(struct annotated_flex *p) {
 // FRONTEND-NEXT:  [[ENTRY:.*:]]
 // FRONTEND-NEXT:    [[FAM:%.*]] = getelementptr inbounds nuw 
[[STRUCT_ANNOTATED_FLEX:%.*]], ptr [[P]], i32 0, i32 2
 // FRONTEND-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr 
[[FAM]], i64 0, i64 3
-// FRONTEND-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds 
[[STRUCT_ANNOTATED_FLEX]], ptr [[P]], i32 0, i32 0
+// FRONTEND-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr 
[[P]], i64 0
 // FRONTEND-NEXT:    [[COUNTED_BY_LOAD:%.*]] = load i64, ptr 
[[COUNTED_BY_GEP]], align 4
 // FRONTEND-NEXT:    [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = mul nuw i64 
[[COUNTED_BY_LOAD]], 1
 // FRONTEND-NEXT:    [[RESULT:%.*]] = sub nuw i64 
[[FLEXIBLE_ARRAY_MEMBER_SIZE]], 3
@@ -340,8 +340,8 @@ size_t ptr_addrof(struct annotated_flex *p) {
     return __builtin_dynamic_object_size(&p->fam, 1);
 }
 //.
-// O2: [[META3:![0-9]+]] = !{!"omnipotent char", [[META4:![0-9]+]], i64 0}
-// O2: [[META4]] = !{!"Simple C/C++ TBAA"}
-// O2: [[LONG_TBAA5]] = !{[[META6:![0-9]+]], [[META6]], i64 0}
-// O2: [[META6]] = !{!"long", [[META3]], i64 0}
+// O2: [[META4:![0-9]+]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0}
+// O2: [[META5]] = !{!"Simple C/C++ TBAA"}
+// O2: [[LONG_TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0}
+// O2: [[META7]] = !{!"long", [[META4]], i64 0}
 //.
diff --git a/clang/test/CodeGen/attr-counted-by-nested-structs.c 
b/clang/test/CodeGen/attr-counted-by-nested-structs.c
index 9f715add35872..0c9f349e82a8b 100644
--- a/clang/test/CodeGen/attr-counted-by-nested-structs.c
+++ b/clang/test/CodeGen/attr-counted-by-nested-structs.c
@@ -43,7 +43,7 @@ struct quad_nested {
 // CHECK-NEXT:    [[BUF:%.*]] = getelementptr inbounds nuw 
[[STRUCT_SINGLE_NESTED:%.*]], ptr [[TMP0]], i32 0, i32 1
 // CHECK-NEXT:    [[TMP1:%.*]] = load ptr, ptr [[P_ADDR]], align 8
 // CHECK-NEXT:    [[BUF1:%.*]] = getelementptr inbounds nuw 
[[STRUCT_SINGLE_NESTED]], ptr [[TMP1]], i32 0, i32 1
-// CHECK-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds 
[[STRUCT_FLEX:%.*]], ptr [[BUF1]], i32 0, i32 0
+// CHECK-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr 
[[BUF1]], i64 0
 // CHECK-NEXT:    [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[COUNTED_BY_GEP]], 
align 4
 // CHECK-NEXT:    [[COUNT:%.*]] = zext i32 [[COUNTED_BY_LOAD]] to i64
 // CHECK-NEXT:    [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = mul nuw i64 [[COUNT]], 1
@@ -66,7 +66,7 @@ unsigned test_size_of_single_nested(struct single_nested *p) {
 // CHECK-NEXT:    [[BUF:%.*]] = getelementptr inbounds nuw 
[[STRUCT_DOUBLE_NESTED:%.*]], ptr [[TMP0]], i32 0, i32 1
 // CHECK-NEXT:    [[TMP1:%.*]] = load ptr, ptr [[P_ADDR]], align 8
 // CHECK-NEXT:    [[BUF1:%.*]] = getelementptr inbounds nuw 
[[STRUCT_DOUBLE_NESTED]], ptr [[TMP1]], i32 0, i32 1
-// CHECK-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds 
[[STRUCT_SINGLE_NESTED:%.*]], ptr [[BUF1]], i32 0, i32 1, i32 0
+// CHECK-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr 
[[BUF1]], i64 4
 // CHECK-NEXT:    [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[COUNTED_BY_GEP]], 
align 4
 // CHECK-NEXT:    [[COUNT:%.*]] = zext i32 [[COUNTED_BY_LOAD]] to i64
 // CHECK-NEXT:    [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = mul nuw i64 [[COUNT]], 1
@@ -89,7 +89,7 @@ unsigned test_size_of_double_nested(struct double_nested *p) {
 // CHECK-NEXT:    [[BUF:%.*]] = getelementptr inbounds nuw 
[[STRUCT_TRIPLE_NESTED:%.*]], ptr [[TMP0]], i32 0, i32 1
 // CHECK-NEXT:    [[TMP1:%.*]] = load ptr, ptr [[P_ADDR]], align 8
 // CHECK-NEXT:    [[BUF1:%.*]] = getelementptr inbounds nuw 
[[STRUCT_TRIPLE_NESTED]], ptr [[TMP1]], i32 0, i32 1
-// CHECK-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds 
[[STRUCT_DOUBLE_NESTED:%.*]], ptr [[BUF1]], i32 0, i32 1, i32 1, i32 0
+// CHECK-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr 
[[BUF1]], i64 8
 // CHECK-NEXT:    [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[COUNTED_BY_GEP]], 
align 4
 // CHECK-NEXT:    [[COUNT:%.*]] = zext i32 [[COUNTED_BY_LOAD]] to i64
 // CHECK-NEXT:    [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = mul nuw i64 [[COUNT]], 1
@@ -112,7 +112,7 @@ unsigned test_size_of_triple_nested(struct triple_nested 
*p) {
 // CHECK-NEXT:    [[BUF:%.*]] = getelementptr inbounds nuw 
[[STRUCT_QUAD_NESTED:%.*]], ptr [[TMP0]], i32 0, i32 1
 // CHECK-NEXT:    [[TMP1:%.*]] = load ptr, ptr [[P_ADDR]], align 8
 // CHECK-NEXT:    [[BUF1:%.*]] = getelementptr inbounds nuw 
[[STRUCT_QUAD_NESTED]], ptr [[TMP1]], i32 0, i32 1
-// CHECK-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds 
[[STRUCT_TRIPLE_NESTED:%.*]], ptr [[BUF1]], i32 0, i32 1, i32 1, i32 1, i32 0
+// CHECK-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr 
[[BUF1]], i64 12
 // CHECK-NEXT:    [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[COUNTED_BY_GEP]], 
align 4
 // CHECK-NEXT:    [[COUNT:%.*]] = zext i32 [[COUNTED_BY_LOAD]] to i64
 // CHECK-NEXT:    [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = mul nuw i64 [[COUNT]], 1
diff --git a/clang/test/CodeGen/attr-counted-by-union-storage.c 
b/clang/test/CodeGen/attr-counted-by-union-storage.c
new file mode 100644
index 0000000000000..585cc87244dc7
--- /dev/null
+++ b/clang/test/CodeGen/attr-counted-by-union-storage.c
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -emit-llvm -o - %s | 
FileCheck %s
+
+// The union's IR type is struct work, so num_layers has to be reached by byte
+// offset rather than through struct work's field indices.
+
+struct list {
+  struct list *next, *prev;
+};
+
+struct work {
+  long data;
+  struct list entry;
+  void (*func)(void);
+};
+
+struct domain {
+  void *rules[3];
+  void *hierarchy;
+  union {
+    struct work work_free;
+    struct {
+      int usage;
+      unsigned int num_layers;
+      unsigned int masks[] __attribute__((counted_by(num_layers)));
+    };
+  };
+};
+
+// CHECK-LABEL: define {{.*}} @test_bdos(
+// CHECK: [[GEP:%.*]] = getelementptr inbounds nuw i8, ptr %d, i64 36
+// CHECK: load i32, ptr [[GEP]]
+unsigned long test_bdos(struct domain *d) {
+  return __builtin_dynamic_object_size(d->masks, 1);
+}
diff --git a/clang/test/CodeGen/builtin-counted-by-ref.c 
b/clang/test/CodeGen/builtin-counted-by-ref.c
index 8b1ef0edb8bd9..b79eb168e88da 100644
--- a/clang/test/CodeGen/builtin-counted-by-ref.c
+++ b/clang/test/CodeGen/builtin-counted-by-ref.c
@@ -23,8 +23,8 @@ struct a {
 // X86_64-NEXT:    [[TMP1:%.*]] = load i32, ptr [[SIZE_ADDR]], align 4
 // X86_64-NEXT:    [[CONV1:%.*]] = trunc i32 [[TMP1]] to i16
 // X86_64-NEXT:    [[TMP2:%.*]] = load ptr, ptr [[P]], align 8
-// X86_64-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds 
[[STRUCT_A:%.*]], ptr [[TMP2]], i32 0, i32 1
-// X86_64-NEXT:    store i16 [[CONV1]], ptr [[DOT_COUNTED_BY_GEP]], align 2
+// X86_64-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr 
[[TMP2]], i64 2
+// X86_64-NEXT:    store i16 [[CONV1]], ptr [[COUNTED_BY_GEP]], align 2
 // X86_64-NEXT:    [[TMP3:%.*]] = load ptr, ptr [[P]], align 8
 // X86_64-NEXT:    ret ptr [[TMP3]]
 //
@@ -42,8 +42,8 @@ struct a {
 // I386-NEXT:    [[TMP1:%.*]] = load i32, ptr [[SIZE_ADDR]], align 4
 // I386-NEXT:    [[CONV:%.*]] = trunc i32 [[TMP1]] to i16
 // I386-NEXT:    [[TMP2:%.*]] = load ptr, ptr [[P]], align 4
-// I386-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds 
[[STRUCT_A:%.*]], ptr [[TMP2]], i32 0, i32 1
-// I386-NEXT:    store i16 [[CONV]], ptr [[DOT_COUNTED_BY_GEP]], align 2
+// I386-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr 
[[TMP2]], i32 2
+// I386-NEXT:    store i16 [[CONV]], ptr [[COUNTED_BY_GEP]], align 2
 // I386-NEXT:    [[TMP3:%.*]] = load ptr, ptr [[P]], align 4
 // I386-NEXT:    ret ptr [[TMP3]]
 //
@@ -91,8 +91,8 @@ struct b {
 // X86_64-NEXT:    [[TMP1:%.*]] = load i32, ptr [[SIZE_ADDR]], align 4
 // X86_64-NEXT:    [[CONV1:%.*]] = trunc i32 [[TMP1]] to i8
 // X86_64-NEXT:    [[TMP2:%.*]] = load ptr, ptr [[P]], align 8
-// X86_64-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds 
[[STRUCT_B:%.*]], ptr [[TMP2]], i32 0, i32 1, i32 1, i32 1, i32 0
-// X86_64-NEXT:    store i8 [[CONV1]], ptr [[DOT_COUNTED_BY_GEP]], align 1
+// X86_64-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr 
[[TMP2]], i64 12
+// X86_64-NEXT:    store i8 [[CONV1]], ptr [[COUNTED_BY_GEP]], align 1
 // X86_64-NEXT:    [[TMP3:%.*]] = load ptr, ptr [[P]], align 8
 // X86_64-NEXT:    ret ptr [[TMP3]]
 //
@@ -110,8 +110,8 @@ struct b {
 // I386-NEXT:    [[TMP1:%.*]] = load i32, ptr [[SIZE_ADDR]], align 4
 // I386-NEXT:    [[CONV:%.*]] = trunc i32 [[TMP1]] to i8
 // I386-NEXT:    [[TMP2:%.*]] = load ptr, ptr [[P]], align 4
-// I386-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds 
[[STRUCT_B:%.*]], ptr [[TMP2]], i32 0, i32 1, i32 1, i32 1, i32 0
-// I386-NEXT:    store i8 [[CONV]], ptr [[DOT_COUNTED_BY_GEP]], align 1
+// I386-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr 
[[TMP2]], i32 12
+// I386-NEXT:    store i8 [[CONV]], ptr [[COUNTED_BY_GEP]], align 1
 // I386-NEXT:    [[TMP3:%.*]] = load ptr, ptr [[P]], align 4
 // I386-NEXT:    ret ptr [[TMP3]]
 //
@@ -200,8 +200,8 @@ struct d {
 // X86_64-NEXT:    [[TMP2:%.*]] = load i32, ptr [[SIZE_ADDR]], align 4
 // X86_64-NEXT:    [[CONV:%.*]] = trunc i32 [[TMP2]] to i16
 // X86_64-NEXT:    [[TMP3:%.*]] = load ptr, ptr [[P]], align 8
-// X86_64-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds 
[[STRUCT_D]], ptr [[TMP3]], i32 0, i32 1
-// X86_64-NEXT:    store i16 [[CONV]], ptr [[DOT_COUNTED_BY_GEP]], align 2
+// X86_64-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr 
[[TMP3]], i64 4
+// X86_64-NEXT:    store i16 [[CONV]], ptr [[COUNTED_BY_GEP]], align 2
 // X86_64-NEXT:    [[TMP4:%.*]] = load ptr, ptr [[P]], align 8
 // X86_64-NEXT:    ret ptr [[TMP4]]
 //
@@ -222,8 +222,8 @@ struct d {
 // I386-NEXT:    [[TMP2:%.*]] = load i32, ptr [[SIZE_ADDR]], align 4
 // I386-NEXT:    [[CONV:%.*]] = trunc i32 [[TMP2]] to i16
 // I386-NEXT:    [[TMP3:%.*]] = load ptr, ptr [[P]], align 4
-// I386-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds 
[[STRUCT_D]], ptr [[TMP3]], i32 0, i32 1
-// I386-NEXT:    store i16 [[CONV]], ptr [[DOT_COUNTED_BY_GEP]], align 2
+// I386-NEXT:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr 
[[TMP3]], i32 4
+// I386-NEXT:    store i16 [[CONV]], ptr [[COUNTED_BY_GEP]], align 2
 // I386-NEXT:    [[TMP4:%.*]] = load ptr, ptr [[P]], align 4
 // I386-NEXT:    ret ptr [[TMP4]]
 //
@@ -246,13 +246,13 @@ struct outer {
 
 // X86_64-LABEL: define dso_local ptr @test5(
 // X86_64-SAME: i32 noundef [[COUNT:%.*]]) #[[ATTR0]] {
-// X86_64:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds 
[[STRUCT_INNER:%.*]], ptr {{%.*}}, i32 0, i32 0
-// X86_64-NEXT:    store i32 [[TMP1:%.*]], ptr [[DOT_COUNTED_BY_GEP]], align 4
+// X86_64:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr {{%.*}}, 
i64 0
+// X86_64-NEXT:    store i32 [[TMP1:%.*]], ptr [[COUNTED_BY_GEP]], align 4
 //
 // I386-LABEL: define dso_local ptr @test5(
 // I386-SAME: i32 noundef [[COUNT:%.*]]) #[[ATTR0]] {
-// I386:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds 
[[STRUCT_INNER:%.*]], ptr {{%.*}}, i32 0, i32 0
-// I386-NEXT:    store i32 [[TMP1:%.*]], ptr [[DOT_COUNTED_BY_GEP]], align 4
+// I386:    [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr {{%.*}}, 
i32 0
+// I386-NEXT:    store i32 [[TMP1:%.*]], ptr [[COUNTED_BY_GEP]], align 4
 //
 struct inner *test5(int count) {
   struct inner *entries = __builtin_malloc(sizeof(*entries) + count * 
sizeof(*entries->ent));

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to