// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -O0 %s -o - 2>&1 | FileCheck %s typedef unsigned long size_t; struct Foo { int t[10]; }; #define PS(N) __attribute__((pass_object_size(N))) int gi = 0; // CHECK-LABEL: define i32 @ObjectSize0(i8* %{{.*}}, i64) int ObjectSize0(void *const p PS(0)) { // CHECK-NOT: @llvm.objectsize return __builtin_object_size(p, 0); } // CHECK-LABEL: define i32 @ObjectSize1(i8* %{{.*}}, i64) int ObjectSize1(void *const p PS(1)) { // CHECK-NOT: @llvm.objectsize return __builtin_object_size(p, 1); } // CHECK-LABEL: define i32 @ObjectSize2(i8* %{{.*}}, i64) int ObjectSize2(void *const p PS(2)) { // CHECK-NOT: @llvm.objectsize return __builtin_object_size(p, 2); } // CHECK-LABEL: define i32 @ObjectSize3(i8* %{{.*}}, i64) int ObjectSize3(void *const p PS(3)) { // CHECK-NOT: @llvm.objectsize return __builtin_object_size(p, 3); } // CHECK-LABEL: define void @test1 void test1() { struct Foo t[10]; // CHECK: call i32 @ObjectSize0(i8* %{{.*}}, i64 360) gi = ObjectSize0(&t[1]); // CHECK: call i32 @ObjectSize1(i8* %{{.*}}, i64 360) gi = ObjectSize1(&t[1]); // CHECK: call i32 @ObjectSize2(i8* %{{.*}}, i64 360) gi = ObjectSize2(&t[1]); // CHECK: call i32 @ObjectSize3(i8* %{{.*}}, i64 360) gi = ObjectSize3(&t[1]); // CHECK: call i32 @ObjectSize0(i8* %{{.*}}, i64 356) gi = ObjectSize0(&t[1].t[1]); // CHECK: call i32 @ObjectSize1(i8* %{{.*}}, i64 36) gi = ObjectSize1(&t[1].t[1]); // CHECK: call i32 @ObjectSize2(i8* %{{.*}}, i64 356) gi = ObjectSize2(&t[1].t[1]); // CHECK: call i32 @ObjectSize3(i8* %{{.*}}, i64 36) gi = ObjectSize3(&t[1].t[1]); } // CHECK-LABEL: define void @test2 void test2(struct Foo *t) { // CHECK: [[VAR:%[0-9]+]] = call i64 @llvm.objectsize // CHECK: call i32 @ObjectSize1(i8* %{{.*}}, i64 [[VAR]]) gi = ObjectSize1(&t->t[1]); // CHECK: call i32 @ObjectSize3(i8* %{{.*}}, i64 36) gi = ObjectSize3(&t->t[1]); } // CHECK-LABEL: define i32 @_Z27NoViableOverloadObjectSize0Pv int NoViableOverloadObjectSize0(void *const p) __attribute__((overloadable)) { // CHECK: @llvm.objectsize return __builtin_object_size(p, 0); } // CHECK-LABEL: define i32 @_Z27NoViableOverloadObjectSize1Pv int NoViableOverloadObjectSize1(void *const p) __attribute__((overloadable)) { // CHECK: @llvm.objectsize return __builtin_object_size(p, 1); } // CHECK-LABEL: define i32 @_Z27NoViableOverloadObjectSize2Pv int NoViableOverloadObjectSize2(void *const p) __attribute__((overloadable)) { // CHECK: @llvm.objectsize return __builtin_object_size(p, 2); } // CHECK-LABEL: define i32 @_Z27NoViableOverloadObjectSize3Pv int NoViableOverloadObjectSize3(void *const p) __attribute__((overloadable)) { // CHECK-NOT: @llvm.objectsize return __builtin_object_size(p, 3); } // CHECK-LABEL: define i32 @_Z27NoViableOverloadObjectSize0Pv // CHECK-NOT: @llvm.objectsize int NoViableOverloadObjectSize0(void *const p PS(0)) __attribute__((overloadable)) { return __builtin_object_size(p, 0); } int NoViableOverloadObjectSize1(void *const p PS(1)) __attribute__((overloadable)) { return __builtin_object_size(p, 1); } int NoViableOverloadObjectSize2(void *const p PS(2)) __attribute__((overloadable)) { return __builtin_object_size(p, 2); } int NoViableOverloadObjectSize3(void *const p PS(3)) __attribute__((overloadable)) { return __builtin_object_size(p, 3); } const static int SHOULDNT_BE_CALLED = -100; int NoViableOverloadObjectSize0(void *const p PS(0)) __attribute__((overloadable, enable_if(p == 0, "never selected"))) { return SHOULDNT_BE_CALLED; } int NoViableOverloadObjectSize1(void *const p PS(1)) __attribute__((overloadable, enable_if(p == 0, "never selected"))) { return SHOULDNT_BE_CALLED; } int NoViableOverloadObjectSize2(void *const p PS(2)) __attribute__((overloadable, enable_if(p == 0, "never selected"))) { return SHOULDNT_BE_CALLED; } int NoViableOverloadObjectSize3(void *const p PS(3)) __attribute__((overloadable, enable_if(p == 0, "never selected"))) { return SHOULDNT_BE_CALLED; } // CHECK-LABEL: define void @test3 void test3() { struct Foo t[10]; // CHECK: call i32 @_Z27NoViableOverloadObjectSize0PvU17pass_object_size0(i8* %{{.*}}, i64 360) gi = NoViableOverloadObjectSize0(&t[1]); // CHECK: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 360) gi = NoViableOverloadObjectSize1(&t[1]); // CHECK: call i32 @_Z27NoViableOverloadObjectSize2PvU17pass_object_size2(i8* %{{.*}}, i64 360) gi = NoViableOverloadObjectSize2(&t[1]); // CHECK: call i32 @_Z27NoViableOverloadObjectSize3PvU17pass_object_size3(i8* %{{.*}}, i64 360) gi = NoViableOverloadObjectSize3(&t[1]); // CHECK: call i32 @_Z27NoViableOverloadObjectSize0PvU17pass_object_size0(i8* %{{.*}}, i64 356) gi = NoViableOverloadObjectSize0(&t[1].t[1]); // CHECK: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 36) gi = NoViableOverloadObjectSize1(&t[1].t[1]); // CHECK: call i32 @_Z27NoViableOverloadObjectSize2PvU17pass_object_size2(i8* %{{.*}}, i64 356) gi = NoViableOverloadObjectSize2(&t[1].t[1]); // CHECK: call i32 @_Z27NoViableOverloadObjectSize3PvU17pass_object_size3(i8* %{{.*}}, i64 36) gi = NoViableOverloadObjectSize3(&t[1].t[1]); } // CHECK-LABEL: define void @test4 void test4(struct Foo *t) { // CHECK: call i32 @_Z27NoViableOverloadObjectSize0PvU17pass_object_size0(i8* %{{.*}}, i64 %{{.*}}) gi = NoViableOverloadObjectSize0(&t[1]); // CHECK: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 %{{.*}}) gi = NoViableOverloadObjectSize1(&t[1]); // CHECK: call i32 @_Z27NoViableOverloadObjectSize2PvU17pass_object_size2(i8* %{{.*}}, i64 %{{.*}}) gi = NoViableOverloadObjectSize2(&t[1]); // CHECK: call i32 @_Z27NoViableOverloadObjectSize3PvU17pass_object_size3(i8* %{{.*}}, i64 0) gi = NoViableOverloadObjectSize3(&t[1]); // CHECK: call i32 @_Z27NoViableOverloadObjectSize0PvU17pass_object_size0(i8* %{{.*}}, i64 %{{.*}}) gi = NoViableOverloadObjectSize0(&t[1].t[1]); // CHECK: [[VAR:%[0-9]+]] = call i64 @llvm.objectsize // CHECK: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 [[VAR]]) gi = NoViableOverloadObjectSize1(&t[1].t[1]); // CHECK: call i32 @_Z27NoViableOverloadObjectSize2PvU17pass_object_size2(i8* %{{.*}}, i64 %{{.*}}) gi = NoViableOverloadObjectSize2(&t[1].t[1]); // CHECK: call i32 @_Z27NoViableOverloadObjectSize3PvU17pass_object_size3(i8* %{{.*}}, i64 36) gi = NoViableOverloadObjectSize3(&t[1].t[1]); } void test5() { struct Foo t[10]; int (*f)(void *) = &NoViableOverloadObjectSize0; gi = f(&t[1]); } // CHECK-LABEL: define i32 @IndirectObjectSize0 int IndirectObjectSize0(void *const p PS(0)) { // CHECK: call i32 @ObjectSize0(i8* %{{.*}}, i64 %{{.*}}) // CHECK-NOT: @llvm.objectsize return ObjectSize0(p); } // CHECK-LABEL: define i32 @IndirectObjectSize1 int IndirectObjectSize1(void *const p PS(1)) { // CHECK: call i32 @ObjectSize1(i8* %{{.*}}, i64 %{{.*}}) // CHECK-NOT: @llvm.objectsize return ObjectSize1(p); } // CHECK-LABEL: define i32 @IndirectObjectSize2 int IndirectObjectSize2(void *const p PS(2)) { // CHECK: call i32 @ObjectSize2(i8* %{{.*}}, i64 %{{.*}}) // CHECK-NOT: @llvm.objectsize return ObjectSize2(p); } // CHECK-LABEL: define i32 @IndirectObjectSize3 int IndirectObjectSize3(void *const p PS(3)) { // CHECK: call i32 @ObjectSize3(i8* %{{.*}}, i64 %{{.*}}) // CHECK-NOT: @llvm.objectsize return ObjectSize3(p); } int Overload0(void *, size_t, void *, size_t); int OverloadNoSize(void *, void *); int OverloadedObjectSize(void *const p PS(0), void *const c PS(0)) __attribute__((overloadable)) __asm__("Overload0"); int OverloadedObjectSize(void *const p, void *const c) __attribute__((overloadable)) __asm__("OverloadNoSize"); // CHECK-LABEL: define void @test6 void test6() { int known[10], *opaque; // CHECK: call i32 @"\01Overload0" gi = OverloadedObjectSize(&known[0], &known[0]); // CHECK: call i32 @"\01Overload0" gi = OverloadedObjectSize(&known[0], opaque); // CHECK: call i32 @"\01Overload0" gi = OverloadedObjectSize(opaque, &known[0]); // CHECK: call i32 @"\01Overload0" gi = OverloadedObjectSize(opaque, opaque); } int Identity(void *p, size_t i) { return i; } // CHECK-NOT: define void @AsmObjectSize int AsmObjectSize0(void *const p PS(0)) __asm__("Identity"); int AsmObjectSize1(void *const p PS(1)) __asm__("Identity"); int AsmObjectSize2(void *const p PS(2)) __asm__("Identity"); int AsmObjectSize3(void *const p PS(3)) __asm__("Identity"); // CHECK-LABEL: define void @test7 void test7() { struct Foo t[10]; // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 360) gi = AsmObjectSize0(&t[1]); // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 360) gi = AsmObjectSize1(&t[1]); // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 360) gi = AsmObjectSize2(&t[1]); // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 360) gi = AsmObjectSize3(&t[1]); // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 356) gi = AsmObjectSize0(&t[1].t[1]); // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 36) gi = AsmObjectSize1(&t[1].t[1]); // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 356) gi = AsmObjectSize2(&t[1].t[1]); // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 36) gi = AsmObjectSize3(&t[1].t[1]); } // CHECK-LABEL: define void @test8 void test8(struct Foo *t) { // CHECK: [[VAR:%[0-9]+]] = call i64 @llvm.objectsize // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 [[VAR]]) gi = AsmObjectSize1(&t[1].t[1]); // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 36) gi = AsmObjectSize3(&t[1].t[1]); } void DifferingObjectSize0(void *const p __attribute__((pass_object_size(0)))); void DifferingObjectSize1(void *const p __attribute__((pass_object_size(1)))); void DifferingObjectSize2(void *const p __attribute__((pass_object_size(2)))); void DifferingObjectSize3(void *const p __attribute__((pass_object_size(3)))); // CHECK-LABEL: define void @test9 void test9(void *const p __attribute__((pass_object_size(0)))) { // CHECK: @llvm.objectsize DifferingObjectSize2(p); // CHECK-NOT: @llvm.objectsize DifferingObjectSize0(p); DifferingObjectSize1(p); // CHECK: call void @DifferingObjectSize3(i8* %{{.*}}, i64 0) DifferingObjectSize3(p); } // CHECK-LABEL: define void @test10 void test10(void *const p __attribute__((pass_object_size(1)))) { // CHECK: @llvm.objectsize DifferingObjectSize2(p); // CHECK: @llvm.objectsize DifferingObjectSize0(p); // CHECK-NOT: @llvm.objectsize DifferingObjectSize1(p); // CHECK: call void @DifferingObjectSize3(i8* %{{.*}}, i64 0) DifferingObjectSize3(p); } // CHECK-LABEL: define void @test11 void test11(void *const p __attribute__((pass_object_size(2)))) { // CHECK: @llvm.objectsize DifferingObjectSize0(p); // CHECK: @llvm.objectsize DifferingObjectSize1(p); // CHECK-NOT: @llvm.objectsize DifferingObjectSize2(p); // CHECK: call void @DifferingObjectSize3(i8* %{{.*}}, i64 0) DifferingObjectSize3(p); } // CHECK-LABEL: define void @test12 void test12(void *const p __attribute__((pass_object_size(3)))) { // CHECK: @llvm.objectsize DifferingObjectSize0(p); // CHECK: @llvm.objectsize DifferingObjectSize1(p); // CHECK-NOT: @llvm.objectsize DifferingObjectSize2(p); DifferingObjectSize3(p); } // CHECK-LABEL: define void @test13 void test13() { char c[10]; unsigned i = 0; char *p = c; // CHECK: @llvm.objectsize ObjectSize0(p); // Allow side-effects, since they always need to happen anyway. Just make sure // we don't perform them twice. // CHECK: = add // CHECK-NOT: = add // CHECK: @llvm.objectsize // CHECK: call i32 @ObjectSize0 ObjectSize0(p + ++i); // CHECK: = add // CHECK: @llvm.objectsize // CHECK-NOT: = add // CHECK: call i32 @ObjectSize0 ObjectSize0(p + i++); } // There was a bug where variadic functions with pass_object_size would cause // problems in the form of failed assertions. void my_sprintf(char *const c __attribute__((pass_object_size(0))), ...) {} // CHECK-LABEL: define void @test14 void test14(char *c) { // CHECK: @llvm.objectsize // CHECK: call void (i8*, i64, ...) @my_sprintf my_sprintf(c); // CHECK: @llvm.objectsize // CHECK: call void (i8*, i64, ...) @my_sprintf my_sprintf(c, 1, 2, 3); } void pass_size_unsigned(unsigned *const PS(0)); // Bug: we weren't lowering to the proper @llvm.objectsize for pointers that // don't turn into i8*s, which caused crashes. // CHECK-LABEL: define void @test15 void test15(unsigned *I) { // CHECK: @llvm.objectsize.i64.p0i32 // CHECK: call void @pass_size_unsigned pass_size_unsigned(I); } void pass_size_as1(__attribute__((address_space(1))) void *const PS(0)); void pass_size_unsigned_as1( __attribute__((address_space(1))) unsigned *const PS(0)); // CHECK-LABEL: define void @test16 void test16(__attribute__((address_space(1))) unsigned *I) { // CHECK: call i64 @llvm.objectsize.i64.p1i8 // CHECK: call void @pass_size_as1 pass_size_as1(I); // CHECK: call i64 @llvm.objectsize.i64.p1i32 // CHECK: call void @pass_size_unsigned_as1 pass_size_unsigned_as1(I); } // This used to cause assertion failures, since we'd try to emit the statement // expression (and definitions for `a`) twice. // CHECK-LABEL: define void @test17 void test17(char *C) { // Check for 65535 to see if we're emitting this pointer twice. // CHECK: 65535 // CHECK-NOT: 65535 // CHECK: @llvm.objectsize.i64.p0i8(i8* [[PTR:%[^,]+]], // CHECK-NOT: 65535 // CHECK: call i32 @ObjectSize0(i8* [[PTR]] ObjectSize0(C + ({ int a = 65535; a; })); }