diff options
Diffstat (limited to 'test/CodeGenObjC')
32 files changed, 1639 insertions, 57 deletions
diff --git a/test/CodeGenObjC/Inputs/strong_in_union.h b/test/CodeGenObjC/Inputs/strong_in_union.h new file mode 100644 index 000000000000..abe4549055c6 --- /dev/null +++ b/test/CodeGenObjC/Inputs/strong_in_union.h @@ -0,0 +1,10 @@ +#ifndef STRONG_IN_UNION_H +#define STRONG_IN_UNION_H +#pragma clang system_header + +typedef union { + id f0; + int *f1; +} U; + +#endif // STRONG_IN_UNION_H diff --git a/test/CodeGenObjC/arc-foreach.m b/test/CodeGenObjC/arc-foreach.m index 77cb068187fa..ffeb37247b1b 100644 --- a/test/CodeGenObjC/arc-foreach.m +++ b/test/CodeGenObjC/arc-foreach.m @@ -42,7 +42,7 @@ void test0(NSArray *array) { // Initialize the fast enumaration state. // CHECK-LP64-NEXT: [[T0:%.*]] = bitcast [[STATE_T]]* [[STATE]] to i8* -// CHECK-LP64-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 64, i32 8, i1 false) +// CHECK-LP64-NEXT: call void @llvm.memset.p0i8.i64(i8* align 8 [[T0]], i8 0, i64 64, i1 false) // Evaluate the collection expression and retain. // CHECK-LP64-NEXT: [[T0:%.*]] = load [[ARRAY_T]]*, [[ARRAY_T]]** [[ARRAY]], align 8 diff --git a/test/CodeGenObjC/arc.m b/test/CodeGenObjC/arc.m index d34156ee3473..3243952a36b3 100644 --- a/test/CodeGenObjC/arc.m +++ b/test/CodeGenObjC/arc.m @@ -7,30 +7,30 @@ // RUN: %clang_cc1 -fobjc-runtime=macosx-10.7.0 -triple x86_64-apple-darwin11 -Wno-objc-root-class -Wno-incompatible-pointer-types -Wno-arc-unsafe-retained-assign -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=ARC-NATIVE %s // ARC-ALIEN: declare extern_weak void @objc_storeStrong(i8**, i8*) -// ARC-ALIEN: declare extern_weak i8* @objc_retain(i8* returned) -// ARC-ALIEN: declare extern_weak i8* @objc_autoreleaseReturnValue(i8* returned) +// ARC-ALIEN: declare extern_weak i8* @objc_retain(i8*) +// ARC-ALIEN: declare extern_weak i8* @objc_autoreleaseReturnValue(i8*) // ARC-ALIEN: declare i8* @objc_msgSend(i8*, i8*, ...) [[NLB:#[0-9]+]] // ARC-ALIEN: declare extern_weak void @objc_release(i8*) -// ARC-ALIEN: declare extern_weak i8* @objc_retainAutoreleasedReturnValue(i8* returned) +// ARC-ALIEN: declare extern_weak i8* @objc_retainAutoreleasedReturnValue(i8*) // ARC-ALIEN: declare extern_weak i8* @objc_initWeak(i8**, i8*) // ARC-ALIEN: declare extern_weak i8* @objc_storeWeak(i8**, i8*) // ARC-ALIEN: declare extern_weak i8* @objc_loadWeakRetained(i8**) // ARC-ALIEN: declare extern_weak void @objc_destroyWeak(i8**) -// declare extern_weak i8* @objc_autorelease(i8*) -// ARC-ALIEN: declare extern_weak i8* @objc_retainAutorelease(i8* returned) +// ARC-ALIEN: declare extern_weak i8* @objc_autorelease(i8*) +// ARC-ALIEN: declare extern_weak i8* @objc_retainAutorelease(i8*) // ARC-NATIVE: declare void @objc_storeStrong(i8**, i8*) -// ARC-NATIVE: declare i8* @objc_retain(i8* returned) [[NLB:#[0-9]+]] -// ARC-NATIVE: declare i8* @objc_autoreleaseReturnValue(i8* returned) +// ARC-NATIVE: declare i8* @objc_retain(i8*) [[NLB:#[0-9]+]] +// ARC-NATIVE: declare i8* @objc_autoreleaseReturnValue(i8*) // ARC-NATIVE: declare i8* @objc_msgSend(i8*, i8*, ...) [[NLB]] // ARC-NATIVE: declare void @objc_release(i8*) [[NLB]] -// ARC-NATIVE: declare i8* @objc_retainAutoreleasedReturnValue(i8* returned) +// ARC-NATIVE: declare i8* @objc_retainAutoreleasedReturnValue(i8*) // ARC-NATIVE: declare i8* @objc_initWeak(i8**, i8*) // ARC-NATIVE: declare i8* @objc_storeWeak(i8**, i8*) // ARC-NATIVE: declare i8* @objc_loadWeakRetained(i8**) // ARC-NATIVE: declare void @objc_destroyWeak(i8**) -// declare i8* @objc_autorelease(i8*) -// ARC-NATIVE: declare i8* @objc_retainAutorelease(i8* returned) +// ARC-NATIVE: declare i8* @objc_autorelease(i8*) +// ARC-NATIVE: declare i8* @objc_retainAutorelease(i8*) // CHECK-LABEL: define void @test0 void test0(id x) { @@ -507,7 +507,7 @@ void test19() { // CHECK: [[X:%.*]] = alloca [5 x i8*], align 16 // CHECK: call void @llvm.lifetime.start // CHECK-NEXT: [[T0:%.*]] = bitcast [5 x i8*]* [[X]] to i8* - // CHECK: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 40, i32 16, i1 false) + // CHECK: call void @llvm.memset.p0i8.i64(i8* align 16 [[T0]], i8 0, i64 40, i1 false) id x[5]; extern id test19_helper(void); @@ -538,6 +538,7 @@ void test20(unsigned n) { // CHECK-LABEL: define void @test20 // CHECK: [[N:%.*]] = alloca i32, align 4 // CHECK-NEXT: [[SAVED_STACK:%.*]] = alloca i8* + // CHECK-NEXT: [[VLA_EXPR:%.*]] = alloca i64, align 8 // CHECK-NEXT: store i32 {{%.*}}, i32* [[N]], align 4 id x[n]; @@ -553,10 +554,13 @@ void test20(unsigned n) { // Allocate the VLA. // CHECK-NEXT: [[VLA:%.*]] = alloca i8*, i64 [[DIM]], align 16 + // Store the VLA #elements expression. + // CHECK-NEXT: store i64 [[DIM]], i64* [[VLA_EXPR]], align 8 + // Zero-initialize. // CHECK-NEXT: [[T0:%.*]] = bitcast i8** [[VLA]] to i8* // CHECK-NEXT: [[T1:%.*]] = mul nuw i64 [[DIM]], 8 - // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 [[T1]], i32 16, i1 false) + // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 16 [[T0]], i8 0, i64 [[T1]], i1 false) // Destroy. // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8*, i8** [[VLA]], i64 [[DIM]] @@ -579,6 +583,7 @@ void test21(unsigned n) { // CHECK-LABEL: define void @test21 // CHECK: [[N:%.*]] = alloca i32, align 4 // CHECK-NEXT: [[SAVED_STACK:%.*]] = alloca i8* + // CHECK-NEXT: [[VLA_EXPR:%.*]] = alloca i64, align 8 // CHECK-NEXT: store i32 {{%.*}}, i32* [[N]], align 4 id x[2][n][3]; @@ -595,11 +600,14 @@ void test21(unsigned n) { // CHECK-NEXT: [[T0:%.*]] = mul nuw i64 2, [[DIM]] // CHECK-NEXT: [[VLA:%.*]] = alloca [3 x i8*], i64 [[T0]], align 16 + // Store the VLA #elements expression. + // CHECK-NEXT: store i64 [[DIM]], i64* [[VLA_EXPR]], align 8 + // Zero-initialize. // CHECK-NEXT: [[T0:%.*]] = bitcast [3 x i8*]* [[VLA]] to i8* // CHECK-NEXT: [[T1:%.*]] = mul nuw i64 2, [[DIM]] // CHECK-NEXT: [[T2:%.*]] = mul nuw i64 [[T1]], 24 - // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 [[T2]], i32 16, i1 false) + // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 16 [[T0]], i8 0, i64 [[T2]], i1 false) // Destroy. // CHECK-NEXT: [[T0:%.*]] = mul nuw i64 2, [[DIM]] @@ -1504,9 +1512,7 @@ void test68(void) { // CHECK: [[SELF:%.*]] = alloca [[TEST69:%.*]]*, align 8 // CHECK: [[T0:%.*]] = load [[TEST69]]*, [[TEST69]]** [[SELF]], align 8 // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST69]]* [[T0]] to i8* -// CHECK-NEXT: [[RETAIN:%.*]] = call i8* @objc_retain(i8* [[T1]]) -// CHECK-NEXT: [[AUTORELEASE:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[RETAIN]]) -// CHECK-NEXT: ret i8* [[AUTORELEASE]] +// CHECK-NEXT: ret i8* [[T1]] // rdar://problem/10907547 void test70(id i) { @@ -1520,6 +1526,37 @@ void test70(id i) { }; } +// Be sure that we emit lifetime intrinsics only after dtors +struct AggDtor { + char cs[40]; + id x; +}; + +struct AggDtor getAggDtor(void); + +// CHECK-LABEL: define void @test71 +void test71(void) { + // FIXME: It would be nice if the __destructor_8_s40 for the first call (and + // the following lifetime.end) came before the second call. + // + // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP1:[^ ]+]] to i8* + // CHECK: call void @llvm.lifetime.start.p0i8({{[^,]+}}, i8* %[[T]]) + // CHECK: call void @getAggDtor(%struct.AggDtor* sret %[[TMP1]]) + // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP2:[^ ]+]] to i8* + // CHECK: call void @llvm.lifetime.start.p0i8({{[^,]+}}, i8* %[[T]]) + // CHECK: call void @getAggDtor(%struct.AggDtor* sret %[[TMP2]]) + // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP2]] to i8** + // CHECK: call void @__destructor_8_s40(i8** %[[T]]) + // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP2:[^ ]+]] to i8* + // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* %[[T]]) + // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP1]] to i8** + // CHECK: call void @__destructor_8_s40(i8** %[[T]]) + // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP1:[^ ]+]] to i8* + // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* %[[T]]) + getAggDtor(); + getAggDtor(); +} + // ARC-ALIEN: attributes [[NLB]] = { nonlazybind } // ARC-NATIVE: attributes [[NLB]] = { nonlazybind } // CHECK: attributes [[NUW]] = { nounwind } diff --git a/test/CodeGenObjC/availability-dso-local.m b/test/CodeGenObjC/availability-dso-local.m new file mode 100644 index 000000000000..8ff41d87f1e2 --- /dev/null +++ b/test/CodeGenObjC/availability-dso-local.m @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -triple thumbv7-apple-ios10.0.0 -emit-llvm -fvisibility hidden -w %s -o - | FileCheck %s + +// CHECK: @"OBJC_CLASS_$_a" = hidden global %struct._class_t + +__attribute__((availability(ios, introduced = 11.0))) @interface a @end + @implementation a @end diff --git a/test/CodeGenObjC/blocks.m b/test/CodeGenObjC/blocks.m index d485bb4053b0..05880dea79b8 100644 --- a/test/CodeGenObjC/blocks.m +++ b/test/CodeGenObjC/blocks.m @@ -79,10 +79,9 @@ void test2(Test2 *x) { // Then we initialize the block, blah blah blah. // CHECK: call void @test2_helper( - // Finally, kill the variable with BLOCK_FIELD_IS_BYREF. We're not - // supposed to pass BLOCK_FIELD_IS_WEAK here. + // Finally, kill the variable with BLOCK_FIELD_IS_BYREF. // CHECK: [[T0:%.*]] = bitcast [[WEAK_T]]* [[WEAKX]] to i8* - // CHECK: call void @_Block_object_dispose(i8* [[T0]], i32 8) + // CHECK: call void @_Block_object_dispose(i8* [[T0]], i32 24) __attribute__((objc_gc(weak))) __block Test2 *weakX = x; test2_helper(^{ [weakX destroy]; }); diff --git a/test/CodeGenObjC/builtin-memfns.m b/test/CodeGenObjC/builtin-memfns.m index bb425c037c64..6cc91b109cf5 100644 --- a/test/CodeGenObjC/builtin-memfns.m +++ b/test/CodeGenObjC/builtin-memfns.m @@ -5,6 +5,6 @@ void *memcpy(void *restrict s1, const void *restrict s2, unsigned long n); // PR13697 void test1(int *a, id b) { // CHECK: @test1 - // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 8, i32 1, i1 false) + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 8, i1 false) memcpy(a, b, 8); } diff --git a/test/CodeGenObjC/constant-strings.m b/test/CodeGenObjC/constant-strings.m index a1daa9284b81..df821968917a 100644 --- a/test/CodeGenObjC/constant-strings.m +++ b/test/CodeGenObjC/constant-strings.m @@ -14,5 +14,18 @@ // RUN: %clang_cc1 -triple x86_64-macho -fobjc-runtime=gcc -fconstant-string-class NSConstantString -emit-llvm -o %t %s // RUN: FileCheck --check-prefix=CHECK-GNU-WITH-CLASS < %t %s // CHECK-GNU-WITH-CLASS: NSConstantString -id a = @"Hello World!"; +// +// RUN: %clang_cc1 -triple x86_64-unknown-freebsd -fobjc-runtime=gnustep-2.0 -emit-llvm -o %t %s +// RUN: FileCheck --check-prefix=CHECK-GNUSTEP2 < %t %s +// CHECK-GNUSTEP2: @._OBJC_CLASS_NSConstantString = external global i8* +// CHECK-GNUSTEP2: @0 = private unnamed_addr constant [13 x i8] c"Hello World!\00", align 1 +// CHECK-GNUSTEP2: @.objc_string = private global { i8**, i32, i32, i32, i32, i8* } { i8** @._OBJC_CLASS_NSConstantString, i32 0, i32 12, i32 12, i32 0, i8* getelementptr inbounds ([13 x i8], [13 x i8]* @0, i64 0, i64 0) }, section "__objc_constant_string", align 8 +// CHECK-GNUSTEP2: @b = global i8* inttoptr (i64 -3340545023602065388 to i8*), align 8 +// CHECK-GNUSTEP2: @.objc_str_Hello_World = linkonce_odr hidden global { i8**, i32, i32, i32, i32, i8* } { i8** @._OBJC_CLASS_NSConstantString, i32 0, i32 11, i32 11, i32 0, i8* getelementptr inbounds ([12 x i8], [12 x i8]* @1, i64 0, i64 0) }, section "__objc_constant_string", comdat, align 8 +// CHECK-GNUSTEP2: @c = +// CHECK-SAME-GNUSTEP2: @.objc_str_Hello_World +// +id a = @"Hello World!"; +id b = @"hi"; +id c = @"Hello World"; diff --git a/test/CodeGenObjC/debug-info-category.m b/test/CodeGenObjC/debug-info-category.m new file mode 100644 index 000000000000..faca3a49c23e --- /dev/null +++ b/test/CodeGenObjC/debug-info-category.m @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -dwarf-version=5 -emit-llvm -debug-info-kind=limited -w -triple x86_64-apple-darwin10 %s -o - | FileCheck %s --check-prefix CHECK --check-prefix DWARF5 +// RUN: %clang_cc1 -dwarf-version=4 -emit-llvm -debug-info-kind=limited -w -triple x86_64-apple-darwin10 %s -o - | FileCheck %s --check-prefix CHECK --check-prefix DWARF4 + +@interface Foo { + int integer; +} + +- (int)integer; +- (id)integer:(int)_integer; +@end + +@implementation Foo +- (int)integer { + return integer; +} + +- (id)integer:(int)_integer { + integer = _integer; + return self; +} +@end + +@interface Foo (Bar) ++ (id)zero:(Foo *)zeroend; +- (id)add:(Foo *)addend; +@end + +@implementation Foo (Bar) ++ (id)zero:(Foo *)zeroend { + return [self integer:0]; +} +- (id)add:(Foo *)addend { + return [self integer:[self integer] + [addend integer]]; +} +@end + +// CHECK: ![[STRUCT:.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Foo" + +// DWARF5: !DISubprogram(name: "-[Foo integer]", scope: ![[STRUCT]], {{.*}}isDefinition: false +// DWARF5: !DISubprogram(name: "-[Foo integer:]", scope: ![[STRUCT]], {{.*}}isDefinition: false +// DWARF5: !DISubprogram(name: "+[Foo(Bar) zero:]", scope: ![[STRUCT]], {{.*}}isDefinition: false +// DWARF5: !DISubprogram(name: "-[Foo(Bar) add:]", scope: ![[STRUCT]], {{.*}}isDefinition: false + +// DWARF4-NOT: !DISubprogram(name: "-[Foo integer]", scope: ![[STRUCT]], {{.*}}isDefinition: false +// DWARF4-NOT: !DISubprogram(name: "-[Foo integer:]", scope: ![[STRUCT]], {{.*}}isDefinition: false +// DWARF4-NOT: !DISubprogram(name: "+[Foo(Bar) zero:]", scope: ![[STRUCT]], {{.*}}isDefinition: false +// DWARF4-NOT: !DISubprogram(name: "-[Foo(Bar) add:]", scope: ![[STRUCT]], {{.*}}isDefinition: false + +// CHECK: = distinct !DISubprogram(name: "-[Foo integer]"{{.*}}isDefinition: true +// CHECK: = distinct !DISubprogram(name: "-[Foo integer:]"{{.*}}isDefinition: true +// CHECK: = distinct !DISubprogram(name: "+[Foo(Bar) zero:]"{{.*}}isDefinition: true +// CHECK: = distinct !DISubprogram(name: "-[Foo(Bar) add:]"{{.*}}isDefinition: true diff --git a/test/CodeGenObjC/disable-tail-call-escaping-block.m b/test/CodeGenObjC/disable-tail-call-escaping-block.m new file mode 100644 index 000000000000..48b0eda5a562 --- /dev/null +++ b/test/CodeGenObjC/disable-tail-call-escaping-block.m @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -fno-escaping-block-tail-calls -emit-llvm -o - %s | FileCheck %s + +// CHECK-LABEL: define void @test( +// CHECK: store i8* bitcast (void (i8*)* @[[TEST_BLOCK_INVOKE0:.*]] to i8*) +// CHECK: store i8* bitcast (void (i8*)* @[[TEST_BLOCK_INVOKE1:.*]] to i8*) +// CHECK: store i8* bitcast (void (i8*)* @[[TEST_BLOCK_INVOKE2:.*]] to i8*) +// CHECK: store i8* bitcast (void (i8*)* @[[TEST_BLOCK_INVOKE3:.*]] to i8*) +// CHECK: store i8* bitcast (void (i8*)* @[[TEST_BLOCK_INVOKE4:.*]] to i8*) +// CHECK: store i8* bitcast (void (i8*)* @[[TEST_BLOCK_INVOKE5:.*]] to i8*) +// CHECK: store i8* bitcast (void (i8*)* @[[TEST_BLOCK_INVOKE6:.*]] to i8*) + +// CHECK: define internal void @[[TEST_BLOCK_INVOKE0]]({{.*}}) #[[DISABLEATTR:.*]] { +// CHECK: define internal void @[[TEST_BLOCK_INVOKE1]]({{.*}}) #[[ENABLEATTR:.*]] { +// CHECK: define internal void @[[TEST_BLOCK_INVOKE2]]({{.*}}) #[[DISABLEATTR]] { +// CHECK: define internal void @[[TEST_BLOCK_INVOKE3]]({{.*}}) #[[DISABLEATTR]] { +// CHECK: define internal void @[[TEST_BLOCK_INVOKE4]]({{.*}}) #[[ENABLEATTR]] { +// CHECK: define internal void @[[TEST_BLOCK_INVOKE5]]({{.*}}) #[[DISABLEATTR]] { +// CHECK: define internal void @[[TEST_BLOCK_INVOKE6]]({{.*}}) #[[ENABLEATTR]] { + +// CHECK: attributes #[[ENABLEATTR]] = {{{.*}}"disable-tail-calls"="false"{{.*}}} +// CHECK: attributes #[[DISABLEATTR]] = {{{.*}}"disable-tail-calls"="true"{{.*}}} + +typedef void (^BlockTy)(void); +typedef void (*NoEscapeFnTy)(__attribute__((noescape)) BlockTy); + +void callee0(__attribute__((noescape)) BlockTy); +void callee1(BlockTy); + +__attribute__((objc_root_class)) +@interface C0 +-(void)m0:(__attribute__((noescape)) BlockTy)p; +-(void)m1:(BlockTy)p; +@end + +@implementation C0 +-(void)m0:(__attribute__((noescape)) BlockTy)p {} +-(void)m1:(BlockTy)p {} +@end + +NoEscapeFnTy noescapefunc; + +void test(id a, C0 *c0) { + BlockTy b0 = ^{ (void)a; }; // disable tail-call optimization. + callee0(b0); + callee0(^{ (void)a; }); // enable tail-call optimization. + callee1(^{ (void)a; }); // disable tail-call optimization. + + BlockTy b1 = ^{ (void)a; }; // disable tail-call optimization. + [c0 m0:b1]; + [c0 m0:^{ (void)a; }]; // enable tail-call optimization. + [c0 m1:^{ (void)a; }]; // disable tail-call optimization. + + noescapefunc(^{ (void)a; }); // enable tail-call optimization. +} diff --git a/test/CodeGenObjC/dllstorage.m b/test/CodeGenObjC/dllstorage.m index a2665eefad85..2cc4dc72a0cb 100644 --- a/test/CodeGenObjC/dllstorage.m +++ b/test/CodeGenObjC/dllstorage.m @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -fdeclspec -fobjc-runtime=ios -fobjc-exceptions -S -emit-llvm -o - %s | FileCheck -check-prefix CHECK-IR %s -// RUN: %clang_cc1 -triple i686-windows-itanium -fms-extensions -fobjc-runtime=macosx -fdeclspec -fobjc-exceptions -S -emit-llvm -o - %s | FileCheck -check-prefix CHECK-IR %s -// RUN: %clang_cc1 -triple i686-windows-itanium -fms-extensions -fobjc-runtime=objfw -fdeclspec -fobjc-exceptions -S -emit-llvm -o - %s | FileCheck -check-prefix CHECK-FW %s +// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -fdeclspec -fobjc-runtime=ios -fobjc-exceptions -S -emit-llvm -o - %s | FileCheck -allow-deprecated-dag-overlap -check-prefix CHECK-IR %s +// RUN: %clang_cc1 -triple i686-windows-itanium -fms-extensions -fobjc-runtime=macosx -fdeclspec -fobjc-exceptions -S -emit-llvm -o - %s | FileCheck -allow-deprecated-dag-overlap -check-prefix CHECK-IR %s +// RUN: %clang_cc1 -triple i686-windows-itanium -fms-extensions -fobjc-runtime=objfw -fdeclspec -fobjc-exceptions -S -emit-llvm -o - %s | FileCheck -allow-deprecated-dag-overlap -check-prefix CHECK-FW %s // CHECK-IR-DAG: @_objc_empty_cache = external dllimport global %struct._objc_cache @@ -16,11 +16,11 @@ __declspec(dllexport) @interface J : I @end -// CHECK-IR-DAG: @"OBJC_METACLASS_$_J" = dllexport global %struct._class_t -// CHECK-IR-DAG: @"OBJC_CLASS_$_J" = dllexport global %struct._class_t +// CHECK-IR-DAG: @"OBJC_METACLASS_$_J" = dso_local dllexport global %struct._class_t +// CHECK-IR-DAG: @"OBJC_CLASS_$_J" = dso_local dllexport global %struct._class_t -// CHECK-FW-DAG: @_OBJC_METACLASS_J = dllexport global -// CHECK-FW-DAG: @_OBJC_CLASS_J = dllexport global +// CHECK-FW-DAG: @_OBJC_METACLASS_J = dso_local dllexport global +// CHECK-FW-DAG: @_OBJC_CLASS_J = dso_local dllexport global @implementation J { id _ivar; @@ -32,11 +32,11 @@ __declspec(dllexport) @interface K : J @end -// CHECK-IR-DAG: @"OBJC_METACLASS_$_K" = global %struct._class_t -// CHECK-IR-DAG: @"OBJC_CLASS_$_K" = global %struct._class_t +// CHECK-IR-DAG: @"OBJC_METACLASS_$_K" = dso_local global %struct._class_t +// CHECK-IR-DAG: @"OBJC_CLASS_$_K" = dso_local global %struct._class_t -// CHECK-FW-DAG: @_OBJC_METACLASS_K = global -// CHECK-FW-DAG: @_OBJC_CLASS_K = global +// CHECK-FW-DAG: @_OBJC_METACLASS_K = dso_local global +// CHECK-FW-DAG: @_OBJC_CLASS_K = dso_local global @implementation K { id _ivar; @@ -49,11 +49,11 @@ __declspec(dllexport) @interface L : K @end -// CHECK-IR-DAG: @"OBJC_METACLASS_$_L" = dllexport global %struct._class_t -// CHECK-IR-DAG: @"OBJC_CLASS_$_L" = dllexport global %struct._class_t +// CHECK-IR-DAG: @"OBJC_METACLASS_$_L" = dso_local dllexport global %struct._class_t +// CHECK-IR-DAG: @"OBJC_CLASS_$_L" = dso_local dllexport global %struct._class_t -// CHECK-FW-DAG: @_OBJC_METACLASS_L = dllexport global -// CHECK-FW-DAG: @_OBJC_CLASS_L = dllexport global +// CHECK-FW-DAG: @_OBJC_METACLASS_L = dso_local dllexport global +// CHECK-FW-DAG: @_OBJC_CLASS_L = dso_local dllexport global @implementation L { id _none; @@ -94,13 +94,13 @@ __attribute__((__objc_exception__)) @interface N : I @end -// CHECK-FW-DAG: @_OBJC_METACLASS_N = dllexport global -// CHECK-FW-DAG: @_OBJC_CLASS_N = dllexport global +// CHECK-FW-DAG: @_OBJC_METACLASS_N = dso_local dllexport global +// CHECK-FW-DAG: @_OBJC_CLASS_N = dso_local dllexport global @implementation N : I @end -// CHECK-IR-DAG: @"OBJC_EHTYPE_$_N" = dllexport global %struct._objc_typeinfo +// CHECK-IR-DAG: @"OBJC_EHTYPE_$_N" = dso_local dllexport global %struct._objc_typeinfo __declspec(dllimport) __attribute__((__objc_exception__)) @@ -113,7 +113,7 @@ __attribute__((__objc_exception__)) @interface P : I @end -// CHECK-IR-DAG: @"OBJC_EHTYPE_$_P" = external global %struct._objc_typeinfo +// CHECK-IR-DAG: @"OBJC_EHTYPE_$_P" = external dso_local global %struct._objc_typeinfo @interface Q : M @end diff --git a/test/CodeGenObjC/forward-declare-protocol-gnu.m b/test/CodeGenObjC/forward-declare-protocol-gnu.m new file mode 100644 index 000000000000..b57a4a48d4a0 --- /dev/null +++ b/test/CodeGenObjC/forward-declare-protocol-gnu.m @@ -0,0 +1,11 @@ +// RUN: %clang -S -emit-llvm %s -o - -x objective-c -fobjc-runtime=gnustep-1.5 | FileCheck %s + +// Regression test: check that we don't crash when referencing a forward-declared protocol. +@protocol P; + +Protocol *getProtocol(void) +{ + return @protocol(P); +} + +// CHECK: @.objc_protocol diff --git a/test/CodeGenObjC/forward-protocol-metadata-symbols.m b/test/CodeGenObjC/forward-protocol-metadata-symbols.m index 78c51e490137..16d33ec15d82 100644 --- a/test/CodeGenObjC/forward-protocol-metadata-symbols.m +++ b/test/CodeGenObjC/forward-protocol-metadata-symbols.m @@ -23,4 +23,17 @@ int main() { // CHECK: @"\01l_OBJC_LABEL_PROTOCOL_$_P0" = weak hidden global // CHECK: @"\01l_OBJC_PROTOCOL_REFERENCE_$_P0" = weak hidden global -// CHECK: llvm.compiler.used = appending global [10 x i8*] {{[^"]*}}OBJC_CLASS_NAME_{{[^"]*}}OBJC_METH_VAR_NAME_{{[^"]*}}OBJC_METH_VAR_TYPE_{{[^"]*}}"\01l_OBJC_$_CLASS_METHODS_A"{{[^"]*}}"\01l_OBJC_CLASS_PROTOCOLS_$_A"{{[^"]*}}OBJC_CLASS_NAME_.1{{[^"]*}}"\01l_OBJC_PROTOCOL_$_P0"{{[^"]*}}"\01l_OBJC_LABEL_PROTOCOL_$_P0"{{[^"]*}}"\01l_OBJC_PROTOCOL_REFERENCE_$_P0"{{[^"]*}}"OBJC_LABEL_CLASS_$"{{[^"]*}} section "llvm.metadata" +// CHECK: llvm.used = appending global [3 x i8*] +// CHECK-SAME: "\01l_OBJC_PROTOCOL_$_P0" +// CHECK-SAME: "\01l_OBJC_LABEL_PROTOCOL_$_P0" +// CHECK-SAME: "\01l_OBJC_PROTOCOL_REFERENCE_$_P0" + +// CHECK: llvm.compiler.used = appending global [7 x i8*] +// CHECK-SAME: OBJC_CLASS_NAME_ +// CHECK-SAME: OBJC_METH_VAR_NAME_ +// CHECK-SAME: OBJC_METH_VAR_TYPE_ +// CHECK-SAME: "\01l_OBJC_$_CLASS_METHODS_A" +// CHECK-SAME: "\01l_OBJC_CLASS_PROTOCOLS_$_A" +// CHECK-SAME: OBJC_CLASS_NAME_.1 +// CHECK-SAME: "OBJC_LABEL_CLASS_$" +// CHECK-SAME: section "llvm.metadata" diff --git a/test/CodeGenObjC/gnu-empty-protocol-v3.m b/test/CodeGenObjC/gnu-empty-protocol-v3.m new file mode 100644 index 000000000000..151427bf062e --- /dev/null +++ b/test/CodeGenObjC/gnu-empty-protocol-v3.m @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fobjc-runtime=gnustep-1.9 -emit-llvm -o - %s | FileCheck %s + +@protocol X; + +__attribute__((objc_root_class)) +@interface Z <X> +@end + +@implementation Z +@end + + +// CHECK: @.objc_protocol_list = internal global { i8*, i32, [0 x i8*] } zeroinitializer, align 4 +// CHECK: @.objc_method_list = internal global { i32, [0 x { i8*, i8* }] } zeroinitializer, align 4 +// CHECK: @.objc_protocol_name = private unnamed_addr constant [2 x i8] c"X\00", align 1 +// CHECK: @._OBJC_PROTOCOL_X = internal global { i8*, i8*, { i8*, i32, [0 x i8*] }*, i8*, i8*, i8*, i8*, i8*, i8* } { +// CHECK-SAME: i8* inttoptr (i32 3 to i8*), +// CHECK-SAME: i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.objc_protocol_name, i32 0, i32 0), +// CHECK-SAME: { i8*, i32, [0 x i8*] }* @.objc_protocol_list +// CHECK-SAME: { i32, [0 x { i8*, i8* }] }* @.objc_method_list +// CHECK-SAME: { i32, [0 x { i8*, i8* }] }* @.objc_method_list +// CHECK-SAME: { i32, [0 x { i8*, i8* }] }* @.objc_method_list +// CHECK-SAME: { i32, [0 x { i8*, i8* }] }* @.objc_method_list +// CHECK-SAME: i8* null +// CHECK-SAME: i8* null +// CHECK-SAME: }, align 4 diff --git a/test/CodeGenObjC/gnu-init.m b/test/CodeGenObjC/gnu-init.m new file mode 100644 index 000000000000..beb06bbe0df4 --- /dev/null +++ b/test/CodeGenObjC/gnu-init.m @@ -0,0 +1,69 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-freebsd -S -emit-llvm -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck %s -check-prefix=CHECK-NEW +// RUN: %clang_cc1 -triple x86_64-unknown-freebsd -S -emit-llvm -fobjc-runtime=gnustep-1.8 -o - %s | FileCheck %s -check-prefix=CHECK-OLD + +// Almost minimal Objective-C file, check that it emits calls to the correct +// runtime entry points. +@interface X @end +@implementation X @end + + +// Check that we emit a class ref +// CHECK-NEW: @._OBJC_REF_CLASS_X +// CHECK-NEW-SAME: section "__objc_class_refs" + +// Check that we get a class ref to the defined class. +// CHECK-NEW: @._OBJC_INIT_CLASS_X = global +// CHECK-NEW-SAME* @._OBJC_CLASS_X, section "__objc_classes" + +// Check that we emit the section start and end symbols as hidden globals. +// CHECK-NEW: @__start___objc_selectors = external hidden global i8* +// CHECK-NEW: @__stop___objc_selectors = external hidden global i8* +// CHECK-NEW: @__start___objc_classes = external hidden global i8* +// CHECK-NEW: @__stop___objc_classes = external hidden global i8* +// CHECK-NEW: @__start___objc_class_refs = external hidden global i8* +// CHECK-NEW: @__stop___objc_class_refs = external hidden global i8* +// CHECK-NEW: @__start___objc_cats = external hidden global i8* +// CHECK-NEW: @__stop___objc_cats = external hidden global i8* +// CHECK-NEW: @__start___objc_protocols = external hidden global i8* +// CHECK-NEW: @__stop___objc_protocols = external hidden global i8* +// CHECK-NEW: @__start___objc_protocol_refs = external hidden global i8* +// CHECK-NEW: @__stop___objc_protocol_refs = external hidden global i8* +// CHECK-NEW: @__start___objc_class_aliases = external hidden global i8* +// CHECK-NEW: @__stop___objc_class_aliases = external hidden global i8* +// CHECK-NEW: @__start___objc_constant_string = external hidden global i8* +// CHECK-NEW: @__stop___objc_constant_string = external hidden global i8* + +// Check that we emit the init structure correctly, including in a comdat. +// CHECK-NEW: @.objc_init = linkonce_odr hidden global { i64, i8**, i8**, i8**, i8**, i8**, i8**, i8**, i8**, i8**, i8**, i8**, i8**, i8**, i8**, i8**, i8** } { i64 0, i8** @__start___objc_selectors, i8** @__stop___objc_selectors, i8** @__start___objc_classes, i8** @__stop___objc_classes, i8** @__start___objc_class_refs, i8** @__stop___objc_class_refs, i8** @__start___objc_cats, i8** @__stop___objc_cats, i8** @__start___objc_protocols, i8** @__stop___objc_protocols, i8** @__start___objc_protocol_refs, i8** @__stop___objc_protocol_refs, i8** @__start___objc_class_aliases, i8** @__stop___objc_class_aliases, i8** @__start___objc_constant_string, i8** @__stop___objc_constant_string }, comdat, align 8 + +// Check that the load function is manually inserted into .ctors. +// CHECK-NEW: @.objc_ctor = linkonce hidden constant void ()* @.objcv2_load_function, section ".ctors", comdat + + +// Make sure that we provide null versions of everything so the __start / +// __stop symbols work. +// CHECK-NEW: @.objc_null_selector = linkonce_odr hidden global { i8*, i8* } zeroinitializer, section "__objc_selectors", comdat, align 8 +// CHECK-NEW: @.objc_null_category = linkonce_odr hidden global { i8*, i8*, i8*, i8*, i8*, i8*, i8* } zeroinitializer, section "__objc_cats", comdat, align 8 +// CHECK-NEW: @.objc_null_protocol = linkonce_odr hidden global { i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8* } zeroinitializer, section "__objc_protocols", comdat, align 8 +// CHECK-NEW: @.objc_null_protocol_ref = linkonce_odr hidden global { i8* } zeroinitializer, section "__objc_protocol_refs", comdat, align 8 +// CHECK-NEW: @.objc_null_class_alias = linkonce_odr hidden global { i8*, i8* } zeroinitializer, section "__objc_class_aliases", comdat, align 8 +// CHECK-NEW: @.objc_null_constant_string = linkonce_odr hidden global { i8*, i32, i32, i32, i32, i8* } zeroinitializer, section "__objc_constant_string", comdat, align 8 +// Make sure that the null symbols are not going to be removed, even by linking. +// CHECK-NEW: @llvm.used = appending global [7 x i8*] [i8* bitcast ({ { i8*, i8*, i8*, i64, i64, i64, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i64, i8* }*, i8*, i8*, i64, i64, i64, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i64, i8* }** @._OBJC_INIT_CLASS_X to i8*), i8* bitcast ({ i8*, i8* }* @.objc_null_selector to i8*), i8* bitcast ({ i8*, i8*, i8*, i8*, i8*, i8*, i8* }* @.objc_null_category to i8*), i8* bitcast ({ i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8* }* @.objc_null_protocol to i8*), i8* bitcast ({ i8* }* @.objc_null_protocol_ref to i8*), i8* bitcast ({ i8*, i8* }* @.objc_null_class_alias to i8*), i8* bitcast ({ i8*, i32, i32, i32, i32, i8* }* @.objc_null_constant_string to i8*)], section "llvm.metadata" +// Make sure that the load function and the reference to it are marked as used. +// CHECK-NEW: @llvm.compiler.used = appending global [2 x i8*] [i8* bitcast (void ()* @.objcv2_load_function to i8*), i8* bitcast (void ()** @.objc_ctor to i8*)], section "llvm.metadata" + +// Check that we emit the load function in a comdat and that it does the right thing. +// CHECK-NEW: define linkonce_odr hidden void @.objcv2_load_function() comdat { +// CHECK-NEW-NEXT: entry: +// CHECK-NEW-NEXT: call void @__objc_load( +// CHECK-NEW-SAME: @.objc_init +// CHECK-NEW-NEXT: ret void + +// CHECK-OLD: @4 = internal global { i64, i64, i8*, { i64, { i8*, i8* }*, i16, i16, [4 x i8*] }* } { i64 9, i64 32, i8* getelementptr inbounds ([{{[0-9]+}} x i8], [{{[0-9]+}} x i8]* @.objc_source_file_name, i64 0, i64 0), { i64, { i8*, i8* }*, i16, i16, [4 x i8*] }* @3 }, align 8 +// CHECK-OLD: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @.objc_load_function, i8* null }] + +// CHECK-OLD: define internal void @.objc_load_function() { +// CHECK-OLD-NEXT: entry: +// CHECK-OLD-NEXT: call void ({ i64, i64, i8*, { i64, { i8*, i8* }*, i16, i16, [4 x i8*] }* }*, ...) @__objc_exec_class({ i64, i64, i8*, { i64, { i8*, i8* }*, i16, i16, [4 x i8*] }* }* @4) + diff --git a/test/CodeGenObjC/gnustep2-category.m b/test/CodeGenObjC/gnustep2-category.m new file mode 100644 index 000000000000..e0dd7e3f5474 --- /dev/null +++ b/test/CodeGenObjC/gnustep2-category.m @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-freebsd -S -emit-llvm -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck %s + + +// Check that we have a method list that refers to the correct thing method: +// CHECK: internal global { i8*, i32, i64, [1 x { i8* (i8*, i8*, ...)*, i8*, i8* }] } { i8* null, i32 1, i64 24, +// CHECK-SAME: @_i_X_Cat_x +// CHECK-SAME: @".objc_selector_x_i16\010:8" + +// Check that we emit the correct encoding for the property (somewhere) +// CHECK: c"Ti,R\00" + +// Check that we emit a single-element property list of the correct form. +// CHECK: internal global { i32, i32, i8*, [1 x { i8*, i8*, i8*, i8*, i8* }] } + +// CHECK: @.objc_category_XCat = internal global { i8*, i8*, i8*, i8*, i8*, i8*, i8* } +// CHECK-SAME: section "__objc_cats", align 8 + +@interface X @end + +@interface X (Cat) +@property (readonly) int x; +@end + +@implementation X (Cat) +- (int)x { return 12; } +@end diff --git a/test/CodeGenObjC/gnustep2-class.m b/test/CodeGenObjC/gnustep2-class.m new file mode 100644 index 000000000000..0103a6fceee3 --- /dev/null +++ b/test/CodeGenObjC/gnustep2-class.m @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-freebsd -S -emit-llvm -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck %s + +@interface Super @end + +@interface X : Super +{ + int ivar1; + id ivar2; +} +@property (readonly) int x; +@property id y; +@end + +@implementation X +@synthesize y; + +- (int)x { return 12; } ++ (int)clsMeth { return 42; } +- (id)meth { return ivar2; } +@end + +// Check that we get an ivar offset variable for the synthesised ivar. +// CHECK: @"__objc_ivar_offset_X.y.\01" = hidden global i32 16 +// +// Check that we get a sensible metaclass method list. +// CHECK: internal global { i8*, i32, i64, [1 x { i8* (i8*, i8*, ...)*, i8*, i8* }] } +// CHECK-SAME: @_c_X__clsMeth + +// Check that we get a metaclass and that it is not an exposed symbol: +// CHECK: @._OBJC_METACLASS_X = internal global + +// Check that we get a reference to the superclass symbol: +// CHECK: @._OBJC_CLASS_Super = external global i8* + +// Check that we get an ivar list with all three ivars, in the correct order +// CHECK: private global { i32, i64, [3 x { i8*, i8*, i32*, i32, i32 }] } +// CHECK-SAME: @__objc_ivar_offset_X.ivar1.i +// CHECK-SAME: @"__objc_ivar_offset_X.ivar2.\01" +// CHECK-SAME: @"__objc_ivar_offset_X.y.\01" + +// Check that we get some plausible property metadata. +// CHECK: private unnamed_addr constant [5 x i8] c"Ti,R\00", align 1 +// CHECK: private unnamed_addr constant [6 x i8] c"T@,Vy\00", align 1 +// CHECK: = internal global { i32, i32, i8*, [2 x { i8*, i8*, i8*, i8*, i8* }] } { i32 2, i32 40, i8* null, + +// Check that we get a class structure. +// CHECK: @._OBJC_CLASS_X = global { { i8*, i8*, i8*, i64, i64, i64, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i64, i8* }*, i8*, i8*, i64, i64, i64, { i32, i64, [3 x { i8*, i8*, i32*, i32, i32 }] }*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i64, { i32, i32, i8*, [2 x { i8*, i8*, i8*, i8*, i8* }] }* } +// CHECK-SAME: @._OBJC_METACLASS_X +// CHECK-SAME: @._OBJC_CLASS_Super + +// And check that we get a pointer to it in the right place +// CHECK: @._OBJC_REF_CLASS_X = global +// CHECK-SAME: @._OBJC_CLASS_X +// CHECK-SAME: section "__objc_class_refs" + diff --git a/test/CodeGenObjC/gnustep2-ivar-offset.m b/test/CodeGenObjC/gnustep2-ivar-offset.m new file mode 100644 index 000000000000..432fa567de30 --- /dev/null +++ b/test/CodeGenObjC/gnustep2-ivar-offset.m @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-freebsd -S -emit-llvm -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck %s + + +@class NSString; + +@interface ANObject { +@public +// Public ivars have default visibility +// CHECK: @"__objc_ivar_offset_ANObject.isa.\01" = global i32 0 + struct objc_object *isa; +@private +// Private and package ivars should have hidden linkage. +// Check that in the GNUstep v2 ABI, instance variable offset names include +// type encodings (with @ mangled to \01 to avoid collisions with ELF symbol +// versions). +// CHECK: private unnamed_addr constant [12 x i8] c"@\22NSString\22\00" +// CHECK: @"__objc_ivar_offset_ANObject._stringIvar.\01" = hidden global i32 8 + NSString *_stringIvar; +@package +// CHECK: @__objc_ivar_offset_ANObject._intIvar.i = hidden global i32 16 + int _intIvar; +} +@end +@implementation ANObject @end + +// Check that the ivar metadata contains 3 entries of the correct form and correctly sets the size. +// CHECK: @.objc_ivar_list = private global { i32, i64, [3 x { i8*, i8*, i32*, i32, i32 }] } { i32 3, i64 32, +// Check that we're emitting the extended type encoding for the string ivar. diff --git a/test/CodeGenObjC/gnustep2-proto.m b/test/CodeGenObjC/gnustep2-proto.m new file mode 100644 index 000000000000..536714f03a99 --- /dev/null +++ b/test/CodeGenObjC/gnustep2-proto.m @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-freebsd -S -emit-llvm -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck %s + +@protocol X +@optional +- (id)x; +@required ++ (void*)y; +@property int reqProp; +@optional +@property int optProp; +@end + +// Check that we get some plausible-looking method lists. +// CHECK: internal global { i32, i32, [2 x { i8*, i8* }] } { i32 2, i32 16, +// CHECK-SAME: @".objc_selector_reqProp_i16\010:8" +// CHECK-SAME: @".objc_selector_setReqProp:_v20\010:8i16" +// CHECK: internal global { i32, i32, [3 x { i8*, i8* }] } { i32 3, i32 16, +// CHECK-SAME: @".objc_selector_x_\0116\010:8" +// CHECK-SAME: @".objc_selector_optProp_i16\010:8" +// CHECK-SAME: @".objc_selector_setOptProp:_v20\010:8i16" + + +// Check that we're emitting the protocol and a correctly initialised +// indirection variable. +// CHECK: @._OBJC_PROTOCOL_X = global +// CHECK-SAME: , section "__objc_protocols", comdat, align 8 +// CHECK: @._OBJC_REF_PROTOCOL_X = global +// CHECK-SAME: @._OBJC_PROTOCOL_X +// CHECK-SAME: , section "__objc_protocol_refs", align 8 + + +// Check that we load from the indirection variable on protocol references. +// CHECK: define i8* @x() +// CHECK: = load +// CHECK-SAME: @._OBJC_REF_PROTOCOL_X, align 8 +void *x() +{ + return @protocol(X); +} diff --git a/test/CodeGenObjC/ivar-type-encoding.m b/test/CodeGenObjC/ivar-type-encoding.m index 2fd962cf07bb..a7ad55c6715c 100644 --- a/test/CodeGenObjC/ivar-type-encoding.m +++ b/test/CodeGenObjC/ivar-type-encoding.m @@ -29,10 +29,10 @@ int main() { return 0; } -// CHECK: @0 = private unnamed_addr constant [12 x i8] c"_stringIvar\00" -// CHECK: @1 = private unnamed_addr constant [12 x i8] c"@\22NSString\22\00" -// CHECK: @2 = private unnamed_addr constant [9 x i8] c"_intIvar\00" -// CHECK: @3 = private unnamed_addr constant [2 x i8] c"i\00" +// CHECK: = private unnamed_addr constant [12 x i8] c"_stringIvar\00" +// CHECK: = private unnamed_addr constant [12 x i8] c"@\22NSString\22\00" +// CHECK: = private unnamed_addr constant [9 x i8] c"_intIvar\00" +// CHECK: = private unnamed_addr constant [2 x i8] c"i\00" @interface Class1 { int : 3; diff --git a/test/CodeGenObjC/messages-2.m b/test/CodeGenObjC/messages-2.m index be66f71f66f7..38c5d5016a92 100644 --- a/test/CodeGenObjC/messages-2.m +++ b/test/CodeGenObjC/messages-2.m @@ -157,7 +157,7 @@ void test0(A *x) { // CHECK: call {{.*}} @objc_msgSend_stret to // CHECK-NEXT: br label // CHECK: [[T0:%.*]] = bitcast [[POINT_T]]* [[POINT]] to i8* - // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 48, i32 4, i1 false) + // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 [[T0]], i8 0, i64 48, i1 false) // CHECK-NEXT: br label // CHECK-NF: [[X:%.*]] = alloca [[A]]* @@ -169,7 +169,7 @@ void test0(A *x) { // CHECK-NF: call {{.*}} @objc_msgSend_stret to // CHECK-NF-NEXT: br label // CHECK-NF: [[T0:%.*]] = bitcast [[POINT_T]]* [[POINT]] to i8* - // CHECK-NF-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 48, i32 4, i1 false) + // CHECK-NF-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 [[T0]], i8 0, i64 48, i1 false) // CHECK-NF-NEXT: br label MyPoint point = [x returnAPoint]; } diff --git a/test/CodeGenObjC/noescape.m b/test/CodeGenObjC/noescape.m index 49bc0e4a7d33..56e1e51e5d3f 100644 --- a/test/CodeGenObjC/noescape.m +++ b/test/CodeGenObjC/noescape.m @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -o - %s | FileCheck -check-prefix CHECK -check-prefix CHECK-NOARC %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -fobjc-arc -o - %s | FileCheck -check-prefix CHECK -check-prefix CHECK-ARC %s typedef void (^BlockTy)(void); @@ -12,6 +13,12 @@ void noescapeFunc1(__attribute__((noescape)) int *); void noescapeFunc2(__attribute__((noescape)) id); void noescapeFunc3(__attribute__((noescape)) union U); +// Block descriptors of non-escaping blocks don't need pointers to copy/dispose +// helper functions. + +// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 } +// CHECK: @[[BLOCK_DESCIPTOR_TMP_2:.*]] = internal constant { i64, i64, i8*, i64 } { i64 0, i64 40, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8 + // CHECK-LABEL: define void @test0( // CHECK: call void @noescapeFunc0({{.*}}, {{.*}} nocapture {{.*}}) // CHECK: declare void @noescapeFunc0(i8*, {{.*}} nocapture) @@ -69,3 +76,41 @@ void test5(BlockTy2 b, int *p) { ^(int *__attribute__((noescape)) p0){}(p); b(p); } + +// If the block is non-escaping, set the BLOCK_IS_NOESCAPE and BLOCK_IS_GLOBAL +// bits of field 'flags' and set the 'isa' field to 'NSConcreteGlobalBlock'. + +// CHECK: define void @test6(i8* %{{.*}}, i8* %[[B:.*]]) +// CHECK: %{{.*}} = alloca i8*, align 8 +// CHECK: %[[B_ADDR:.*]] = alloca i8*, align 8 +// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, align 8 +// CHECK-NOARC: store i8* %[[B]], i8** %[[B_ADDR]], align 8 +// CHECK-ARC: store i8* null, i8** %[[B_ADDR]], align 8 +// CHECK-ARC: call void @objc_storeStrong(i8** %[[B_ADDR]], i8* %[[B]]) +// CHECK-ARC: %[[V0:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 5 +// CHECK: %[[BLOCK_ISA:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 0 +// CHECK: store i8* bitcast (i8** @_NSConcreteGlobalBlock to i8*), i8** %[[BLOCK_ISA]], align 8 +// CHECK: %[[BLOCK_FLAGS:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 1 +// CHECK: store i32 -796917760, i32* %[[BLOCK_FLAGS]], align 8 +// CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 4 +// CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i64 }* @[[BLOCK_DESCIPTOR_TMP_2]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8 +// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 5 +// CHECK-NOARC: %[[V1:.*]] = load i8*, i8** %[[B_ADDR]], align 8 +// CHECK-NOARC: store i8* %[[V1]], i8** %[[BLOCK_CAPTURED]], align 8 +// CHECK-ARC: %[[V2:.*]] = load i8*, i8** %[[B_ADDR]], align 8 +// CHECK-ARC: %[[V3:.*]] = call i8* @objc_retain(i8* %[[V2]]) #3 +// CHECK-ARC: store i8* %[[V3]], i8** %[[BLOCK_CAPTURED]], align 8 +// CHECK: call void @noescapeFunc0( +// CHECK-ARC: call void @objc_storeStrong(i8** %[[V0]], i8* null) +// CHECK-ARC: call void @objc_storeStrong(i8** %[[B_ADDR]], i8* null) + +// Non-escaping blocks don't need copy/dispose helper functions. + +// CHECK-NOT: define internal void @__copy_helper_block_ +// CHECK-NOT: define internal void @__destroy_helper_block_ + +void func(id); + +void test6(id a, id b) { + noescapeFunc0(a, ^{ func(b); }); +} diff --git a/test/CodeGenObjC/nontrivial-c-struct-exception.m b/test/CodeGenObjC/nontrivial-c-struct-exception.m new file mode 100644 index 000000000000..7db53bb74249 --- /dev/null +++ b/test/CodeGenObjC/nontrivial-c-struct-exception.m @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks -fobjc-runtime=ios-11.0 -fobjc-exceptions -fexceptions -emit-llvm -o - %s | FileCheck %s + +// CHECK: %[[STRUCT_STRONG:.*]] = type { i32, i8* } +// CHECK: %[[STRUCT_WEAK:.*]] = type { i32, i8* } + +typedef struct { + int i; + id f1; +} Strong; + +typedef struct { + int i; + __weak id f1; +} Weak; + +// CHECK: define void @testStrongException() +// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONG]], align 8 +// CHECK: %[[AGG_TMP1:.*]] = alloca %[[STRUCT_STRONG]], align 8 +// CHECK: %[[CALL:.*]] = call [2 x i64] @genStrong() +// CHECK: %[[V0:.*]] = bitcast %[[STRUCT_STRONG]]* %[[AGG_TMP]] to [2 x i64]* +// CHECK: store [2 x i64] %[[CALL]], [2 x i64]* %[[V0]], align 8 +// CHECK: invoke [2 x i64] @genStrong() + +// CHECK: call void @calleeStrong([2 x i64] %{{.*}}, [2 x i64] %{{.*}}) +// CHECK-NEXT: ret void + +// CHECK: landingpad { i8*, i32 } +// CHECK: %[[V9:.*]] = bitcast %[[STRUCT_STRONG]]* %[[AGG_TMP]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V9]]) +// CHECK: br label + +// CHECK: resume + +Strong genStrong(void); +void calleeStrong(Strong, Strong); + +void testStrongException(void) { + calleeStrong(genStrong(), genStrong()); +} + +// CHECK: define void @testWeakException() +// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_WEAK]], align 8 +// CHECK: %[[AGG_TMP1:.*]] = alloca %[[STRUCT_WEAK]], align 8 +// CHECK: call void @genWeak(%[[STRUCT_WEAK]]* sret %[[AGG_TMP]]) +// CHECK: invoke void @genWeak(%[[STRUCT_WEAK]]* sret %[[AGG_TMP1]]) + +// CHECK: call void @calleeWeak(%[[STRUCT_WEAK]]* %[[AGG_TMP]], %[[STRUCT_WEAK]]* %[[AGG_TMP1]]) +// CHECK: ret void + +// CHECK: landingpad { i8*, i32 } +// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_WEAK]]* %[[AGG_TMP]] to i8** +// CHECK: call void @__destructor_8_w8(i8** %[[V3]]) +// CHECK: br label + +// CHECK: resume + +Weak genWeak(void); +void calleeWeak(Weak, Weak); + +void testWeakException(void) { + calleeWeak(genWeak(), genWeak()); +} diff --git a/test/CodeGenObjC/nontrivial-c-struct-func-name-collision.m b/test/CodeGenObjC/nontrivial-c-struct-func-name-collision.m new file mode 100644 index 000000000000..bf512ec88b7f --- /dev/null +++ b/test/CodeGenObjC/nontrivial-c-struct-func-name-collision.m @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks -fobjc-runtime=ios-11.0 -emit-llvm -verify -o - %s + +typedef struct { // expected-error {{special function __default_constructor_8_s8 for non-trivial C struct has incorrect type}} + int i; + id f1; +} StrongSmall; + +int __default_constructor_8_s8(double a) { + return 0; +} + +void testIncorrectFunctionType(void) { + StrongSmall x; +} diff --git a/test/CodeGenObjC/objc-container-subscripting-1.m b/test/CodeGenObjC/objc-container-subscripting-1.m index f9322fa63c1e..18f2f8cf6ffd 100644 --- a/test/CodeGenObjC/objc-container-subscripting-1.m +++ b/test/CodeGenObjC/objc-container-subscripting-1.m @@ -25,8 +25,8 @@ int main() { // CHECK-NEXT: store i8* [[CALL]], i8** [[OLDOBJ:%.*]], align 8 val = (array[10] = oldObject); -// CHECK: [[THREE:%.*]] = load {{%.*}} [[array:%.*]], align 8 -// CHECK-NEXT: [[FOUR:%.*]] = load i8*, i8** [[oldObject:%.*]], align 8 +// CHECK: [[FOUR:%.*]] = load i8*, i8** [[oldObject:%.*]], align 8 +// CHECK-NEXT: [[THREE:%.*]] = load {{%.*}} [[array:%.*]], align 8 // CHECK-NEXT: [[FIVE:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_.2 // CHECK-NEXT: [[SIX:%.*]] = bitcast {{%.*}} [[THREE]] to i8* // CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*, i32)*)(i8* [[SIX]], i8* [[FIVE]], i8* [[FOUR]], i32 10) @@ -45,9 +45,9 @@ int main() { val = (dictionary[key] = newObject); -// CHECK: [[TWELVE:%.*]] = load {{%.*}} [[DICTIONARY]], align 8 +// CHECK: [[FOURTEEN:%.*]] = load i8*, i8** [[NEWOBJECT:%.*]], align 8 +// CHECK-NEXT: [[TWELVE:%.*]] = load {{%.*}} [[DICTIONARY]], align 8 // CHECK-NEXT: [[THIRTEEN:%.*]] = load i8*, i8** [[KEY]], align 8 -// CHECK-NEXT: [[FOURTEEN:%.*]] = load i8*, i8** [[NEWOBJECT:%.*]], align 8 // CHECK-NEXT: [[SIXTEEN:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_.6 // CHECK-NEXT: [[SEVENTEEN:%.*]] = bitcast {{%.*}} [[TWELVE]] to i8* // CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*, i8*)*)(i8* [[SEVENTEEN]], i8* [[SIXTEEN]], i8* [[FOURTEEN]], i8* [[THIRTEEN]]) diff --git a/test/CodeGenObjC/objc-non-trivial-struct-nrvo.m b/test/CodeGenObjC/objc-non-trivial-struct-nrvo.m new file mode 100644 index 000000000000..798aba248941 --- /dev/null +++ b/test/CodeGenObjC/objc-non-trivial-struct-nrvo.m @@ -0,0 +1,134 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck %s + +// CHECK: %[[STRUCT_TRIVIAL:.*]] = type { i32 } +// CHECK: %[[STRUCT_TRIVIALBIG:.*]] = type { [64 x i32] } +// CHECK: %[[STRUCT_STRONG:.*]] = type { i8* } +// CHECK: %[[STRUCT_WEAK:.*]] = type { i8* } + +typedef struct { + int x; +} Trivial; + +typedef struct { + int x[64]; +} TrivialBig; + +typedef struct { + id x; +} Strong; + +typedef struct { + __weak id x; +} Weak; + +// CHECK: define i32 @testTrivial() +// CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_TRIVIAL]], align 4 +// CHECK-NEXT: call void @func0(%[[STRUCT_TRIVIAL]]* %[[RETVAL]]) +// CHECK-NOT: memcpy +// CHECK: ret i32 % + +void func0(Trivial *); + +Trivial testTrivial(void) { + Trivial a; + func0(&a); + return a; +} + +void func1(TrivialBig *); + +// CHECK: define void @testTrivialBig(%[[STRUCT_TRIVIALBIG]]* noalias sret %[[AGG_RESULT:.*]]) +// CHECK-NOT: alloca +// CHECK: call void @func1(%[[STRUCT_TRIVIALBIG]]* %[[AGG_RESULT]]) +// CHECK-NEXT: ret void + +TrivialBig testTrivialBig(void) { + TrivialBig a; + func1(&a); + return a; +} + +// CHECK: define i8* @testStrong() +// CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_STRONG]], align 8 +// CHECK: %[[NRVO:.*]] = alloca i1, align 1 +// CHECK: %[[V0:.*]] = bitcast %[[STRUCT_STRONG]]* %[[RETVAL]] to i8** +// CHECK: call void @__default_constructor_8_s0(i8** %[[V0]]) +// CHECK: store i1 true, i1* %[[NRVO]], align 1 +// CHECK: %[[NRVO_VAL:.*]] = load i1, i1* %[[NRVO]], align 1 +// CHECK: br i1 %[[NRVO_VAL]], + +// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONG]]* %[[RETVAL]] to i8** +// CHECK: call void @__destructor_8_s0(i8** %[[V1]]) +// CHECK: br + +// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[RETVAL]], i32 0, i32 0 +// CHECK: %[[V2:.*]] = load i8*, i8** %[[COERCE_DIVE]], align 8 +// CHECK: ret i8* %[[V2]] + +Strong testStrong(void) { + Strong a; + return a; +} + +// CHECK: define void @testWeak(%[[STRUCT_WEAK]]* noalias sret %[[AGG_RESULT:.*]]) +// CHECK: %[[NRVO:.*]] = alloca i1, align 1 +// CHECK: %[[V0:.*]] = bitcast %[[STRUCT_WEAK]]* %[[AGG_RESULT]] to i8** +// CHECK: call void @__default_constructor_8_w0(i8** %[[V0]]) +// CHECK: store i1 true, i1* %[[NRVO]], align 1 +// CHECK: %[[NRVO_VAL:.*]] = load i1, i1* %[[NRVO]], align 1 +// CHECK: br i1 %[[NRVO_VAL]], + +// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_WEAK]]* %[[AGG_RESULT]] to i8** +// CHECK: call void @__destructor_8_w0(i8** %[[V1]]) +// CHECK: br + +// CHECK-NOT: call +// CHECK: ret void + +Weak testWeak(void) { + Weak a; + return a; +} + +// CHECK: define void @testWeak2( +// CHECK: call void @__default_constructor_8_w0( +// CHECK: call void @__default_constructor_8_w0( +// CHECK: call void @__copy_constructor_8_8_w0( +// CHECK: call void @__copy_constructor_8_8_w0( +// CHECK: call void @__destructor_8_w0( +// CHECK: call void @__destructor_8_w0( + +Weak testWeak2(int c) { + Weak a, b; + if (c) + return a; + else + return b; +} + +// CHECK: define internal void @"\01-[C1 foo1]"(%[[STRUCT_WEAK]]* noalias sret %[[AGG_RESULT:.*]], %{{.*}}* %{{.*}}, i8* %{{.*}}) +// CHECK: %[[NRVO:.*]] = alloca i1, align 1 +// CHECK: %[[V0:.*]] = bitcast %[[STRUCT_WEAK]]* %[[AGG_RESULT]] to i8** +// CHECK: call void @__default_constructor_8_w0(i8** %[[V0]]) +// CHECK: store i1 true, i1* %[[NRVO]], align 1 +// CHECK: %[[NRVO_VAL:.*]] = load i1, i1* %[[NRVO]], align 1 +// CHECK: br i1 %[[NRVO_VAL]], + +// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_WEAK]]* %[[AGG_RESULT]] to i8** +// CHECK: call void @__destructor_8_w0(i8** %[[V1]]) +// CHECK: br + +// CHECK-NOT: call +// CHECK: ret void + +__attribute__((objc_root_class)) +@interface C1 +- (Weak)foo1; +@end + +@implementation C1 +- (Weak)foo1 { + Weak a; + return a; +} +@end diff --git a/test/CodeGenObjC/objc-runtime-name.m b/test/CodeGenObjC/objc-runtime-name.m new file mode 100644 index 000000000000..228525fc55c0 --- /dev/null +++ b/test/CodeGenObjC/objc-runtime-name.m @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -triple i386-apple-macosx10.13.0 -fobjc-runtime=macosx-fragile-10.13.0 -fobjc-subscripting-legacy-runtime -emit-llvm -o - %s | FileCheck %s + +// Check that the runtime name is emitted and used instead of the class +// identifier. + +// CHECK: module asm {{.*}}objc_class_name_XYZ=0 +// CHECK: module asm {{.*}}globl .objc_class_name_XYZ +// CHECK: module asm {{.*}}lazy_reference .objc_class_name_XYZ + +// CHECK: @[[OBJC_CLASS_NAME:.*]] = private unnamed_addr constant [4 x i8] c"XYZ{{.*}}, section "__TEXT,__cstring,cstring_literals", +// CHECK: = private global {{.*}} bitcast ([4 x i8]* @[[OBJC_CLASS_NAME]] to {{.*}}), section "__OBJC,__cls_refs,literal_pointers,no_dead_strip" + +__attribute__((objc_root_class,objc_runtime_name("XYZ"))) +@interface A ++(void)m1; +@end + +@implementation A ++(void)m1 {} +@end + +void test(void) { + [A m1]; +} diff --git a/test/CodeGenObjC/personality.m b/test/CodeGenObjC/personality.m new file mode 100644 index 000000000000..0db0803c455d --- /dev/null +++ b/test/CodeGenObjC/personality.m @@ -0,0 +1,76 @@ +// RUN: %clang_cc1 -triple i686-unknown-linux-gnu -fexceptions -fobjc-exceptions -fobjc-runtime=macosx-fragile -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-MACOSX-FRAGILE +// RUN: %clang_cc1 -triple i686-unknown-linux-gnu -fexceptions -fobjc-exceptions -fobjc-runtime=ios -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-NS +// RUN: %clang_cc1 -triple i686-unknown-linux-gnu -fexceptions -fobjc-exceptions -fobjc-runtime=macosx -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-NS +// RUN: %clang_cc1 -triple i686-unknown-linux-gnu -fexceptions -fobjc-exceptions -fobjc-runtime=watchos -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-NS +// RUN: %clang_cc1 -triple i686-unknown-linux-gnu -fexceptions -fobjc-exceptions -fobjc-runtime=gnustep-1.7 -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-GNUSTEP-1_7 +// RUN: %clang_cc1 -triple i686-unknown-linux-gnu -fexceptions -fobjc-exceptions -fobjc-runtime=gnustep -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-GNUSTEP +// RUN: %clang_cc1 -triple i686-unknown-linux-gnu -fexceptions -fobjc-exceptions -fobjc-runtime=gcc -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-GCC +// RUN: %clang_cc1 -triple i686-unknown-linux-gnu -fexceptions -fseh-exceptions -fobjc-exceptions -fobjc-runtime=gcc -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-GCC-SEH +// RUN: %clang_cc1 -triple i686-unknown-linux-gnu -fexceptions -fsjlj-exceptions -fobjc-exceptions -fobjc-runtime=gcc -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-GCC-SJLJ +// RUN: %clang_cc1 -triple i686-unknown-linux-gnu -fexceptions -fobjc-exceptions -fobjc-runtime=objfw -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-OBJFW +// RUN: %clang_cc1 -triple i686-unknown-linux-gnu -fexceptions -fseh-exceptions -fobjc-exceptions -fobjc-runtime=objfw -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-OBJFW-SEH +// RUN: %clang_cc1 -triple i686-unknown-linux-gnu -fexceptions -fsjlj-exceptions -fobjc-exceptions -fobjc-runtime=objfw -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-OBJFW-SJLJ + +// RUN: %clang_cc1 -triple i686-unknown-windows-msvc -fexceptions -fobjc-exceptions -fobjc-runtime=macosx-fragile -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-WIN-MSVC +// RUN: %clang_cc1 -triple i686-unknown-windows-msvc -fexceptions -fobjc-exceptions -fobjc-runtime=ios -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-WIN-MSVC +// RUN: %clang_cc1 -triple i686-unknown-windows-msvc -fexceptions -fobjc-exceptions -fobjc-runtime=macosx -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-WIN-MSVC +// RUN: %clang_cc1 -triple i686-unknown-windows-msvc -fexceptions -fobjc-exceptions -fobjc-runtime=watchos -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-WIN-MSVC +// RUN: %clang_cc1 -triple i686-unknown-windows-msvc -fexceptions -fobjc-exceptions -fobjc-runtime=gnustep-1.7 -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-WIN-MSVC +// RUN: %clang_cc1 -triple i686-unknown-windows-msvc -fexceptions -fobjc-exceptions -fobjc-runtime=gnustep -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-WIN-MSVC +// RUN: %clang_cc1 -triple i686-unknown-windows-msvc -fexceptions -fobjc-exceptions -fobjc-runtime=gcc -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-WIN-MSVC +// RUN: %clang_cc1 -triple i686-unknown-windows-msvc -fexceptions -fobjc-exceptions -fobjc-runtime=objfw -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-WIN-MSVC + +// RUN: %clang_cc1 -triple i686-unknown-windows-gnu -fexceptions -fobjc-exceptions -fobjc-runtime=macosx-fragile -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-MACOSX-FRAGILE +// RUN: %clang_cc1 -triple i686-unknown-windows-gnu -fexceptions -fdwarf-exceptions -fobjc-exceptions -fobjc-runtime=macosx-fragile -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-MACOSX-FRAGILE-MINGW-DWARF +// RUN: %clang_cc1 -triple i686-unknown-windows-gnu -fexceptions -fseh-exceptions -fobjc-exceptions -fobjc-runtime=macosx-fragile -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-MACOSX-FRAGILE-MINGW-SEH +// RUN: %clang_cc1 -triple i686-unknown-windows-gnu -fexceptions -fsjlj-exceptions -fobjc-exceptions -fobjc-runtime=macosx-fragile -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-MACOSX-FRAGILE-MINGW-SJLJ +// RUN: %clang_cc1 -triple i686-unknown-windows-gnu -fexceptions -fobjc-exceptions -fobjc-runtime=ios -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-NS +// RUN: %clang_cc1 -triple i686-unknown-windows-gnu -fexceptions -fobjc-exceptions -fobjc-runtime=macosx -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-NS +// RUN: %clang_cc1 -triple i686-unknown-windows-gnu -fexceptions -fobjc-exceptions -fobjc-runtime=watchos -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-NS +// RUN: %clang_cc1 -triple i686-unknown-windows-gnu -fexceptions -fobjc-exceptions -fobjc-runtime=gnustep-1.7 -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-GNUSTEP-1_7 +// RUN: %clang_cc1 -triple i686-unknown-windows-gnu -fexceptions -fobjc-exceptions -fobjc-runtime=gnustep -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-GNUSTEP +// RUN: %clang_cc1 -triple i686-unknown-windows-gnu -fexceptions -fobjc-exceptions -fobjc-runtime=gcc -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-GCC +// RUN: %clang_cc1 -triple i686-unknown-windows-gnu -fexceptions -fseh-exceptions -fobjc-exceptions -fobjc-runtime=gcc -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-GCC-SEH +// RUN: %clang_cc1 -triple i686-unknown-windows-gnu -fexceptions -fsjlj-exceptions -fobjc-exceptions -fobjc-runtime=gcc -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-GCC-SJLJ +// RUN: %clang_cc1 -triple i686-unknown-windows-gnu -fexceptions -fobjc-exceptions -fobjc-runtime=objfw -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-OBJFW +// RUN: %clang_cc1 -triple i686-unknown-windows-gnu -fexceptions -fseh-exceptions -fobjc-exceptions -fobjc-runtime=objfw -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-OBJFW-SEH +// RUN: %clang_cc1 -triple i686-unknown-windows-gnu -fexceptions -fsjlj-exceptions -fobjc-exceptions -fobjc-runtime=objfw -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-OBJFW-SJLJ + +void g(void); + +// CHECK-MACOSX-FRAGILE: personality i8* bitcast (i32 (...)* @__gcc_personality_v0 to i8*) +// CHECK-NS: personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) +// CHECK-GNUSTEP-1_7: personality i8* bitcast (i32 (...)* @__gnustep_objc_personality_v0 to i8*) +// CHECK-GNUSTEP: personality i8* bitcast (i32 (...)* @__gnu_objc_personality_v0 to i8*) +// CHECK-GCC: personality i8* bitcast (i32 (...)* @__gnu_objc_personality_v0 to i8*) +// CHECK-GCC-SEH: personality i8* bitcast (i32 (...)* @__gnu_objc_personality_seh0 to i8*) +// CHECK-GCC-SJLJ: personality i8* bitcast (i32 (...)* @__gnu_objc_personality_sj0 to i8*) +// CHECK-OBJFW: personality i8* bitcast (i32 (...)* @__gnu_objc_personality_v0 to i8*) +// CHECK-OBJFW-SEH: personality i8* bitcast (i32 (...)* @__gnu_objc_personality_seh0 to i8*) +// CHECK-OBJFW-SJLJ: personality i8* bitcast (i32 (...)* @__gnu_objc_personality_sj0 to i8*) + +// CHECK-WIN-MSVC: personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) + +// CHECK-MACOSX-FRAGILE-MINGW-DWARF: personality i8* bitcast (i32 (...)* @__gcc_personality_v0 to i8*) +// CHECK-MACOSX-FRAGILE-MINGW-SEH: personality i8* bitcast (i32 (...)* @__gcc_personality_seh0 to i8*) +// CHECK-MACOSX-FRAGILE-MINGW-SJLJ: personality i8* bitcast (i32 (...)* @__gcc_personality_sj0 to i8*) + +void f(void) { + @try { + g(); + } @catch (...) { + } +} + +#if defined(__SEH_EXCEPTIONS__) +// CHECK-WIN-SEH-X86: personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) +// CHECK-WIN-SEH-X64: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) + +void h(void) { + __try { + i(); + } __finally { + } +} +#endif + diff --git a/test/CodeGenObjC/runtime-abi-match.m b/test/CodeGenObjC/runtime-abi-match.m index ef391724ece0..ac8eea6cd421 100644 --- a/test/CodeGenObjC/runtime-abi-match.m +++ b/test/CodeGenObjC/runtime-abi-match.m @@ -1,4 +1,4 @@ -// RUN: %clang -target armv7-windows -fobjc-runtime=ios -O1 -fexceptions -S -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple thumbv7--windows-itanium -fobjc-runtime=ios -O1 -fexceptions -fobjc-exceptions -emit-llvm %s -o - | FileCheck %s // REQUIRES: arm-registered-target void (*f)(id); diff --git a/test/CodeGenObjC/stret-1.m b/test/CodeGenObjC/stret-1.m index 2314d5a9ecf5..1122c28a468b 100644 --- a/test/CodeGenObjC/stret-1.m +++ b/test/CodeGenObjC/stret-1.m @@ -16,7 +16,7 @@ int main(int argc, const char **argv) s = [(id)(argc&~255) method]; // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret [[T0:%[^,]+]] // CHECK: [[T0P:%.*]] = bitcast %struct.stret* [[T0]] to i8* - // CHECK: call void @llvm.memset.p0i8.i64(i8* [[T0P]], i8 0, i64 400, i32 4, i1 false) + // CHECK: call void @llvm.memset.p0i8.i64(i8* align 4 [[T0P]], i8 0, i64 400, i1 false) s = [Test method]; // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret [[T1:%[^,]+]] diff --git a/test/CodeGenObjC/strong-in-c-struct.m b/test/CodeGenObjC/strong-in-c-struct.m new file mode 100644 index 000000000000..36e9049635f2 --- /dev/null +++ b/test/CodeGenObjC/strong-in-c-struct.m @@ -0,0 +1,563 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks -fobjc-runtime=ios-11.0 -emit-llvm -o - -DUSESTRUCT -I %S/Inputs %s | FileCheck %s + +// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks -fobjc-runtime=ios-11.0 -emit-pch -I %S/Inputs -o %t %s +// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks -fobjc-runtime=ios-11.0 -include-pch %t -emit-llvm -o - -DUSESTRUCT -I %S/Inputs %s | FileCheck %s + +#ifndef HEADER +#define HEADER +#include "strong_in_union.h" + +typedef void (^BlockTy)(void); + +typedef struct { + int a[4]; +} Trivial; + +typedef struct { + Trivial f0; + id f1; +} Strong; + +typedef struct { + int i; + id f1; +} StrongSmall; + +typedef struct { + Strong f0; + id f1; + double d; +} StrongOuter; + +typedef struct { + int f0; + volatile id f1; +} StrongVolatile; + +typedef struct { + BlockTy f0; +} StrongBlock; + +typedef struct { + int i; + id f0[2][2]; +} IDArray; + +typedef struct { + double d; + Strong f0[2][2]; +} StructArray; + +typedef struct { + id f0; + int i : 9; +} Bitfield0; + +typedef struct { + char c; + int i0 : 2; + int i1 : 4; + id f0; + int i2 : 31; + int i3 : 1; + id f1; + int : 0; + int a[3]; + id f2; + double d; + int i4 : 1; + volatile int i5 : 2; + volatile char i6; +} Bitfield1; + +typedef struct { + id x; + volatile int a[16]; +} VolatileArray ; + +#endif + +#ifdef USESTRUCT + +StrongSmall getStrongSmall(void); +StrongOuter getStrongOuter(void); +void calleeStrongSmall(StrongSmall); +void func(Strong *); + +// CHECK: %[[STRUCT_BITFIELD1:.*]] = type { i8, i8, i8*, i32, i8*, [3 x i32], i8*, double, i8, i8 } + +// CHECK: define void @test_constructor_destructor_StrongOuter() +// CHECK: %[[T:.*]] = alloca %[[STRUCT_STRONGOUTER:.*]], align 8 +// CHECK: %[[V0:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T]] to i8** +// CHECK: call void @__default_constructor_8_s16_s24(i8** %[[V0]]) +// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T]] to i8** +// CHECK: call void @__destructor_8_s16_s24(i8** %[[V1]]) +// CHECK: ret void + +// CHECK: define linkonce_odr hidden void @__default_constructor_8_s16_s24(i8** %[[DST:.*]]) +// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 +// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 +// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 +// CHECK: call void @__default_constructor_8_s16(i8** %[[V0]]) +// CHECK: %[[V1:.*]] = bitcast i8** %[[V0]] to i8* +// CHECK: %[[V2:.*]] = getelementptr inbounds i8, i8* %[[V1]], i64 24 +// CHECK: %[[V3:.*]] = bitcast i8* %[[V2]] to i8** +// CHECK: %[[V4:.*]] = bitcast i8** %[[V3]] to i8* +// CHECK: call void @llvm.memset.p0i8.i64(i8* align 8 %[[V4]], i8 0, i64 8, i1 false) +// CHECK: ret void + +// CHECK: define linkonce_odr hidden void @__default_constructor_8_s16(i8** %[[DST:.*]]) +// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 +// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 +// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 +// CHECK: %[[V1:.*]] = bitcast i8** %[[V0]] to i8* +// CHECK: %[[V2:.*]] = getelementptr inbounds i8, i8* %[[V1]], i64 16 +// CHECK: %[[V3:.*]] = bitcast i8* %[[V2]] to i8** +// CHECK: %[[V4:.*]] = bitcast i8** %[[V3]] to i8* +// CHECK: call void @llvm.memset.p0i8.i64(i8* align 8 %[[V4]], i8 0, i64 8, i1 false) +// CHECK: ret void + +// CHECK: define linkonce_odr hidden void @__destructor_8_s16_s24(i8** %[[DST:.*]]) +// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 +// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 +// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 +// CHECK: call void @__destructor_8_s16(i8** %[[V0]]) +// CHECK: %[[V1:.*]] = bitcast i8** %[[V0]] to i8* +// CHECK: %[[V2:.*]] = getelementptr inbounds i8, i8* %[[V1]], i64 24 +// CHECK: %[[V3:.*]] = bitcast i8* %[[V2]] to i8** +// CHECK: call void @objc_storeStrong(i8** %[[V3]], i8* null) +// CHECK: ret void + +// CHECK: define linkonce_odr hidden void @__destructor_8_s16(i8** %[[DST:.*]]) +// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 +// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 +// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 +// CHECK: %[[V1:.*]] = bitcast i8** %[[V0]] to i8* +// CHECK: %[[V2:.*]] = getelementptr inbounds i8, i8* %[[V1]], i64 16 +// CHECK: %[[V3:.*]] = bitcast i8* %[[V2]] to i8** +// CHECK: call void @objc_storeStrong(i8** %[[V3]], i8* null) +// CHECK: ret void + +void test_constructor_destructor_StrongOuter(void) { + StrongOuter t; +} + +// CHECK: define void @test_copy_constructor_StrongOuter(%[[STRUCT_STRONGOUTER:.*]]* %[[S:.*]]) +// CHECK: %[[S_ADDR:.*]] = alloca %[[STRUCT_STRONGOUTER]]*, align 8 +// CHECK: %[[T:.*]] = alloca %[[STRUCT_STRONGOUTER]], align 8 +// CHECK: store %[[STRUCT_STRONGOUTER]]* %[[S]], %[[STRUCT_STRONGOUTER]]** %[[S_ADDR]], align 8 +// CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGOUTER]]*, %[[STRUCT_STRONGOUTER]]** %[[S_ADDR]], align 8 +// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T]] to i8** +// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[V0]] to i8** +// CHECK: call void @__copy_constructor_8_8_t0w16_s16_s24_t32w8(i8** %[[V1]], i8** %[[V2]]) +// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T]] to i8** +// CHECK: call void @__destructor_8_s16_s24(i8** %[[V3]]) +// CHECK: ret void + +// CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 +// CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8 +// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 +// CHECK: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8 +// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 +// CHECK: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8 +// CHECK: call void @__copy_constructor_8_8_t0w16_s16(i8** %[[V0]], i8** %[[V1]]) +// CHECK: %[[V2:.*]] = bitcast i8** %[[V0]] to i8* +// CHECK: %[[V3:.*]] = getelementptr inbounds i8, i8* %[[V2]], i64 24 +// CHECK: %[[V4:.*]] = bitcast i8* %[[V3]] to i8** +// CHECK: %[[V5:.*]] = bitcast i8** %[[V1]] to i8* +// CHECK: %[[V6:.*]] = getelementptr inbounds i8, i8* %[[V5]], i64 24 +// CHECK: %[[V7:.*]] = bitcast i8* %[[V6]] to i8** +// CHECK: %[[V8:.*]] = load i8*, i8** %[[V7]], align 8 +// CHECK: %[[V9:.*]] = call i8* @objc_retain(i8* %[[V8]]) +// CHECK: store i8* %[[V9]], i8** %[[V4]], align 8 +// CHECK: %[[V10:.*]] = bitcast i8** %[[V0]] to i8* +// CHECK: %[[V11:.*]] = getelementptr inbounds i8, i8* %[[V10]], i64 32 +// CHECK: %[[V12:.*]] = bitcast i8* %[[V11]] to i8** +// CHECK: %[[V13:.*]] = bitcast i8** %[[V1]] to i8* +// CHECK: %[[V14:.*]] = getelementptr inbounds i8, i8* %[[V13]], i64 32 +// CHECK: %[[V15:.*]] = bitcast i8* %[[V14]] to i8** +// CHECK: %[[V16:.*]] = bitcast i8** %[[V12]] to i64* +// CHECK: %[[V17:.*]] = bitcast i8** %[[V15]] to i64* +// CHECK: %[[V18:.*]] = load i64, i64* %[[V17]], align 8 +// CHECK: store i64 %[[V18]], i64* %[[V16]], align 8 +// CHECK: ret void + +// CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_t0w16_s16(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 +// CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8 +// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 +// CHECK: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8 +// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 +// CHECK: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8 +// CHECK: %[[V2:.*]] = bitcast i8** %[[V0]] to i8* +// CHECK: %[[V3:.*]] = bitcast i8** %[[V1]] to i8* +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[V2]], i8* align 8 %[[V3]], i64 16, i1 false) +// CHECK: %[[V4:.*]] = bitcast i8** %[[V0]] to i8* +// CHECK: %[[V5:.*]] = getelementptr inbounds i8, i8* %[[V4]], i64 16 +// CHECK: %[[V6:.*]] = bitcast i8* %[[V5]] to i8** +// CHECK: %[[V7:.*]] = bitcast i8** %[[V1]] to i8* +// CHECK: %[[V8:.*]] = getelementptr inbounds i8, i8* %[[V7]], i64 16 +// CHECK: %[[V9:.*]] = bitcast i8* %[[V8]] to i8** +// CHECK: %[[V10:.*]] = load i8*, i8** %[[V9]], align 8 +// CHECK: %[[V11:.*]] = call i8* @objc_retain(i8* %[[V10]]) +// CHECK: store i8* %[[V11]], i8** %[[V6]], align 8 +// CHECK: ret void + +void test_copy_constructor_StrongOuter(StrongOuter *s) { + StrongOuter t = *s; +} + +/// CHECK: define linkonce_odr hidden void @__copy_assignment_8_8_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 +// CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8 +// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 +// CHECK: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8 +// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 +// CHECK: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8 +// CHECK: %[[V2:.*]] = bitcast i8** %[[V0]] to i8* +// CHECK: %[[V3:.*]] = getelementptr inbounds i8, i8* %[[V2]], i64 24 +// CHECK: %[[V4:.*]] = bitcast i8* %[[V3]] to i8** +// CHECK: %[[V5:.*]] = bitcast i8** %[[V1]] to i8* +// CHECK: %[[V6:.*]] = getelementptr inbounds i8, i8* %[[V5]], i64 24 +// CHECK: %[[V7:.*]] = bitcast i8* %[[V6]] to i8** +// CHECK: %[[V8:.*]] = load i8*, i8** %[[V7]], align 8 +// CHECK: call void @objc_storeStrong(i8** %[[V4]], i8* %[[V8]]) + +void test_copy_assignment_StrongOuter(StrongOuter *d, StrongOuter *s) { + *d = *s; +} + +// CHECK: define void @test_move_constructor_StrongOuter() +// CHECK: %[[T1:.*]] = getelementptr inbounds %[[STRUCT_BLOCK_BYREF_T:.*]], %[[STRUCT_BLOCK_BYREF_T]]* %{{.*}}, i32 0, i32 7 +// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T1]] to i8** +// CHECK: call void @__default_constructor_8_s16_s24(i8** %[[V1]]) +// CHECK: %[[T2:.*]] = getelementptr inbounds %[[STRUCT_BLOCK_BYREF_T]], %[[STRUCT_BLOCK_BYREF_T]]* %{{.*}}, i32 0, i32 7 +// CHECK: %[[V9:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T2]] to i8** +// CHECK: call void @__destructor_8_s16_s24(i8** %[[V9]]) + +// CHECK: define internal void @__Block_byref_object_copy_(i8*, i8*) +// CHECK: call void @__move_constructor_8_8_t0w16_s16_s24_t32w8( + +// CHECK: define linkonce_odr hidden void @__move_constructor_8_8_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 +// CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8 +// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 +// CHECK: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8 +// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 +// CHECK: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8 +// CHECK: call void @__move_constructor_8_8_t0w16_s16(i8** %[[V0]], i8** %[[V1]]) +// CHECK: %[[V2:.*]] = bitcast i8** %[[V0]] to i8* +// CHECK: %[[V3:.*]] = getelementptr inbounds i8, i8* %[[V2]], i64 24 +// CHECK: %[[V4:.*]] = bitcast i8* %[[V3]] to i8** +// CHECK: %[[V5:.*]] = bitcast i8** %[[V1]] to i8* +// CHECK: %[[V6:.*]] = getelementptr inbounds i8, i8* %[[V5]], i64 24 +// CHECK: %[[V7:.*]] = bitcast i8* %[[V6]] to i8** +// CHECK: %[[V8:.*]] = load i8*, i8** %[[V7]], align 8 +// CHECK: store i8* null, i8** %[[V7]], align 8 +// CHECK: store i8* %[[V8]], i8** %[[V4]], align 8 + +// CHECK: define internal void @__Block_byref_object_dispose_(i8*) +// CHECK: call void @__destructor_8_s16_s24( + +void test_move_constructor_StrongOuter(void) { + __block StrongOuter t; + BlockTy b = ^{ (void)t; }; +} + +// CHECK: define linkonce_odr hidden void @__move_assignment_8_8_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 +// CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8 +// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 +// CHECK: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8 +// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 +// CHECK: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8 +// CHECK: call void @__move_assignment_8_8_t0w16_s16(i8** %[[V0]], i8** %[[V1]]) +// CHECK: %[[V2:.*]] = bitcast i8** %[[V0]] to i8* +// CHECK: %[[V3:.*]] = getelementptr inbounds i8, i8* %[[V2]], i64 24 +// CHECK: %[[V4:.*]] = bitcast i8* %[[V3]] to i8** +// CHECK: %[[V5:.*]] = bitcast i8** %[[V1]] to i8* +// CHECK: %[[V6:.*]] = getelementptr inbounds i8, i8* %[[V5]], i64 24 +// CHECK: %[[V7:.*]] = bitcast i8* %[[V6]] to i8** +// CHECK: %[[V8:.*]] = load i8*, i8** %[[V7]], align 8 +// CHECK: store i8* null, i8** %[[V7]], align 8 +// CHECK: %[[V9:.*]] = load i8*, i8** %[[V4]], align 8 +// CHECK: store i8* %[[V8]], i8** %[[V4]], align 8 +// CHECK: call void @objc_release(i8* %[[V9]]) + +void test_move_assignment_StrongOuter(StrongOuter *p) { + *p = getStrongOuter(); +} + +// CHECK: define void @test_parameter_StrongSmall([2 x i64] %[[A_COERCE:.*]]) +// CHECK: %[[A:.*]] = alloca %[[STRUCT_STRONG:.*]], align 8 +// CHECK: %[[V0:.*]] = bitcast %[[STRUCT_STRONG]]* %[[A]] to [2 x i64]* +// CHECK: store [2 x i64] %[[A_COERCE]], [2 x i64]* %[[V0]], align 8 +// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONG]]* %[[A]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V1]]) +// CHECK: ret void + +void test_parameter_StrongSmall(StrongSmall a) { +} + +// CHECK: define void @test_argument_StrongSmall([2 x i64] %[[A_COERCE:.*]]) +// CHECK: %[[A:.*]] = alloca %[[STRUCT_STRONGSMALL:.*]], align 8 +// CHECK: %[[TEMP_LVALUE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8 +// CHECK: %[[V0:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[A]] to [2 x i64]* +// CHECK: store [2 x i64] %[[A_COERCE]], [2 x i64]* %[[V0]], align 8 +// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TEMP_LVALUE]] to i8** +// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[A]] to i8** +// CHECK: call void @__copy_constructor_8_8_t0w4_s8(i8** %[[V1]], i8** %[[V2]]) +// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TEMP_LVALUE]] to [2 x i64]* +// CHECK: %[[V4:.*]] = load [2 x i64], [2 x i64]* %[[V3]], align 8 +// CHECK: call void @calleeStrongSmall([2 x i64] %[[V4]]) +// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[A]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V5]]) +// CHECK: ret void + +void test_argument_StrongSmall(StrongSmall a) { + calleeStrongSmall(a); +} + +// CHECK: define [2 x i64] @test_return_StrongSmall([2 x i64] %[[A_COERCE:.*]]) +// CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_STRONGSMALL:.*]], align 8 +// CHECK: %[[A:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8 +// CHECK: %[[V0:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[A]] to [2 x i64]* +// CHECK: store [2 x i64] %[[A_COERCE]], [2 x i64]* %[[V0]], align 8 +// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[RETVAL]] to i8** +// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[A]] to i8** +// CHECK: call void @__copy_constructor_8_8_t0w4_s8(i8** %[[V1]], i8** %[[V2]]) +// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[A]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V3]]) +// CHECK: %[[V4:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[RETVAL]] to [2 x i64]* +// CHECK: %[[V5:.*]] = load [2 x i64], [2 x i64]* %[[V4]], align 8 +// CHECK: ret [2 x i64] %[[V5]] + +StrongSmall test_return_StrongSmall(StrongSmall a) { + return a; +} + +// CHECK: define void @test_destructor_ignored_result() +// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL:.*]], align 8 +// CHECK: %[[CALL:.*]] = call [2 x i64] @getStrongSmall() +// CHECK: %[[V0:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to [2 x i64]* +// CHECK: store [2 x i64] %[[CALL]], [2 x i64]* %[[V0]], align 8 +// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V1]]) +// CHECK: ret void + +void test_destructor_ignored_result(void) { + getStrongSmall(); +} + +// CHECK: define void @test_copy_constructor_StrongBlock( +// CHECK: call void @__copy_constructor_8_8_sb0( +// CHECK: call void @__destructor_8_sb0( +// CHECK: ret void + +// CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_sb0(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 +// CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8 +// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 +// CHECK: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8 +// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 +// CHECK: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8 +// CHECK: %[[V2:.*]] = load i8*, i8** %[[V1]], align 8 +// CHECK: %[[V3:.*]] = call i8* @objc_retainBlock(i8* %[[V2]]) +// CHECK: store i8* %[[V3]], i8** %[[V0]], align 8 +// CHECK: ret void + +void test_copy_constructor_StrongBlock(StrongBlock *s) { + StrongBlock t = *s; +} + +// CHECK: define void @test_copy_assignment_StrongBlock(%[[STRUCT_STRONGBLOCK:.*]]* %[[D:.*]], %[[STRUCT_STRONGBLOCK]]* %[[S:.*]]) +// CHECK: call void @__copy_assignment_8_8_sb0( + +// CHECK: define linkonce_odr hidden void @__copy_assignment_8_8_sb0(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 +// CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8 +// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 +// CHECK: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8 +// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 +// CHECK: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8 +// CHECK: %[[V2:.*]] = load i8*, i8** %[[V1]], align 8 +// CHECK: %[[V3:.*]] = call i8* @objc_retainBlock(i8* %[[V2]]) +// CHECK: %[[V4:.*]] = load i8*, i8** %[[V0]], align 8 +// CHECK: store i8* %[[V3]], i8** %[[V0]], align 8 +// CHECK: call void @objc_release(i8* %[[V4]]) +// CHECK: ret void + +void test_copy_assignment_StrongBlock(StrongBlock *d, StrongBlock *s) { + *d = *s; +} + +// CHECK: define void @test_copy_constructor_StrongVolatile0( +// CHECK: call void @__copy_constructor_8_8_t0w4_sv8( +// CHECK: call void @__destructor_8_sv8( + +// CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_t0w4_sv8( +// CHECK: %[[V8:.*]] = load volatile i8*, i8** %{{.*}}, align 8 +// CHECK: %[[V9:.*]] = call i8* @objc_retain(i8* %[[V8]]) +// CHECK: store volatile i8* %[[V9]], i8** %{{.*}}, align 8 + +void test_copy_constructor_StrongVolatile0(StrongVolatile *s) { + StrongVolatile t = *s; +} + +// CHECK: define void @test_copy_constructor_StrongVolatile1( +// CHECK: call void @__copy_constructor_8_8_tv0w128_sv16( + +void test_copy_constructor_StrongVolatile1(Strong *s) { + volatile Strong t = *s; +} + +// CHECK: define void @test_block_capture_Strong() +// CHECK: call void @__default_constructor_8_s16( +// CHECK: call void @__copy_constructor_8_8_t0w16_s16( +// CHECK: call void @__destructor_8_s16( +// CHECK: call void @__destructor_8_s16( +// CHECK: ret void + +// CHECK: define internal void @__copy_helper_block_.1(i8*, i8*) +// CHECK: call void @__copy_constructor_8_8_t0w16_s16( +// CHECK: ret void + +// CHECK: define internal void @__destroy_helper_block_.2( +// CHECK: call void @__destructor_8_s16( +// CHECK: ret void + +void test_block_capture_Strong(void) { + Strong t; + BlockTy b = ^(){ (void)t; }; +} + +// CHECK: define void @test_variable_length_array(i32 %[[N:.*]]) +// CHECK: %[[N_ADDR:.*]] = alloca i32, align 4 +// CHECK: store i32 %[[N]], i32* %[[N_ADDR]], align 4 +// CHECK: %[[V0:.*]] = load i32, i32* %[[N_ADDR]], align 4 +// CHECK: %[[V1:.*]] = zext i32 %[[V0]] to i64 +// CHECK: %[[VLA:.*]] = alloca %[[STRUCT_STRONG:.*]], i64 %[[V1]], align 8 +// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONG]]* %[[VLA]] to i8** +// CHECK: %[[V4:.*]] = mul nuw i64 24, %[[V1]] +// CHECK: %[[V5:.*]] = bitcast i8** %[[V3]] to i8* +// CHECK: %[[V6:.*]] = getelementptr inbounds i8, i8* %[[V5]], i64 %[[V4]] +// CHECK: %[[DSTARRAY_END:.*]] = bitcast i8* %[[V6]] to i8** +// CHECK: br label + +// CHECK: %[[DSTADDR_CUR:.*]] = phi i8** [ %[[V3]], {{.*}} ], [ %[[V7:.*]], {{.*}} ] +// CHECK: %[[DONE:.*]] = icmp eq i8** %[[DSTADDR_CUR]], %[[DSTARRAY_END]] +// CHECK: br i1 %[[DONE]], label + +// CHECK: call void @__default_constructor_8_s16(i8** %[[DSTADDR_CUR]]) +// CHECK: %[[V8:.*]] = bitcast i8** %[[DSTADDR_CUR]] to i8* +// CHECK: %[[V9:.*]] = getelementptr inbounds i8, i8* %[[V8]], i64 24 +// CHECK: %[[V7]] = bitcast i8* %[[V9]] to i8** +// CHECK: br label + +// CHECK: call void @func(%[[STRUCT_STRONG]]* %[[VLA]]) +// CHECK: %[[V10:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[VLA]], i64 %[[V1]] +// CHECK: %[[ARRAYDESTROY_ISEMPTY:.*]] = icmp eq %[[STRUCT_STRONG]]* %[[VLA]], %[[V10]] +// CHECK: br i1 %[[ARRAYDESTROY_ISEMPTY]], label + +// CHECK: %[[ARRAYDESTROY_ELEMENTPAST:.*]] = phi %[[STRUCT_STRONG]]* [ %[[V10]], {{.*}} ], [ %[[ARRAYDESTROY_ELEMENT:.*]], {{.*}} ] +// CHECK: %[[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[ARRAYDESTROY_ELEMENTPAST]], i64 -1 +// CHECK: %[[V11:.*]] = bitcast %[[STRUCT_STRONG]]* %[[ARRAYDESTROY_ELEMENT]] to i8** +// CHECK: call void @__destructor_8_s16(i8** %[[V11]]) +// CHECK: %[[ARRAYDESTROY_DONE:.*]] = icmp eq %[[STRUCT_STRONG]]* %[[ARRAYDESTROY_ELEMENT]], %[[VLA]] +// CHECK: br i1 %[[ARRAYDESTROY_DONE]], label + +// CHECK: ret void + +void test_variable_length_array(int n) { + Strong a[n]; + func(a); +} + +// CHECK: define linkonce_odr hidden void @__default_constructor_8_AB8s8n4_s8_AE( +// CHECK: call void @llvm.memset.p0i8.i64(i8* align 8 %{{.*}}, i8 0, i64 32, i1 false) +void test_constructor_destructor_IDArray(void) { + IDArray t; +} + +// CHECK: define linkonce_odr hidden void @__default_constructor_8_AB8s24n4_s24_AE( +void test_constructor_destructor_StructArray(void) { + StructArray t; +} + +// Check that IRGen copies the 9-bit bitfield emitting i16 load and store. + +// CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_s0_t8w2( +// CHECK: %[[V4:.*]] = bitcast i8** %{{.*}} to i8* +// CHECK: %[[V5:.*]] = getelementptr inbounds i8, i8* %[[V4]], i64 8 +// CHECK: %[[V6:.*]] = bitcast i8* %[[V5]] to i8** +// CHECK: %[[V7:.*]] = bitcast i8** %{{.*}} to i8* +// CHECK: %[[V8:.*]] = getelementptr inbounds i8, i8* %[[V7]], i64 8 +// CHECK: %[[V9:.*]] = bitcast i8* %[[V8]] to i8** +// CHECK: %[[V10:.*]] = bitcast i8** %[[V6]] to i16* +// CHECK: %[[V11:.*]] = bitcast i8** %[[V9]] to i16* +// CHECK: %[[V12:.*]] = load i16, i16* %[[V11]], align 8 +// CHECK: store i16 %[[V12]], i16* %[[V10]], align 8 +// CHECK: ret void + +void test_copy_constructor_Bitfield0(Bitfield0 *a) { + Bitfield0 t = *a; +} + +// CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_t0w2_s8_t16w4_s24_t32w12_s48_t56w9_tv513w2_tv520w8 +// CHECK: %[[V4:.*]] = load i16, i16* %{{.*}}, align 8 +// CHECK: store i16 %[[V4]], i16* %{{.*}}, align 8 +// CHECK: %[[V21:.*]] = load i32, i32* %{{.*}}, align 8 +// CHECK: store i32 %[[V21]], i32* %{{.*}}, align 8 +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %{{.*}}, i8* align 8 %{{.*}}, i64 12, i1 false) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %{{.*}}, i8* align 8 %{{.*}}, i64 9, i1 false) +// CHECK: %[[V54:.*]] = bitcast i8** %[[V0:.*]] to %[[STRUCT_BITFIELD1]]* +// CHECK: %[[I5:.*]] = getelementptr inbounds %[[STRUCT_BITFIELD1]], %[[STRUCT_BITFIELD1]]* %[[V54]], i32 0, i32 8 +// CHECK: %[[V55:.*]] = bitcast i8** %[[V1:.*]] to %[[STRUCT_BITFIELD1]]* +// CHECK: %[[I51:.*]] = getelementptr inbounds %[[STRUCT_BITFIELD1]], %[[STRUCT_BITFIELD1]]* %[[V55]], i32 0, i32 8 +// CHECK: %[[BF_LOAD:.*]] = load volatile i8, i8* %[[I51]], align 8 +// CHECK: %[[BF_SHL:.*]] = shl i8 %[[BF_LOAD]], 5 +// CHECK: %[[BF_ASHR:.*]] = ashr i8 %[[BF_SHL]], 6 +// CHECK: %[[BF_CAST:.*]] = sext i8 %[[BF_ASHR]] to i32 +// CHECK: %[[V56:.*]] = trunc i32 %[[BF_CAST]] to i8 +// CHECK: %[[BF_LOAD2:.*]] = load volatile i8, i8* %[[I5]], align 8 +// CHECK: %[[BF_VALUE:.*]] = and i8 %[[V56]], 3 +// CHECK: %[[BF_SHL3:.*]] = shl i8 %[[BF_VALUE]], 1 +// CHECK: %[[BF_CLEAR:.*]] = and i8 %[[BF_LOAD2]], -7 +// CHECK: %[[BF_SET:.*]] = or i8 %[[BF_CLEAR]], %[[BF_SHL3]] +// CHECK: store volatile i8 %[[BF_SET]], i8* %[[I5]], align 8 +// CHECK: %[[V57:.*]] = bitcast i8** %[[V0]] to %[[STRUCT_BITFIELD1]]* +// CHECK: %[[I6:.*]] = getelementptr inbounds %[[STRUCT_BITFIELD1]], %[[STRUCT_BITFIELD1]]* %[[V57]], i32 0, i32 9 +// CHECK: %[[V58:.*]] = bitcast i8** %[[V1]] to %[[STRUCT_BITFIELD1]]* +// CHECK: %[[I64:.*]] = getelementptr inbounds %[[STRUCT_BITFIELD1]], %[[STRUCT_BITFIELD1]]* %[[V58]], i32 0, i32 9 +// CHECK: %[[V59:.*]] = load volatile i8, i8* %[[I64]], align 1 +// CHECK: store volatile i8 %[[V59]], i8* %[[I6]], align 1 + +void test_copy_constructor_Bitfield1(Bitfield1 *a) { + Bitfield1 t = *a; +} + +// CHECK: define void @test_strong_in_union() +// CHECK: alloca %{{.*}} +// CHECK-NEXT: ret void + +void test_strong_in_union() { + U t; +} + +// CHECK: define void @test_copy_constructor_VolatileArray( +// CHECK: call void @__copy_constructor_8_8_s0_AB8s4n16_tv64w32_AE( + +// CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_s0_AB8s4n16_tv64w32_AE( +// CHECK: %[[ADDR_CUR:.*]] = phi i8** +// CHECK: %[[ADDR_CUR1:.*]] = phi i8** +// CHECK: %[[V12:.*]] = bitcast i8** %[[ADDR_CUR]] to i32* +// CHECK: %[[V13:.*]] = bitcast i8** %[[ADDR_CUR1]] to i32* +// CHECK: %[[V14:.*]] = load volatile i32, i32* %[[V13]], align 4 +// CHECK: store volatile i32 %[[V14]], i32* %[[V12]], align 4 + +void test_copy_constructor_VolatileArray(VolatileArray *a) { + VolatileArray t = *a; +} + +#endif /* USESTRUCT */ diff --git a/test/CodeGenObjC/ubsan-nullability.m b/test/CodeGenObjC/ubsan-nullability.m index eeb24b03c868..8e7a9cba7c71 100644 --- a/test/CodeGenObjC/ubsan-nullability.m +++ b/test/CodeGenObjC/ubsan-nullability.m @@ -1,6 +1,6 @@ // REQUIRES: asserts -// RUN: %clang_cc1 -x objective-c -emit-llvm -triple x86_64-apple-macosx10.10.0 -fsanitize=nullability-arg,nullability-assign,nullability-return -w %s -o - | FileCheck %s -// RUN: %clang_cc1 -x objective-c++ -emit-llvm -triple x86_64-apple-macosx10.10.0 -fsanitize=nullability-arg,nullability-assign,nullability-return -w %s -o - | FileCheck %s +// RUN: %clang_cc1 -x objective-c -emit-llvm -triple x86_64-apple-macosx10.10.0 -fblocks -fobjc-arc -fsanitize=nullability-arg,nullability-assign,nullability-return -w %s -o - | FileCheck %s +// RUN: %clang_cc1 -x objective-c++ -emit-llvm -triple x86_64-apple-macosx10.10.0 -fblocks -fobjc-arc -fsanitize=nullability-arg,nullability-assign,nullability-return -w %s -o - | FileCheck %s // CHECK: [[NONNULL_RV_LOC1:@.*]] = private unnamed_addr global {{.*}} i32 100, i32 6 // CHECK: [[NONNULL_ARG_LOC:@.*]] = private unnamed_addr global {{.*}} i32 204, i32 15 {{.*}} i32 190, i32 23 @@ -177,6 +177,37 @@ void call_A(A *a, int *p) { void dont_crash(int *_Nonnull p, ...) {} +@protocol NSObject +- (id)init; +@end +@interface NSObject <NSObject> {} +@end + +#pragma clang assume_nonnull begin + +/// Create a "NSObject * _Nonnull" instance. +NSObject *get_nonnull_error() { + // Use nil for convenience. The actual object doesn't matter. + return (NSObject *)NULL; +} + +NSObject *_Nullable no_null_return_value_diagnostic(int flag) { +// CHECK-LABEL: define internal {{.*}}no_null_return_value_diagnostic{{i?}}_block_invoke +// CHECK-NOT: @__ubsan_handle_nullability_return + NSObject *_Nullable (^foo)() = ^() { + if (flag) { + // Clang should not infer a nonnull return value for this block when this + // call is present. + return get_nonnull_error(); + } else { + return (NSObject *)NULL; + } + }; + return foo(); +} + +#pragma clang assume_nonnull end + int main() { nonnull_retval1(INULL); nonnull_retval2(INNULL, INNULL, INULL, (int *_Nullable)NULL, 0, 0, 0, 0); @@ -188,5 +219,7 @@ int main() { nonnull_init2(INULL); call_A((A *)NULL, INULL); dont_crash(INNULL, NULL); + no_null_return_value_diagnostic(0); + no_null_return_value_diagnostic(1); return 0; } diff --git a/test/CodeGenObjC/weak-in-c-struct.m b/test/CodeGenObjC/weak-in-c-struct.m new file mode 100644 index 000000000000..b0f4c0851021 --- /dev/null +++ b/test/CodeGenObjC/weak-in-c-struct.m @@ -0,0 +1,193 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks -fobjc-runtime=ios-11.0 -emit-llvm -o - %s | FileCheck -check-prefix=ARM64 -check-prefix=COMMON %s +// RUN: %clang_cc1 -triple thumbv7-apple-ios10 -fobjc-arc -fblocks -fobjc-runtime=ios-10.0 -emit-llvm -o - %s | FileCheck -check-prefix=COMMON %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.13 -fobjc-arc -fblocks -fobjc-runtime=macosx-10.13.0 -emit-llvm -o - %s | FileCheck -check-prefix=COMMON %s +// RUN: %clang_cc1 -triple i386-apple-macosx10.13.0 -fobjc-arc -fblocks -fobjc-runtime=macosx-fragile-10.13.0 -emit-llvm -o - %s | FileCheck -check-prefix=COMMON %s + +typedef void (^BlockTy)(void); + +// COMMON: %[[STRUCT_WEAK:.*]] = type { i32, i8* } + +typedef struct { + int f0; + __weak id f1; +} Weak; + +Weak getWeak(void); +void calleeWeak(Weak); + +// ARM64: define void @test_constructor_destructor_Weak() +// ARM64: %[[T:.*]] = alloca %[[STRUCT_WEAK]], align 8 +// ARM64: %[[V0:.*]] = bitcast %[[STRUCT_WEAK]]* %[[T]] to i8** +// ARM64: call void @__default_constructor_8_w8(i8** %[[V0]]) +// ARM64: %[[V1:.*]] = bitcast %[[STRUCT_WEAK]]* %[[T]] to i8** +// ARM64: call void @__destructor_8_w8(i8** %[[V1]]) +// ARM64: ret void + +// ARM64: define linkonce_odr hidden void @__default_constructor_8_w8(i8** %[[DST:.*]]) +// ARM64: %[[DST_ADDR:.*]] = alloca i8**, align 8 +// ARM64: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 +// ARM64: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 +// ARM64: %[[V1]] = bitcast i8** %[[V0]] to i8* +// ARM64: %[[V2:.*]] = getelementptr inbounds i8, i8* %[[V1]], i64 8 +// ARM64: %[[V3:.*]] = bitcast i8* %[[V2]] to i8** +// ARM64: %[[V4:.*]] = bitcast i8** %[[V3]] to i8* +// ARM64: call void @llvm.memset.p0i8.i64(i8* align 8 %[[V4]], i8 0, i64 8, i1 false) + +// ARM64: define linkonce_odr hidden void @__destructor_8_w8(i8** %[[DST:.*]]) +// ARM64: %[[DST_ADDR:.*]] = alloca i8**, align 8 +// ARM64: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 +// ARM64: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 +// ARM64: %[[V1:.*]] = bitcast i8** %[[V0]] to i8* +// ARM64: %[[V2:.*]] = getelementptr inbounds i8, i8* %[[V1]], i64 8 +// ARM64: %[[V3:.*]] = bitcast i8* %[[V2]] to i8** +// ARM64: call void @objc_destroyWeak(i8** %[[V3]]) + +void test_constructor_destructor_Weak(void) { + Weak t; +} + +// ARM64: define void @test_copy_constructor_Weak(%[[STRUCT_WEAK]]* %{{.*}}) +// ARM64: call void @__copy_constructor_8_8_t0w4_w8(i8** %{{.*}}, i8** %{{.*}}) +// ARM64: call void @__destructor_8_w8(i8** %{{.*}}) + +// ARM64: define linkonce_odr hidden void @__copy_constructor_8_8_t0w4_w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +// ARM64: %[[DST_ADDR:.*]] = alloca i8**, align 8 +// ARM64: %[[SRC_ADDR:.*]] = alloca i8**, align 8 +// ARM64: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 +// ARM64: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8 +// ARM64: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 +// ARM64: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8 +// ARM64: %[[V2:.*]] = bitcast i8** %[[V0]] to i32* +// ARM64: %[[V3:.*]] = bitcast i8** %[[V1]] to i32* +// ARM64: %[[V4:.*]] = load i32, i32* %[[V3]], align 8 +// ARM64: store i32 %[[V4]], i32* %[[V2]], align 8 +// ARM64: %[[V5:.*]] = bitcast i8** %[[V0]] to i8* +// ARM64: %[[V6:.*]] = getelementptr inbounds i8, i8* %[[V5]], i64 8 +// ARM64: %[[V7:.*]] = bitcast i8* %[[V6]] to i8** +// ARM64: %[[V8:.*]] = bitcast i8** %[[V1]] to i8* +// ARM64: %[[V9:.*]] = getelementptr inbounds i8, i8* %[[V8]], i64 8 +// ARM64: %[[V10:.*]] = bitcast i8* %[[V9]] to i8** +// ARM64: call void @objc_copyWeak(i8** %[[V7]], i8** %[[V10]]) + +void test_copy_constructor_Weak(Weak *s) { + Weak t = *s; +} + +// ARM64: define void @test_copy_assignment_Weak(%[[STRUCT_WEAK]]* %{{.*}}, %[[STRUCT_WEAK]]* %{{.*}}) +// ARM64: call void @__copy_assignment_8_8_t0w4_w8(i8** %{{.*}}, i8** %{{.*}}) + +// ARM64: define linkonce_odr hidden void @__copy_assignment_8_8_t0w4_w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +// ARM64: %[[DST_ADDR:.*]] = alloca i8**, align 8 +// ARM64: %[[SRC_ADDR:.*]] = alloca i8**, align 8 +// ARM64: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 +// ARM64: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8 +// ARM64: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 +// ARM64: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8 +// ARM64: %[[V2:.*]] = bitcast i8** %[[V0]] to i32* +// ARM64: %[[V3:.*]] = bitcast i8** %[[V1]] to i32* +// ARM64: %[[V4:.*]] = load i32, i32* %[[V3]], align 8 +// ARM64: store i32 %[[V4]], i32* %[[V2]], align 8 +// ARM64: %[[V5:.*]] = bitcast i8** %[[V0]] to i8* +// ARM64: %[[V6:.*]] = getelementptr inbounds i8, i8* %[[V5]], i64 8 +// ARM64: %[[V7:.*]] = bitcast i8* %[[V6]] to i8** +// ARM64: %[[V8:.*]] = bitcast i8** %[[V1]] to i8* +// ARM64: %[[V9:.*]] = getelementptr inbounds i8, i8* %[[V8]], i64 8 +// ARM64: %[[V10:.*]] = bitcast i8* %[[V9]] to i8** +// ARM64: %[[V11:.*]] = call i8* @objc_loadWeakRetained(i8** %[[V10]]) +// ARM64: %[[V12:.*]] = call i8* @objc_storeWeak(i8** %[[V7]], i8* %[[V11]]) +// ARM64: call void @objc_release(i8* %[[V11]]) + +void test_copy_assignment_Weak(Weak *d, Weak *s) { + *d = *s; +} + +// ARM64: define internal void @__Block_byref_object_copy_(i8*, i8*) +// ARM64: call void @__move_constructor_8_8_t0w4_w8(i8** %{{.*}}, i8** %{{.*}}) + +// ARM64: define linkonce_odr hidden void @__move_constructor_8_8_t0w4_w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +// ARM64: %[[DST_ADDR:.*]] = alloca i8**, align 8 +// ARM64: %[[SRC_ADDR:.*]] = alloca i8**, align 8 +// ARM64: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 +// ARM64: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8 +// ARM64: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 +// ARM64: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8 +// ARM64: %[[V2:.*]] = bitcast i8** %[[V0]] to i32* +// ARM64: %[[V3:.*]] = bitcast i8** %[[V1]] to i32* +// ARM64: %[[V4:.*]] = load i32, i32* %[[V3]], align 8 +// ARM64: store i32 %[[V4]], i32* %[[V2]], align 8 +// ARM64: %[[V5:.*]] = bitcast i8** %[[V0]] to i8* +// ARM64: %[[V6:.*]] = getelementptr inbounds i8, i8* %[[V5]], i64 8 +// ARM64: %[[V7:.*]] = bitcast i8* %[[V6]] to i8** +// ARM64: %[[V8:.*]] = bitcast i8** %[[V1]] to i8* +// ARM64: %[[V9:.*]] = getelementptr inbounds i8, i8* %[[V8]], i64 8 +// ARM64: %[[V10:.*]] = bitcast i8* %[[V9]] to i8** +// ARM64: call void @objc_moveWeak(i8** %[[V7]], i8** %[[V10]]) + +void test_move_constructor_Weak(void) { + __block Weak t; + BlockTy b = ^{ (void)t; }; +} + +// ARM64: define void @test_move_assignment_Weak(%[[STRUCT_WEAK]]* %{{.*}}) +// ARM64: call void @__move_assignment_8_8_t0w4_w8(i8** %{{.*}}, i8** %{{.*}}) + +// ARM64: define linkonce_odr hidden void @__move_assignment_8_8_t0w4_w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +// ARM64: %[[DST_ADDR:.*]] = alloca i8**, align 8 +// ARM64: %[[SRC_ADDR:.*]] = alloca i8**, align 8 +// ARM64: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 +// ARM64: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8 +// ARM64: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 +// ARM64: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8 +// ARM64: %[[V2:.*]] = bitcast i8** %[[V0]] to i32* +// ARM64: %[[V3:.*]] = bitcast i8** %[[V1]] to i32* +// ARM64: %[[V4:.*]] = load i32, i32* %[[V3]], align 8 +// ARM64: store i32 %[[V4]], i32* %[[V2]], align 8 +// ARM64: %[[V5:.*]] = bitcast i8** %[[V0]] to i8* +// ARM64: %[[V6:.*]] = getelementptr inbounds i8, i8* %[[V5]], i64 8 +// ARM64: %[[V7:.*]] = bitcast i8* %[[V6]] to i8** +// ARM64: %[[V8:.*]] = bitcast i8** %[[V1]] to i8* +// ARM64: %[[V9:.*]] = getelementptr inbounds i8, i8* %[[V8]], i64 8 +// ARM64: %[[V10:.*]] = bitcast i8* %[[V9]] to i8** +// ARM64: %[[V11:.*]] = call i8* @objc_loadWeakRetained(i8** %[[V10]]) +// ARM64: %[[V12:.*]] = call i8* @objc_storeWeak(i8** %[[V7]], i8* %[[V11]]) +// ARM64: call void @objc_destroyWeak(i8** %[[V10]]) +// ARM64: call void @objc_release(i8* %[[V11]]) + +void test_move_assignment_Weak(Weak *p) { + *p = getWeak(); +} + +// COMMON: define void @test_parameter_Weak(%[[STRUCT_WEAK]]* %[[A:.*]]) +// COMMON: %[[V0:.*]] = bitcast %[[STRUCT_WEAK]]* %[[A]] to i8** +// COMMON: call void @__destructor_{{.*}}(i8** %[[V0]]) + +void test_parameter_Weak(Weak a) { +} + +// COMMON: define void @test_argument_Weak(%[[STRUCT_WEAK]]* %[[A:.*]]) +// COMMON: %[[A_ADDR:.*]] = alloca %[[STRUCT_WEAK]]* +// COMMON: %[[AGG_TMP:.*]] = alloca %[[STRUCT_WEAK]] +// COMMON: store %[[STRUCT_WEAK]]* %[[A]], %[[STRUCT_WEAK]]** %[[A_ADDR]] +// COMMON: %[[V0:.*]] = load %[[STRUCT_WEAK]]*, %[[STRUCT_WEAK]]** %[[A_ADDR]] +// COMMON: %[[V1:.*]] = bitcast %[[STRUCT_WEAK]]* %[[AGG_TMP]] to i8** +// COMMON: %[[V2:.*]] = bitcast %[[STRUCT_WEAK]]* %[[V0]] to i8** +// COMMON: call void @__copy_constructor_{{.*}}(i8** %[[V1]], i8** %[[V2]]) +// COMMON: call void @calleeWeak(%[[STRUCT_WEAK]]* %[[AGG_TMP]]) +// COMMON-NEXT: ret + +void test_argument_Weak(Weak *a) { + calleeWeak(*a); +} + +// COMMON: define void @test_return_Weak(%[[STRUCT_WEAK]]* noalias sret %[[AGG_RESULT:.*]], %[[STRUCT_WEAK]]* %[[A:.*]]) +// COMMON: %[[A_ADDR:.*]] = alloca %[[STRUCT_WEAK]]* +// COMMON: store %[[STRUCT_WEAK]]* %[[A]], %[[STRUCT_WEAK]]** %[[A_ADDR]] +// COMMON: %[[V0:.*]] = load %[[STRUCT_WEAK]]*, %[[STRUCT_WEAK]]** %[[A_ADDR]] +// COMMON: %[[V1:.*]] = bitcast %[[STRUCT_WEAK]]* %[[AGG_RESULT]] to i8** +// COMMON: %[[V2:.*]] = bitcast %[[STRUCT_WEAK]]* %[[V0]] to i8** +// COMMON: call void @__copy_constructor_{{.*}}(i8** %[[V1]], i8** %[[V2]]) +// COMMON: ret void + +Weak test_return_Weak(Weak *a) { + return *a; +} |