Skip to content

Commit c0572e8

Browse files
committed
Generate the full struct size directly. Also don't create a subtraction if the offset is zero.
1 parent 222fa83 commit c0572e8

File tree

3 files changed

+322
-7
lines changed

3 files changed

+322
-7
lines changed

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,12 +1155,15 @@ static std::pair<uint64_t, uint64_t> getSubobjectInfo(CodeGenFunction &CGF,
11551155
const ValueDecl *VD = nullptr;
11561156

11571157
if (const auto *DRE = dyn_cast<DeclRefExpr>(Subobject)) {
1158-
VD = DRE->getDecl();
1159-
QualType Ty = VD->getType();
1158+
// We're pointing to the beginning of the struct.
1159+
QualType Ty = DRE->getDecl()->getType();
11601160
if (Ty->isPointerType())
11611161
Ty = Ty->getPointeeType();
1162-
OuterRD = Ty->getAsRecordDecl();
1163-
} else if (const auto *ME = dyn_cast<MemberExpr>(Subobject)) {
1162+
ASTContext &Ctx = CGF.getContext();
1163+
return std::make_pair(Ctx.toCharUnitsFromBits(Ctx.getTypeSize(Ty)).getQuantity(), 0);
1164+
}
1165+
1166+
if (const auto *ME = dyn_cast<MemberExpr>(Subobject)) {
11641167
VD = ME->getMemberDecl();
11651168
OuterRD = VD->getDeclContext()->getOuterLexicalRecordContext();
11661169
} else {
Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 4
2+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s
3+
4+
typedef __SIZE_TYPE__ size_t;
5+
6+
#define __bdos(a) __builtin_dynamic_object_size(a, 1)
7+
8+
struct U {
9+
double d;
10+
int i;
11+
};
12+
13+
struct test_struct {
14+
struct test_struct *vptr;
15+
char buf1[5];
16+
struct i {
17+
char a;
18+
int b[2][13];
19+
int c, d;
20+
} z;
21+
struct U *u_ptr;
22+
unsigned _a : 1;
23+
unsigned _b : 2;
24+
struct {
25+
struct {
26+
char x_1;
27+
char x_2[37];
28+
};
29+
};
30+
union {
31+
struct { char _z[20]; } m;
32+
struct { char _y[13]; } n;
33+
} u;
34+
char buf2[7];
35+
};
36+
37+
size_t ret;
38+
39+
// CHECK-LABEL: define dso_local i64 @test1(
40+
// CHECK-SAME: ptr noundef [[P:%.*]], i32 noundef [[IDX:%.*]]) #[[ATTR0:[0-9]+]] {
41+
// CHECK-NEXT: entry:
42+
// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8
43+
// CHECK-NEXT: [[IDX_ADDR:%.*]] = alloca i32, align 4
44+
// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8
45+
// CHECK-NEXT: store i32 [[IDX]], ptr [[IDX_ADDR]], align 4
46+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8
47+
// CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[TMP0]], i1 false, i1 true, i1 true, i1 false, i64 216, i64 0)
48+
// CHECK-NEXT: ret i64 [[TMP1]]
49+
//
50+
size_t test1(struct test_struct *p, int idx) {
51+
return __bdos(p);
52+
}
53+
54+
// CHECK-LABEL: define dso_local i64 @test2(
55+
// CHECK-SAME: ptr noundef [[P:%.*]], i32 noundef [[IDX:%.*]]) #[[ATTR0]] {
56+
// CHECK-NEXT: entry:
57+
// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8
58+
// CHECK-NEXT: [[IDX_ADDR:%.*]] = alloca i32, align 4
59+
// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8
60+
// CHECK-NEXT: store i32 [[IDX]], ptr [[IDX_ADDR]], align 4
61+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8
62+
// CHECK-NEXT: [[BUF1:%.*]] = getelementptr inbounds [[STRUCT_TEST_STRUCT:%.*]], ptr [[TMP0]], i32 0, i32 1
63+
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[IDX_ADDR]], align 4
64+
// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP1]] to i64
65+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [5 x i8], ptr [[BUF1]], i64 0, i64 [[IDXPROM]]
66+
// CHECK-NEXT: [[TMP2:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[ARRAYIDX]], i1 false, i1 true, i1 true, i1 false, i64 5, i64 8)
67+
// CHECK-NEXT: ret i64 [[TMP2]]
68+
//
69+
size_t test2(struct test_struct *p, int idx) {
70+
return __bdos(&p->buf1[idx]);
71+
}
72+
73+
// CHECK-LABEL: define dso_local i64 @test3(
74+
// CHECK-SAME: ptr noundef [[P:%.*]], i32 noundef [[IDX:%.*]]) #[[ATTR0]] {
75+
// CHECK-NEXT: entry:
76+
// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8
77+
// CHECK-NEXT: [[IDX_ADDR:%.*]] = alloca i32, align 4
78+
// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8
79+
// CHECK-NEXT: store i32 [[IDX]], ptr [[IDX_ADDR]], align 4
80+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8
81+
// CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds [[STRUCT_TEST_STRUCT:%.*]], ptr [[TMP0]], i32 0, i32 2
82+
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[IDX_ADDR]], align 4
83+
// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP1]] to i64
84+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[Z]], i64 [[IDXPROM]]
85+
// CHECK-NEXT: [[TMP2:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[ARRAYIDX]], i1 false, i1 true, i1 true, i1 false, i64 116, i64 16)
86+
// CHECK-NEXT: ret i64 [[TMP2]]
87+
//
88+
size_t test3(struct test_struct *p, int idx) {
89+
return __bdos(&((char *)&p->z)[idx]);
90+
}
91+
92+
// CHECK-LABEL: define dso_local i64 @test4(
93+
// CHECK-SAME: ptr noundef [[P:%.*]], i32 noundef [[IDX:%.*]]) #[[ATTR0]] {
94+
// CHECK-NEXT: entry:
95+
// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8
96+
// CHECK-NEXT: [[IDX_ADDR:%.*]] = alloca i32, align 4
97+
// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8
98+
// CHECK-NEXT: store i32 [[IDX]], ptr [[IDX_ADDR]], align 4
99+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8
100+
// CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds [[STRUCT_TEST_STRUCT:%.*]], ptr [[TMP0]], i32 0, i32 2
101+
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[IDX_ADDR]], align 4
102+
// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP1]] to i64
103+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[Z]], i64 [[IDXPROM]]
104+
// CHECK-NEXT: [[TMP2:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[ARRAYIDX]], i1 false, i1 true, i1 true, i1 false, i64 116, i64 16)
105+
// CHECK-NEXT: ret i64 [[TMP2]]
106+
//
107+
size_t test4(struct test_struct *p, int idx) {
108+
return __bdos(&((char *)&p->z)[idx]);
109+
}
110+
111+
// CHECK-LABEL: define dso_local i64 @test5(
112+
// CHECK-SAME: ptr noundef [[P:%.*]], i32 noundef [[IDX:%.*]]) #[[ATTR0]] {
113+
// CHECK-NEXT: entry:
114+
// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8
115+
// CHECK-NEXT: [[IDX_ADDR:%.*]] = alloca i32, align 4
116+
// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8
117+
// CHECK-NEXT: store i32 [[IDX]], ptr [[IDX_ADDR]], align 4
118+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8
119+
// CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds [[STRUCT_TEST_STRUCT:%.*]], ptr [[TMP0]], i32 0, i32 2
120+
// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_I:%.*]], ptr [[Z]], i32 0, i32 0
121+
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[IDX_ADDR]], align 4
122+
// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP1]] to i64
123+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[IDXPROM]]
124+
// CHECK-NEXT: [[TMP2:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[ARRAYIDX]], i1 false, i1 true, i1 true, i1 false, i64 1, i64 16)
125+
// CHECK-NEXT: ret i64 [[TMP2]]
126+
//
127+
size_t test5(struct test_struct *p, int idx) {
128+
return __bdos(&((char *)&p->z.a)[idx]);
129+
}
130+
131+
// CHECK-LABEL: define dso_local i64 @test6(
132+
// CHECK-SAME: ptr noundef [[P:%.*]], i32 noundef [[IDX:%.*]]) #[[ATTR0]] {
133+
// CHECK-NEXT: entry:
134+
// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8
135+
// CHECK-NEXT: [[IDX_ADDR:%.*]] = alloca i32, align 4
136+
// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8
137+
// CHECK-NEXT: store i32 [[IDX]], ptr [[IDX_ADDR]], align 4
138+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8
139+
// CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds [[STRUCT_TEST_STRUCT:%.*]], ptr [[TMP0]], i32 0, i32 2
140+
// CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_I:%.*]], ptr [[Z]], i32 0, i32 1
141+
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[IDX_ADDR]], align 4
142+
// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP1]] to i64
143+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[B]], i64 [[IDXPROM]]
144+
// CHECK-NEXT: [[TMP2:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[ARRAYIDX]], i1 false, i1 true, i1 true, i1 false, i64 104, i64 20)
145+
// CHECK-NEXT: ret i64 [[TMP2]]
146+
//
147+
size_t test6(struct test_struct *p, int idx) {
148+
return __bdos(&((char *)&p->z.b)[idx]);
149+
}
150+
151+
// CHECK-LABEL: define dso_local i64 @test7(
152+
// CHECK-SAME: ptr noundef [[P:%.*]], i32 noundef [[IDX:%.*]]) #[[ATTR0]] {
153+
// CHECK-NEXT: entry:
154+
// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8
155+
// CHECK-NEXT: [[IDX_ADDR:%.*]] = alloca i32, align 4
156+
// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8
157+
// CHECK-NEXT: store i32 [[IDX]], ptr [[IDX_ADDR]], align 4
158+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8
159+
// CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds [[STRUCT_TEST_STRUCT:%.*]], ptr [[TMP0]], i32 0, i32 2
160+
// CHECK-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_I:%.*]], ptr [[Z]], i32 0, i32 2
161+
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[IDX_ADDR]], align 4
162+
// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP1]] to i64
163+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 [[IDXPROM]]
164+
// CHECK-NEXT: [[TMP2:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[ARRAYIDX]], i1 false, i1 true, i1 true, i1 false, i64 4, i64 124)
165+
// CHECK-NEXT: ret i64 [[TMP2]]
166+
//
167+
size_t test7(struct test_struct *p, int idx) {
168+
return __bdos(&((char *)&p->z.c)[idx]);
169+
}
170+
171+
// CHECK-LABEL: define dso_local i64 @test8(
172+
// CHECK-SAME: ptr noundef [[P:%.*]], i32 noundef [[IDX:%.*]]) #[[ATTR0]] {
173+
// CHECK-NEXT: entry:
174+
// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8
175+
// CHECK-NEXT: [[IDX_ADDR:%.*]] = alloca i32, align 4
176+
// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8
177+
// CHECK-NEXT: store i32 [[IDX]], ptr [[IDX_ADDR]], align 4
178+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8
179+
// CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds [[STRUCT_TEST_STRUCT:%.*]], ptr [[TMP0]], i32 0, i32 2
180+
// CHECK-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_I:%.*]], ptr [[Z]], i32 0, i32 3
181+
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[IDX_ADDR]], align 4
182+
// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP1]] to i64
183+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[D]], i64 [[IDXPROM]]
184+
// CHECK-NEXT: [[TMP2:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[ARRAYIDX]], i1 false, i1 true, i1 true, i1 false, i64 4, i64 128)
185+
// CHECK-NEXT: ret i64 [[TMP2]]
186+
//
187+
size_t test8(struct test_struct *p, int idx) {
188+
return __bdos(&((char *)&p->z.d)[idx]);
189+
}
190+
191+
// CHECK-LABEL: define dso_local i64 @test9(
192+
// CHECK-SAME: ptr noundef [[P:%.*]], i32 noundef [[IDX:%.*]]) #[[ATTR0]] {
193+
// CHECK-NEXT: entry:
194+
// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8
195+
// CHECK-NEXT: [[IDX_ADDR:%.*]] = alloca i32, align 4
196+
// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8
197+
// CHECK-NEXT: store i32 [[IDX]], ptr [[IDX_ADDR]], align 4
198+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8
199+
// CHECK-NEXT: [[U_PTR:%.*]] = getelementptr inbounds [[STRUCT_TEST_STRUCT:%.*]], ptr [[TMP0]], i32 0, i32 3
200+
// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[U_PTR]], align 8
201+
// CHECK-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_U:%.*]], ptr [[TMP1]], i32 0, i32 0
202+
// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[IDX_ADDR]], align 4
203+
// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP2]] to i64
204+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[D]], i64 [[IDXPROM]]
205+
// CHECK-NEXT: [[TMP3:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[ARRAYIDX]], i1 false, i1 true, i1 true, i1 false, i64 8, i64 0)
206+
// CHECK-NEXT: ret i64 [[TMP3]]
207+
//
208+
size_t test9(struct test_struct *p, int idx) {
209+
return __bdos(&((char *)&p->u_ptr->d)[idx]);
210+
}
211+
212+
// CHECK-LABEL: define dso_local i64 @test10(
213+
// CHECK-SAME: ptr noundef [[P:%.*]], i32 noundef [[IDX:%.*]]) #[[ATTR0]] {
214+
// CHECK-NEXT: entry:
215+
// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8
216+
// CHECK-NEXT: [[IDX_ADDR:%.*]] = alloca i32, align 4
217+
// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8
218+
// CHECK-NEXT: store i32 [[IDX]], ptr [[IDX_ADDR]], align 4
219+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8
220+
// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_TEST_STRUCT:%.*]], ptr [[TMP0]], i32 0, i32 5
221+
// CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[STRUCT_ANON:%.*]], ptr [[TMP1]], i32 0, i32 0
222+
// CHECK-NEXT: [[X_1:%.*]] = getelementptr inbounds [[STRUCT_ANON_0:%.*]], ptr [[TMP2]], i32 0, i32 0
223+
// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[IDX_ADDR]], align 4
224+
// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP3]] to i64
225+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[X_1]], i64 [[IDXPROM]]
226+
// CHECK-NEXT: [[TMP4:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[ARRAYIDX]], i1 false, i1 true, i1 true, i1 false, i64 1, i64 145)
227+
// CHECK-NEXT: ret i64 [[TMP4]]
228+
//
229+
size_t test10(struct test_struct *p, int idx) {
230+
return __bdos(&((char *)&p->x_1)[idx]);
231+
}
232+
233+
// CHECK-LABEL: define dso_local i64 @test11(
234+
// CHECK-SAME: ptr noundef [[P:%.*]], i32 noundef [[IDX:%.*]]) #[[ATTR0]] {
235+
// CHECK-NEXT: entry:
236+
// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8
237+
// CHECK-NEXT: [[IDX_ADDR:%.*]] = alloca i32, align 4
238+
// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8
239+
// CHECK-NEXT: store i32 [[IDX]], ptr [[IDX_ADDR]], align 4
240+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8
241+
// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_TEST_STRUCT:%.*]], ptr [[TMP0]], i32 0, i32 5
242+
// CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[STRUCT_ANON:%.*]], ptr [[TMP1]], i32 0, i32 0
243+
// CHECK-NEXT: [[X_2:%.*]] = getelementptr inbounds [[STRUCT_ANON_0:%.*]], ptr [[TMP2]], i32 0, i32 1
244+
// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[IDX_ADDR]], align 4
245+
// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP3]] to i64
246+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[X_2]], i64 [[IDXPROM]]
247+
// CHECK-NEXT: [[TMP4:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[ARRAYIDX]], i1 false, i1 true, i1 true, i1 false, i64 37, i64 146)
248+
// CHECK-NEXT: ret i64 [[TMP4]]
249+
//
250+
size_t test11(struct test_struct *p, int idx) {
251+
return __bdos(&((char *)&p->x_2)[idx]);
252+
}
253+
254+
// CHECK-LABEL: define dso_local i64 @test12(
255+
// CHECK-SAME: ptr noundef [[P:%.*]], i32 noundef [[IDX:%.*]]) #[[ATTR0]] {
256+
// CHECK-NEXT: entry:
257+
// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8
258+
// CHECK-NEXT: [[IDX_ADDR:%.*]] = alloca i32, align 4
259+
// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8
260+
// CHECK-NEXT: store i32 [[IDX]], ptr [[IDX_ADDR]], align 4
261+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8
262+
// CHECK-NEXT: [[U:%.*]] = getelementptr inbounds [[STRUCT_TEST_STRUCT:%.*]], ptr [[TMP0]], i32 0, i32 6
263+
// CHECK-NEXT: [[_Z:%.*]] = getelementptr inbounds [[STRUCT_ANON_1:%.*]], ptr [[U]], i32 0, i32 0
264+
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[IDX_ADDR]], align 4
265+
// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP1]] to i64
266+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [20 x i8], ptr [[_Z]], i64 0, i64 [[IDXPROM]]
267+
// CHECK-NEXT: [[TMP2:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[ARRAYIDX]], i1 false, i1 true, i1 true, i1 false, i64 20, i64 183)
268+
// CHECK-NEXT: ret i64 [[TMP2]]
269+
//
270+
size_t test12(struct test_struct *p, int idx) {
271+
return __bdos(&p->u.m._z[idx]);
272+
}
273+
274+
// CHECK-LABEL: define dso_local i64 @test13(
275+
// CHECK-SAME: ptr noundef [[P:%.*]], i32 noundef [[IDX:%.*]]) #[[ATTR0]] {
276+
// CHECK-NEXT: entry:
277+
// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8
278+
// CHECK-NEXT: [[IDX_ADDR:%.*]] = alloca i32, align 4
279+
// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8
280+
// CHECK-NEXT: store i32 [[IDX]], ptr [[IDX_ADDR]], align 4
281+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8
282+
// CHECK-NEXT: [[U:%.*]] = getelementptr inbounds [[STRUCT_TEST_STRUCT:%.*]], ptr [[TMP0]], i32 0, i32 6
283+
// CHECK-NEXT: [[_Y:%.*]] = getelementptr inbounds [[STRUCT_ANON_2:%.*]], ptr [[U]], i32 0, i32 0
284+
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[IDX_ADDR]], align 4
285+
// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP1]] to i64
286+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [13 x i8], ptr [[_Y]], i64 0, i64 [[IDXPROM]]
287+
// CHECK-NEXT: [[TMP2:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[ARRAYIDX]], i1 false, i1 true, i1 true, i1 false, i64 13, i64 183)
288+
// CHECK-NEXT: ret i64 [[TMP2]]
289+
//
290+
size_t test13(struct test_struct *p, int idx) {
291+
return __bdos(&p->u.n._y[idx]);
292+
}
293+
294+
// CHECK-LABEL: define dso_local i64 @test14(
295+
// CHECK-SAME: ptr noundef [[P:%.*]], i32 noundef [[IDX:%.*]]) #[[ATTR0]] {
296+
// CHECK-NEXT: entry:
297+
// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8
298+
// CHECK-NEXT: [[IDX_ADDR:%.*]] = alloca i32, align 4
299+
// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8
300+
// CHECK-NEXT: store i32 [[IDX]], ptr [[IDX_ADDR]], align 4
301+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8
302+
// CHECK-NEXT: [[BUF2:%.*]] = getelementptr inbounds [[STRUCT_TEST_STRUCT:%.*]], ptr [[TMP0]], i32 0, i32 7
303+
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[IDX_ADDR]], align 4
304+
// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP1]] to i64
305+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [7 x i8], ptr [[BUF2]], i64 0, i64 [[IDXPROM]]
306+
// CHECK-NEXT: [[TMP2:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[ARRAYIDX]], i1 false, i1 true, i1 true, i1 false, i64 7, i64 203)
307+
// CHECK-NEXT: ret i64 [[TMP2]]
308+
//
309+
size_t test14(struct test_struct *p, int idx) {
310+
return __bdos(&p->buf2[idx]);
311+
}

llvm/lib/Analysis/MemoryBuiltins.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -665,9 +665,10 @@ Value *llvm::lowerObjectSizeCall(
665665

666666
if (!EvalOptions.WholeObjectSize && EvalOptions.SubobjectSize) {
667667
Size = ConstantInt::get(Size->getType(), EvalOptions.SubobjectSize);
668-
Offset = Builder.CreateSub(
669-
Offset,
670-
ConstantInt::get(Offset->getType(), EvalOptions.SubobjectOffset));
668+
if (EvalOptions.SubobjectOffset)
669+
Offset = Builder.CreateSub(
670+
Offset,
671+
ConstantInt::get(Offset->getType(), EvalOptions.SubobjectOffset));
671672
}
672673

673674
// If we've outside the end of the object, then we can always access

0 commit comments

Comments
 (0)