[clang] [Clang][counted_by] Load the count through unions by byte offset (PR #228309)
Amaan Qureshi via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 1 19:46:44 PDT 2026
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 <git at amaanq.com>
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));
More information about the cfe-commits
mailing list