214 lines · plain
1// RUN: %clang_cc1 -no-enable-noundef-analysis -triple x86_64-apple-darwin -fblocks -fobjc-arc -fobjc-runtime-has-weak -emit-llvm %s -o - | FileCheck -check-prefix CHECK-LP64 %s2// RUN: %clang_cc1 -no-enable-noundef-analysis -triple x86_64-apple-darwin -O1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -emit-llvm %s -o - | FileCheck -check-prefix CHECK-LP64-OPT %s3 4extern void use(id);5extern void use_block(void (^)(void));6 7struct NSFastEnumerationState;8@interface NSArray9- (unsigned long) countByEnumeratingWithState: (struct NSFastEnumerationState*) state10 objects: (id*) buffer11 count: (unsigned long) bufferSize;12@end;13 14void test0(NSArray *array) {15 // 'x' should be initialized without a retain.16 // We should actually do a non-constant capture, and that17 // capture should require a retain.18 for (id x in array) {19 use_block(^{ use(x); });20 }21}22 23// CHECK-LP64-LABEL: define{{.*}} void @test0(24// CHECK-LP64: [[ARRAY:%.*]] = alloca ptr,25// CHECK-LP64-NEXT: [[X:%.*]] = alloca ptr,26// CHECK-LP64-NEXT: [[STATE:%.*]] = alloca [[STATE_T:%.*]],27// CHECK-LP64-NEXT: [[BUFFER:%.*]] = alloca [16 x ptr], align 828// CHECK-LP64-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],29 30// CHECK-LP64-OPT-LABEL: define{{.*}} void @test031// CHECK-LP64-OPT: [[STATE:%.*]] = alloca [[STATE_T:%.*]], align 832// CHECK-LP64-OPT-NEXT: [[BUFFER:%.*]] = alloca [16 x ptr], align 833// CHECK-LP64-OPT-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 834 35// Initialize 'array'.36// CHECK-LP64-NEXT: store ptr null, ptr [[ARRAY]]37// CHECK-LP64-NEXT: call void @llvm.objc.storeStrong(ptr [[ARRAY]], ptr {{%.*}}) [[NUW:#[0-9]+]]38 39// Initialize the fast enumaration state.40// CHECK-LP64-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[STATE]], i8 0, i64 64, i1 false)41 42// Evaluate the collection expression and retain.43// CHECK-LP64-NEXT: [[T0:%.*]] = load ptr, ptr [[ARRAY]], align 844// CHECK-LP64-NEXT: [[SAVED_ARRAY:%.*]] = call ptr @llvm.objc.retain(ptr [[T0]])45 46// Call the enumeration method.47// CHECK-LP64-NEXT: [[T1:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_48// CHECK-LP64-NEXT: [[SIZE:%.*]] = call i64 @objc_msgSend(ptr [[SAVED_ARRAY]], ptr [[T1]], ptr [[STATE]], ptr [[BUFFER]], i64 16)49 50// Check for a nonzero result.51// CHECK-LP64-NEXT: [[T0:%.*]] = icmp eq i64 [[SIZE]], 052// CHECK-LP64-NEXT: br i1 [[T0]]53 54// CHECK-LP64: [[T0:%.*]] = getelementptr inbounds nuw [[STATE_T]], ptr [[STATE]], i32 0, i32 155// CHECK-LP64-NEXT: [[T1:%.*]] = load ptr, ptr [[T0]]56// CHECK-LP64-NEXT: [[T2:%.*]] = getelementptr inbounds ptr, ptr [[T1]], i6457// CHECK-LP64-NEXT: [[T3:%.*]] = load ptr, ptr [[T2]]58// CHECK-LP64-NEXT: store ptr [[T3]], ptr [[X]]59 60// CHECK-LP64: [[CAPTURED:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 561// CHECK-LP64-NEXT: [[T1:%.*]] = load ptr, ptr [[X]]62// CHECK-LP64-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retain(ptr [[T1]])63// CHECK-LP64-NEXT: store ptr [[T2]], ptr [[CAPTURED]]64// CHECK-LP64-NEXT: call void @use_block(ptr [[BLOCK]])65// CHECK-LP64-NEXT: call void @llvm.objc.storeStrong(ptr [[CAPTURED]], ptr null)66// CHECK-LP64-NOT: call void (...) @llvm.objc.clang.arc.use(67 68// CHECK-LP64-OPT: [[D0:%.*]] = getelementptr inbounds nuw i8, ptr [[BLOCK]], i64 3269// CHECK-LP64-OPT: [[CAPTURE:%.*]] = load ptr, ptr [[D0]]70// CHECK-LP64-OPT: call void (...) @llvm.objc.clang.arc.use(ptr [[CAPTURE]])71 72// CHECK-LP64: [[T1:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_73// CHECK-LP64-NEXT: [[SIZE:%.*]] = call i64 @objc_msgSend(ptr [[SAVED_ARRAY]], ptr [[T1]], ptr [[STATE]], ptr [[BUFFER]], i64 16)74 75// Release the array.76// CHECK-LP64: call void @llvm.objc.release(ptr [[SAVED_ARRAY]])77 78// Destroy 'array'.79// CHECK-LP64: call void @llvm.objc.storeStrong(ptr [[ARRAY]], ptr null)80// CHECK-LP64-NEXT: ret void81 82// CHECK-LP64-LABEL: define internal void @__test0_block_invoke83// CHECK-LP64-NOT: ret84// CHECK-LP64: [[T0:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr {{%.*}}, i32 0, i32 585// CHECK-LP64-NEXT: [[T2:%.*]] = load ptr, ptr [[T0]], align 8 86// CHECK-LP64-NEXT: call void @use(ptr [[T2]])87 88void test1(NSArray *array) {89 for (__weak id x in array) {90 use_block(^{ use(x); });91 }92}93 94// CHECK-LP64-LABEL: define{{.*}} void @test1(95// CHECK-LP64: alloca ptr,96// CHECK-LP64-NEXT: [[X:%.*]] = alloca ptr,97// CHECK-LP64-NEXT: [[STATE:%.*]] = alloca [[STATE_T:%.*]],98// CHECK-LP64-NEXT: alloca [16 x ptr], align 899// CHECK-LP64-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],100 101// CHECK-LP64: [[T0:%.*]] = getelementptr inbounds nuw [[STATE_T]], ptr [[STATE]], i32 0, i32 1102// CHECK-LP64-NEXT: [[T1:%.*]] = load ptr, ptr [[T0]]103// CHECK-LP64-NEXT: [[T2:%.*]] = getelementptr inbounds ptr, ptr [[T1]], i64104// CHECK-LP64-NEXT: [[T3:%.*]] = load ptr, ptr [[T2]]105// CHECK-LP64-NEXT: call ptr @llvm.objc.initWeak(ptr [[X]], ptr [[T3]])106 107// CHECK-LP64: [[T0:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5108// CHECK-LP64: call void @llvm.objc.copyWeak(ptr [[T0]], ptr [[X]])109// CHECK-LP64: call void @use_block110// CHECK-LP64-NEXT: call void @llvm.objc.destroyWeak(ptr [[T0]])111// CHECK-LP64-NEXT: call void @llvm.objc.destroyWeak(ptr [[X]])112 113@interface Test2114- (NSArray *) array;115@end116void test2(Test2 *a) {117 for (id x in a.array) {118 use(x);119 }120}121 122// CHECK-LP64-LABEL: define{{.*}} void @test2(123// CHECK-LP64: [[T0:%.*]] = call ptr @objc_msgSend(124// CHECK-LP64-NEXT: [[T2:%.*]] = notail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[T0]])125 126// Make sure it's not immediately released before starting the iteration.127// CHECK-LP64-NEXT: load ptr, ptr @OBJC_SELECTOR_REFERENCES_128// CHECK-LP64-NEXT: @objc_msgSend129 130// CHECK-LP64: @objc_enumerationMutation131 132// CHECK-LP64: load ptr, ptr @OBJC_SELECTOR_REFERENCES_133// CHECK-LP64-NEXT: @objc_msgSend134 135// CHECK-LP64: call void @llvm.objc.release(ptr [[T2]])136 137 138// Check that the 'continue' label is positioned appropriately139// relative to the collection clenaup.140void test3(NSArray *array) {141 for (id x in array) {142 if (!x) continue;143 use(x);144 }145 146 // CHECK-LP64-LABEL: define{{.*}} void @test3(147 // CHECK-LP64: [[ARRAY:%.*]] = alloca ptr, align 8148 // CHECK-LP64-NEXT: [[X:%.*]] = alloca ptr, align 8149 // CHECK-LP64: [[T0:%.*]] = load ptr, ptr [[X]], align 8150 // CHECK-LP64-NEXT: [[T1:%.*]] = icmp ne ptr [[T0]], null151 // CHECK-LP64-NEXT: br i1 [[T1]],152 // CHECK-LP64: br label [[L:%[^ ]+]]153 // CHECK-LP64: [[T0:%.*]] = load ptr, ptr [[X]], align 8154 // CHECK-LP64-NEXT: call void @use(ptr [[T0]])155 // CHECK-LP64-NEXT: br label [[L]]156}157 158@interface NSObject @end159 160@interface I1 : NSObject161- (NSArray *) foo1:(void (^)(void))block;162- (void) foo2;163@end164 165NSArray *array4;166 167@implementation I1 : NSObject168- (NSArray *) foo1:(void (^)(void))block {169 block();170 return array4;171}172 173- (void) foo2 {174 for (id x in [self foo1:^{ use(self); }]) {175 use(x);176 break;177 }178}179@end180 181// CHECK-LP64-LABEL: define internal void @"\01-[I1 foo2]"(182// CHECK-LP64: [[SELF_ADDR:%.*]] = alloca ptr,183// CHECK-LP64: [[BLOCK:%.*]] = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>,184// CHECK-LP64: store ptr %self, ptr [[SELF_ADDR]]185// CHECK-LP64: [[BC:%.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr [[BLOCK]], i32 0, i32 5186// CHECK-LP64: [[T1:%.*]] = load ptr, ptr [[SELF_ADDR]]187// CHECK-LP64: call ptr @llvm.objc.retain(ptr [[T1]])188 189// CHECK-LP64-OPT-LABEL: define internal void @"\01-[I1 foo2]"(190// CHECK-LP64-OPT: ptr %self191// CHECK-LP64-OPT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],192// CHECK-LP64-OPT: [[T0:%.*]] = getelementptr inbounds nuw i8, ptr [[BLOCK]], i64 32193 194// CHECK-LP64: call void @llvm.objc.storeStrong(ptr [[BC]], ptr null)195// CHECK-LP64-NOT: call void (...) @llvm.objc.clang.arc.use(ptr [[BC]])196// CHECK-LP64: switch i32 {{%.*}}, label %[[UNREACHABLE:.*]] [197// CHECK-LP64-NEXT: i32 0, label %[[CLEANUP_CONT:.*]]198// CHECK-LP64-NEXT: i32 2, label %[[FORCOLL_END:.*]]199// CHECK-LP64-NEXT: ]200 201// CHECK-LP64-OPT: [[T5:%.*]] = load ptr, ptr [[T0]]202// CHECK-LP64-OPT: call void (...) @llvm.objc.clang.arc.use(ptr [[T5]])203 204// CHECK-LP64: {{^|:}}[[CLEANUP_CONT]]205// CHECK-LP64-NEXT: br label %[[FORCOLL_END]]206 207// CHECK-LP64: {{^|:}}[[FORCOLL_END]]208// CHECK-LP64-NEXT: ret void209 210// CHECK-LP64: {{^|:}}[[UNREACHABLE]]211// CHECK-LP64-NEXT: unreachable212 213// CHECK-LP64: attributes [[NUW]] = { nounwind }214