1// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -O0 %s -o - 2>&1 | FileCheck %s
2
3typedef unsigned long size_t;
4
5struct Foo {
6  int t[10];
7};
8
9#define PS(N) __attribute__((pass_object_size(N)))
10
11int gi = 0;
12
13// CHECK-LABEL: define i32 @ObjectSize0(i8* %{{.*}}, i64)
14int ObjectSize0(void *const p PS(0)) {
15  // CHECK-NOT: @llvm.objectsize
16  return __builtin_object_size(p, 0);
17}
18
19// CHECK-LABEL: define i32 @ObjectSize1(i8* %{{.*}}, i64)
20int ObjectSize1(void *const p PS(1)) {
21  // CHECK-NOT: @llvm.objectsize
22  return __builtin_object_size(p, 1);
23}
24
25// CHECK-LABEL: define i32 @ObjectSize2(i8* %{{.*}}, i64)
26int ObjectSize2(void *const p PS(2)) {
27  // CHECK-NOT: @llvm.objectsize
28  return __builtin_object_size(p, 2);
29}
30
31// CHECK-LABEL: define i32 @ObjectSize3(i8* %{{.*}}, i64)
32int ObjectSize3(void *const p PS(3)) {
33  // CHECK-NOT: @llvm.objectsize
34  return __builtin_object_size(p, 3);
35}
36
37// CHECK-LABEL: define void @test1
38void test1() {
39  struct Foo t[10];
40
41  // CHECK: call i32 @ObjectSize0(i8* %{{.*}}, i64 360)
42  gi = ObjectSize0(&t[1]);
43  // CHECK: call i32 @ObjectSize1(i8* %{{.*}}, i64 360)
44  gi = ObjectSize1(&t[1]);
45  // CHECK: call i32 @ObjectSize2(i8* %{{.*}}, i64 360)
46  gi = ObjectSize2(&t[1]);
47  // CHECK: call i32 @ObjectSize3(i8* %{{.*}}, i64 360)
48  gi = ObjectSize3(&t[1]);
49
50  // CHECK: call i32 @ObjectSize0(i8* %{{.*}}, i64 356)
51  gi = ObjectSize0(&t[1].t[1]);
52  // CHECK: call i32 @ObjectSize1(i8* %{{.*}}, i64 36)
53  gi = ObjectSize1(&t[1].t[1]);
54  // CHECK: call i32 @ObjectSize2(i8* %{{.*}}, i64 356)
55  gi = ObjectSize2(&t[1].t[1]);
56  // CHECK: call i32 @ObjectSize3(i8* %{{.*}}, i64 36)
57  gi = ObjectSize3(&t[1].t[1]);
58}
59
60// CHECK-LABEL: define void @test2
61void test2(struct Foo *t) {
62  // CHECK: call i32 @ObjectSize1(i8* %{{.*}}, i64 36)
63  gi = ObjectSize1(&t->t[1]);
64  // CHECK: call i32 @ObjectSize3(i8* %{{.*}}, i64 36)
65  gi = ObjectSize3(&t->t[1]);
66}
67
68// CHECK-LABEL: define i32 @_Z27NoViableOverloadObjectSize0Pv
69int NoViableOverloadObjectSize0(void *const p) __attribute__((overloadable)) {
70  // CHECK: @llvm.objectsize
71  return __builtin_object_size(p, 0);
72}
73
74// CHECK-LABEL: define i32 @_Z27NoViableOverloadObjectSize1Pv
75int NoViableOverloadObjectSize1(void *const p) __attribute__((overloadable)) {
76  // CHECK: @llvm.objectsize
77  return __builtin_object_size(p, 1);
78}
79
80// CHECK-LABEL: define i32 @_Z27NoViableOverloadObjectSize2Pv
81int NoViableOverloadObjectSize2(void *const p) __attribute__((overloadable)) {
82  // CHECK: @llvm.objectsize
83  return __builtin_object_size(p, 2);
84}
85
86// CHECK-LABEL: define i32 @_Z27NoViableOverloadObjectSize3Pv
87int NoViableOverloadObjectSize3(void *const p) __attribute__((overloadable)) {
88  // CHECK-NOT: @llvm.objectsize
89  return __builtin_object_size(p, 3);
90}
91
92// CHECK-LABEL: define i32 @_Z27NoViableOverloadObjectSize0Pv
93// CHECK-NOT: @llvm.objectsize
94int NoViableOverloadObjectSize0(void *const p PS(0))
95    __attribute__((overloadable)) {
96  return __builtin_object_size(p, 0);
97}
98
99int NoViableOverloadObjectSize1(void *const p PS(1))
100    __attribute__((overloadable)) {
101  return __builtin_object_size(p, 1);
102}
103
104int NoViableOverloadObjectSize2(void *const p PS(2))
105    __attribute__((overloadable)) {
106  return __builtin_object_size(p, 2);
107}
108
109int NoViableOverloadObjectSize3(void *const p PS(3))
110    __attribute__((overloadable)) {
111  return __builtin_object_size(p, 3);
112}
113
114const static int SHOULDNT_BE_CALLED = -100;
115int NoViableOverloadObjectSize0(void *const p PS(0))
116    __attribute__((overloadable, enable_if(p == 0, "never selected"))) {
117  return SHOULDNT_BE_CALLED;
118}
119
120int NoViableOverloadObjectSize1(void *const p PS(1))
121    __attribute__((overloadable, enable_if(p == 0, "never selected"))) {
122  return SHOULDNT_BE_CALLED;
123}
124
125int NoViableOverloadObjectSize2(void *const p PS(2))
126    __attribute__((overloadable, enable_if(p == 0, "never selected"))) {
127  return SHOULDNT_BE_CALLED;
128}
129
130int NoViableOverloadObjectSize3(void *const p PS(3))
131    __attribute__((overloadable, enable_if(p == 0, "never selected"))) {
132  return SHOULDNT_BE_CALLED;
133}
134
135// CHECK-LABEL: define void @test3
136void test3() {
137  struct Foo t[10];
138
139  // CHECK: call i32 @_Z27NoViableOverloadObjectSize0PvU17pass_object_size0(i8* %{{.*}}, i64 360)
140  gi = NoViableOverloadObjectSize0(&t[1]);
141  // CHECK: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 360)
142  gi = NoViableOverloadObjectSize1(&t[1]);
143  // CHECK: call i32 @_Z27NoViableOverloadObjectSize2PvU17pass_object_size2(i8* %{{.*}}, i64 360)
144  gi = NoViableOverloadObjectSize2(&t[1]);
145  // CHECK: call i32 @_Z27NoViableOverloadObjectSize3PvU17pass_object_size3(i8* %{{.*}}, i64 360)
146  gi = NoViableOverloadObjectSize3(&t[1]);
147
148  // CHECK: call i32 @_Z27NoViableOverloadObjectSize0PvU17pass_object_size0(i8* %{{.*}}, i64 356)
149  gi = NoViableOverloadObjectSize0(&t[1].t[1]);
150  // CHECK: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 36)
151  gi = NoViableOverloadObjectSize1(&t[1].t[1]);
152  // CHECK: call i32 @_Z27NoViableOverloadObjectSize2PvU17pass_object_size2(i8* %{{.*}}, i64 356)
153  gi = NoViableOverloadObjectSize2(&t[1].t[1]);
154  // CHECK: call i32 @_Z27NoViableOverloadObjectSize3PvU17pass_object_size3(i8* %{{.*}}, i64 36)
155  gi = NoViableOverloadObjectSize3(&t[1].t[1]);
156}
157
158// CHECK-LABEL: define void @test4
159void test4(struct Foo *t) {
160  // CHECK: call i32 @_Z27NoViableOverloadObjectSize0PvU17pass_object_size0(i8* %{{.*}}, i64 %{{.*}})
161  gi = NoViableOverloadObjectSize0(&t[1]);
162  // CHECK: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 %{{.*}})
163  gi = NoViableOverloadObjectSize1(&t[1]);
164  // CHECK: call i32 @_Z27NoViableOverloadObjectSize2PvU17pass_object_size2(i8* %{{.*}}, i64 %{{.*}})
165  gi = NoViableOverloadObjectSize2(&t[1]);
166  // CHECK: call i32 @_Z27NoViableOverloadObjectSize3PvU17pass_object_size3(i8* %{{.*}}, i64 0)
167  gi = NoViableOverloadObjectSize3(&t[1]);
168
169  // CHECK: call i32 @_Z27NoViableOverloadObjectSize0PvU17pass_object_size0(i8* %{{.*}}, i64 %{{.*}})
170  gi = NoViableOverloadObjectSize0(&t[1].t[1]);
171  // CHECK: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 36)
172  gi = NoViableOverloadObjectSize1(&t[1].t[1]);
173  // CHECK: call i32 @_Z27NoViableOverloadObjectSize2PvU17pass_object_size2(i8* %{{.*}}, i64 %{{.*}})
174  gi = NoViableOverloadObjectSize2(&t[1].t[1]);
175  // CHECK: call i32 @_Z27NoViableOverloadObjectSize3PvU17pass_object_size3(i8* %{{.*}}, i64 36)
176  gi = NoViableOverloadObjectSize3(&t[1].t[1]);
177}
178
179void test5() {
180  struct Foo t[10];
181
182  int (*f)(void *) = &NoViableOverloadObjectSize0;
183  gi = f(&t[1]);
184}
185
186// CHECK-LABEL: define i32 @IndirectObjectSize0
187int IndirectObjectSize0(void *const p PS(0)) {
188  // CHECK: call i32 @ObjectSize0(i8* %{{.*}}, i64 %{{.*}})
189  // CHECK-NOT: @llvm.objectsize
190  return ObjectSize0(p);
191}
192
193// CHECK-LABEL: define i32 @IndirectObjectSize1
194int IndirectObjectSize1(void *const p PS(1)) {
195  // CHECK: call i32 @ObjectSize1(i8* %{{.*}}, i64 %{{.*}})
196  // CHECK-NOT: @llvm.objectsize
197  return ObjectSize1(p);
198}
199
200// CHECK-LABEL: define i32 @IndirectObjectSize2
201int IndirectObjectSize2(void *const p PS(2)) {
202  // CHECK: call i32 @ObjectSize2(i8* %{{.*}}, i64 %{{.*}})
203  // CHECK-NOT: @llvm.objectsize
204  return ObjectSize2(p);
205}
206
207// CHECK-LABEL: define i32 @IndirectObjectSize3
208int IndirectObjectSize3(void *const p PS(3)) {
209  // CHECK: call i32 @ObjectSize3(i8* %{{.*}}, i64 %{{.*}})
210  // CHECK-NOT: @llvm.objectsize
211  return ObjectSize3(p);
212}
213
214int Overload0(void *, size_t, void *, size_t);
215int OverloadNoSize(void *, void *);
216
217int OverloadedObjectSize(void *const p PS(0),
218                         void *const c PS(0))
219    __attribute__((overloadable)) __asm__("Overload0");
220
221int OverloadedObjectSize(void *const p, void *const c)
222    __attribute__((overloadable)) __asm__("OverloadNoSize");
223
224// CHECK-LABEL: define void @test6
225void test6() {
226  int known[10], *opaque;
227
228  // CHECK: call i32 @"\01Overload0"
229  gi = OverloadedObjectSize(&known[0], &known[0]);
230
231  // CHECK: call i32 @"\01Overload0"
232  gi = OverloadedObjectSize(&known[0], opaque);
233
234  // CHECK: call i32 @"\01Overload0"
235  gi = OverloadedObjectSize(opaque, &known[0]);
236
237  // CHECK: call i32 @"\01Overload0"
238  gi = OverloadedObjectSize(opaque, opaque);
239}
240
241int Identity(void *p, size_t i) { return i; }
242
243// CHECK-NOT: define void @AsmObjectSize
244int AsmObjectSize0(void *const p PS(0)) __asm__("Identity");
245
246int AsmObjectSize1(void *const p PS(1)) __asm__("Identity");
247
248int AsmObjectSize2(void *const p PS(2)) __asm__("Identity");
249
250int AsmObjectSize3(void *const p PS(3)) __asm__("Identity");
251
252// CHECK-LABEL: define void @test7
253void test7() {
254  struct Foo t[10];
255
256  // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 360)
257  gi = AsmObjectSize0(&t[1]);
258  // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 360)
259  gi = AsmObjectSize1(&t[1]);
260  // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 360)
261  gi = AsmObjectSize2(&t[1]);
262  // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 360)
263  gi = AsmObjectSize3(&t[1]);
264
265  // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 356)
266  gi = AsmObjectSize0(&t[1].t[1]);
267  // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 36)
268  gi = AsmObjectSize1(&t[1].t[1]);
269  // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 356)
270  gi = AsmObjectSize2(&t[1].t[1]);
271  // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 36)
272  gi = AsmObjectSize3(&t[1].t[1]);
273}
274
275// CHECK-LABEL: define void @test8
276void test8(struct Foo *t) {
277  // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 36)
278  gi = AsmObjectSize1(&t[1].t[1]);
279  // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 36)
280  gi = AsmObjectSize3(&t[1].t[1]);
281}
282
283void DifferingObjectSize0(void *const p __attribute__((pass_object_size(0))));
284void DifferingObjectSize1(void *const p __attribute__((pass_object_size(1))));
285void DifferingObjectSize2(void *const p __attribute__((pass_object_size(2))));
286void DifferingObjectSize3(void *const p __attribute__((pass_object_size(3))));
287
288// CHECK-LABEL: define void @test9
289void test9(void *const p __attribute__((pass_object_size(0)))) {
290  // CHECK: @llvm.objectsize
291  DifferingObjectSize2(p);
292
293  // CHECK-NOT: @llvm.objectsize
294  DifferingObjectSize0(p);
295  DifferingObjectSize1(p);
296
297  // CHECK: call void @DifferingObjectSize3(i8* %{{.*}}, i64 0)
298  DifferingObjectSize3(p);
299}
300
301// CHECK-LABEL: define void @test10
302void test10(void *const p __attribute__((pass_object_size(1)))) {
303  // CHECK: @llvm.objectsize
304  DifferingObjectSize2(p);
305  // CHECK: @llvm.objectsize
306  DifferingObjectSize0(p);
307
308  // CHECK-NOT: @llvm.objectsize
309  DifferingObjectSize1(p);
310
311  // CHECK: call void @DifferingObjectSize3(i8* %{{.*}}, i64 0)
312  DifferingObjectSize3(p);
313}
314
315// CHECK-LABEL: define void @test11
316void test11(void *const p __attribute__((pass_object_size(2)))) {
317  // CHECK: @llvm.objectsize
318  DifferingObjectSize0(p);
319  // CHECK: @llvm.objectsize
320  DifferingObjectSize1(p);
321
322  // CHECK-NOT: @llvm.objectsize
323  DifferingObjectSize2(p);
324
325  // CHECK: call void @DifferingObjectSize3(i8* %{{.*}}, i64 0)
326  DifferingObjectSize3(p);
327}
328
329// CHECK-LABEL: define void @test12
330void test12(void *const p __attribute__((pass_object_size(3)))) {
331  // CHECK: @llvm.objectsize
332  DifferingObjectSize0(p);
333  // CHECK: @llvm.objectsize
334  DifferingObjectSize1(p);
335
336  // CHECK-NOT: @llvm.objectsize
337  DifferingObjectSize2(p);
338  DifferingObjectSize3(p);
339}
340
341// CHECK-LABEL: define void @test13
342void test13() {
343  // Ensuring that we don't lower objectsize if the expression has side-effects
344  char c[10];
345  char *p = c;
346
347  // CHECK: @llvm.objectsize
348  ObjectSize0(p);
349
350  // CHECK-NOT: @llvm.objectsize
351  ObjectSize0(++p);
352  ObjectSize0(p++);
353}
354
355// There was a bug where variadic functions with pass_object_size would cause
356// problems in the form of failed assertions.
357void my_sprintf(char *const c __attribute__((pass_object_size(0))), ...) {}
358
359// CHECK-LABEL: define void @test14
360void test14(char *c) {
361  // CHECK: @llvm.objectsize
362  // CHECK: call void (i8*, i64, ...) @my_sprintf
363  my_sprintf(c);
364
365  // CHECK: @llvm.objectsize
366  // CHECK: call void (i8*, i64, ...) @my_sprintf
367  my_sprintf(c, 1, 2, 3);
368}
369