xref: /minix3/external/bsd/llvm/dist/clang/test/CodeGenObjC/arc-foreach.m (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1f4a2713aSLionel Sambuc// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -emit-llvm %s -o %t-64.s
2f4a2713aSLionel Sambuc// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
3f4a2713aSLionel Sambuc// rdar://9503326
4f4a2713aSLionel Sambuc// rdar://9606600
5f4a2713aSLionel Sambuc
6f4a2713aSLionel Sambucextern void use(id);
7f4a2713aSLionel Sambucextern void use_block(void (^)(void));
8f4a2713aSLionel Sambuc
9f4a2713aSLionel Sambucstruct NSFastEnumerationState;
10f4a2713aSLionel Sambuc@interface NSArray
11f4a2713aSLionel Sambuc- (unsigned long) countByEnumeratingWithState: (struct NSFastEnumerationState*) state
12f4a2713aSLionel Sambuc                  objects: (id*) buffer
13f4a2713aSLionel Sambuc                  count: (unsigned long) bufferSize;
14f4a2713aSLionel Sambuc@end;
15f4a2713aSLionel Sambuc
16f4a2713aSLionel Sambucvoid test0(NSArray *array) {
17f4a2713aSLionel Sambuc  // 'x' should be initialized without a retain.
18f4a2713aSLionel Sambuc  // We should actually do a non-constant capture, and that
19f4a2713aSLionel Sambuc  // capture should require a retain.
20f4a2713aSLionel Sambuc  for (id x in array) {
21f4a2713aSLionel Sambuc    use_block(^{ use(x); });
22f4a2713aSLionel Sambuc  }
23f4a2713aSLionel Sambuc}
24f4a2713aSLionel Sambuc
25f4a2713aSLionel Sambuc// CHECK-LP64-LABEL:    define void @test0(
26f4a2713aSLionel Sambuc// CHECK-LP64:      [[ARRAY:%.*]] = alloca [[ARRAY_T:%.*]]*,
27f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[X:%.*]] = alloca i8*,
28f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[STATE:%.*]] = alloca [[STATE_T:%.*]],
29f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[BUFFER:%.*]] = alloca [16 x i8*], align 8
30f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
31f4a2713aSLionel Sambuc
32f4a2713aSLionel Sambuc// Initialize 'array'.
33f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: store [[ARRAY_T]]* null, [[ARRAY_T]]** [[ARRAY]]
34f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[ZERO:%.*]] = bitcast [[ARRAY_T]]** [[ARRAY]] to i8**
35f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[ONE:%.*]] = bitcast [[ARRAY_T]]* {{%.*}} to i8*
36f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: call void @objc_storeStrong(i8** [[ZERO]], i8* [[ONE]]) [[NUW:#[0-9]+]]
37f4a2713aSLionel Sambuc
38f4a2713aSLionel Sambuc// Initialize the fast enumaration state.
39f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T0:%.*]] = bitcast [[STATE_T]]* [[STATE]] to i8*
40f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 64, i32 8, i1 false)
41f4a2713aSLionel Sambuc
42f4a2713aSLionel Sambuc// Evaluate the collection expression and retain.
43f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T0:%.*]] = load [[ARRAY_T]]** [[ARRAY]], align 8
44f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[ARRAY_T]]* [[T0]] to i8*
45f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
46f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[SAVED_ARRAY:%.*]] = bitcast i8* [[T2]] to [[ARRAY_T]]*
47f4a2713aSLionel Sambuc
48f4a2713aSLionel Sambuc// Call the enumeration method.
49*0a6a1f1dSLionel Sambuc// CHECK-LP64-NEXT: [[T0:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
50f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[ARRAY_T]]* [[SAVED_ARRAY]] to i8*
51f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[SIZE:%.*]] = call i64 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i64 (i8*, i8*, [[STATE_T]]*, [16 x i8*]*, i64)*)(i8* [[T1]], i8* [[T0]], [[STATE_T]]* [[STATE]], [16 x i8*]* [[BUFFER]], i64 16)
52f4a2713aSLionel Sambuc
53f4a2713aSLionel Sambuc// Check for a nonzero result.
54f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T0:%.*]] = icmp eq i64 [[SIZE]], 0
55f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: br i1 [[T0]]
56f4a2713aSLionel Sambuc
57f4a2713aSLionel Sambuc// CHECK-LP64:      [[T0:%.*]] = getelementptr inbounds [[STATE_T]]* [[STATE]], i32 0, i32 1
58f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T1:%.*]] = load i8*** [[T0]]
59f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T2:%.*]] = getelementptr i8** [[T1]], i64
60f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T3:%.*]] = load i8** [[T2]]
61f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: store i8* [[T3]], i8** [[X]]
62f4a2713aSLionel Sambuc
63f4a2713aSLionel Sambuc// CHECK-LP64:      [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
64f4a2713aSLionel Sambuc// CHECK-LP64:      [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
65f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T1:%.*]] = load i8** [[X]]
66f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
67f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: store i8* [[T2]], i8** [[T0]]
68f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]]
69f4a2713aSLionel Sambuc// CHECK-LP64: call void @use_block(
70f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: call void @objc_storeStrong(i8** [[D0]], i8* null)
71f4a2713aSLionel Sambuc
72*0a6a1f1dSLionel Sambuc// CHECK-LP64:      [[T0:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
73f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[ARRAY_T]]* [[SAVED_ARRAY]] to i8*
74f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[SIZE:%.*]] = call i64 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i64 (i8*, i8*, [[STATE_T]]*, [16 x i8*]*, i64)*)(i8* [[T1]], i8* [[T0]], [[STATE_T]]* [[STATE]], [16 x i8*]* [[BUFFER]], i64 16)
75f4a2713aSLionel Sambuc
76f4a2713aSLionel Sambuc// Release the array.
77f4a2713aSLionel Sambuc// CHECK-LP64:      [[T0:%.*]] = bitcast [[ARRAY_T]]* [[SAVED_ARRAY]] to i8*
78f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: call void @objc_release(i8* [[T0]])
79f4a2713aSLionel Sambuc
80f4a2713aSLionel Sambuc// Destroy 'array'.
81f4a2713aSLionel Sambuc// CHECK-LP64:      [[T0:%.*]] = bitcast [[ARRAY_T]]** [[ARRAY]] to i8**
82f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: call void @objc_storeStrong(i8** [[T0]], i8* null)
83f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: ret void
84f4a2713aSLionel Sambuc
85f4a2713aSLionel Sambuc// CHECK-LP64-LABEL:    define internal void @__test0_block_invoke
86f4a2713aSLionel Sambuc// CHECK-LP64:      [[BLOCK:%.*]] = bitcast i8* {{%.*}} to [[BLOCK_T]]*
87f4a2713aSLionel Sambuc// CHECK-LP64-NOT:  ret
88f4a2713aSLionel Sambuc// CHECK-LP64:      [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
89f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T2:%.*]] = load i8** [[T0]], align 8
90f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: call void @use(i8* [[T2]])
91f4a2713aSLionel Sambuc
92f4a2713aSLionel Sambucvoid test1(NSArray *array) {
93f4a2713aSLionel Sambuc  for (__weak id x in array) {
94f4a2713aSLionel Sambuc    use_block(^{ use(x); });
95f4a2713aSLionel Sambuc  }
96f4a2713aSLionel Sambuc}
97f4a2713aSLionel Sambuc
98f4a2713aSLionel Sambuc// CHECK-LP64-LABEL:    define void @test1(
99f4a2713aSLionel Sambuc// CHECK-LP64:      alloca [[ARRAY_T:%.*]]*,
100f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[X:%.*]] = alloca i8*,
101f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[STATE:%.*]] = alloca [[STATE_T:%.*]],
102f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: alloca [16 x i8*], align 8
103f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
104f4a2713aSLionel Sambuc
105f4a2713aSLionel Sambuc// CHECK-LP64:      [[T0:%.*]] = getelementptr inbounds [[STATE_T]]* [[STATE]], i32 0, i32 1
106f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T1:%.*]] = load i8*** [[T0]]
107f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T2:%.*]] = getelementptr i8** [[T1]], i64
108f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T3:%.*]] = load i8** [[T2]]
109f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: call i8* @objc_initWeak(i8** [[X]], i8* [[T3]])
110f4a2713aSLionel Sambuc
111f4a2713aSLionel Sambuc// CHECK-LP64:      [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
112f4a2713aSLionel Sambuc// CHECK-LP64:      [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
113f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T1:%.*]] = call i8* @objc_loadWeakRetained(i8** [[X]])
114f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: call i8* @objc_initWeak(i8** [[T0]], i8* [[T1]])
115f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: call void @objc_release(i8* [[T1]])
116f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to
117f4a2713aSLionel Sambuc// CHECK-LP64: call void @use_block
118f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: call void @objc_destroyWeak(i8** [[D0]])
119f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: call void @objc_destroyWeak(i8** [[X]])
120f4a2713aSLionel Sambuc
121f4a2713aSLionel Sambuc// rdar://problem/9817306
122f4a2713aSLionel Sambuc@interface Test2
123f4a2713aSLionel Sambuc- (NSArray *) array;
124f4a2713aSLionel Sambuc@end
125f4a2713aSLionel Sambucvoid test2(Test2 *a) {
126f4a2713aSLionel Sambuc  for (id x in a.array) {
127f4a2713aSLionel Sambuc    use(x);
128f4a2713aSLionel Sambuc  }
129f4a2713aSLionel Sambuc}
130f4a2713aSLionel Sambuc
131f4a2713aSLionel Sambuc// CHECK-LP64-LABEL:    define void @test2(
132f4a2713aSLionel Sambuc// CHECK-LP64:      [[T0:%.*]] = call [[ARRAY_T]]* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to [[ARRAY_T]]* (i8*, i8*)*)(
133f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[ARRAY_T]]* [[T0]] to i8*
134f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
135f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[COLL:%.*]] = bitcast i8* [[T2]] to [[ARRAY_T]]*
136f4a2713aSLionel Sambuc
137f4a2713aSLionel Sambuc// Make sure it's not immediately released before starting the iteration.
138*0a6a1f1dSLionel Sambuc// CHECK-LP64-NEXT: load i8** @OBJC_SELECTOR_REFERENCES_
139f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: [[T0:%.*]] = bitcast [[ARRAY_T]]* [[COLL]] to i8*
140f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: @objc_msgSend
141f4a2713aSLionel Sambuc
142f4a2713aSLionel Sambuc// This bitcast is for the mutation check.
143f4a2713aSLionel Sambuc// CHECK-LP64:      [[T0:%.*]] = bitcast [[ARRAY_T]]* [[COLL]] to i8*
144f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: @objc_enumerationMutation
145f4a2713aSLionel Sambuc
146f4a2713aSLionel Sambuc// This bitcast is for the 'next' message send.
147f4a2713aSLionel Sambuc// CHECK-LP64:      [[T0:%.*]] = bitcast [[ARRAY_T]]* [[COLL]] to i8*
148f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: @objc_msgSend
149f4a2713aSLionel Sambuc
150f4a2713aSLionel Sambuc// This bitcast is for the final release.
151f4a2713aSLionel Sambuc// CHECK-LP64:      [[T0:%.*]] = bitcast [[ARRAY_T]]* [[COLL]] to i8*
152f4a2713aSLionel Sambuc// CHECK-LP64-NEXT: call void @objc_release(i8* [[T0]])
153f4a2713aSLionel Sambuc
154f4a2713aSLionel Sambuc
155f4a2713aSLionel Sambuc// Check that the 'continue' label is positioned appropriately
156f4a2713aSLionel Sambuc// relative to the collection clenaup.
157f4a2713aSLionel Sambucvoid test3(NSArray *array) {
158f4a2713aSLionel Sambuc  for (id x in array) {
159f4a2713aSLionel Sambuc    if (!x) continue;
160f4a2713aSLionel Sambuc    use(x);
161f4a2713aSLionel Sambuc  }
162f4a2713aSLionel Sambuc
163f4a2713aSLionel Sambuc  // CHECK-LP64-LABEL:    define void @test3(
164f4a2713aSLionel Sambuc  // CHECK-LP64:      [[ARRAY:%.*]] = alloca [[ARRAY_T]]*, align 8
165f4a2713aSLionel Sambuc  // CHECK-LP64-NEXT: [[X:%.*]] = alloca i8*, align 8
166f4a2713aSLionel Sambuc  // CHECK-LP64:      [[T0:%.*]] = load i8** [[X]], align 8
167f4a2713aSLionel Sambuc  // CHECK-LP64-NEXT: [[T1:%.*]] = icmp ne i8* [[T0]], null
168f4a2713aSLionel Sambuc  // CHECK-LP64-NEXT: br i1 [[T1]],
169f4a2713aSLionel Sambuc  // CHECK-LP64:      br label [[L:%[^ ]+]]
170f4a2713aSLionel Sambuc  // CHECK-LP64:      [[T0:%.*]] = load i8** [[X]], align 8
171f4a2713aSLionel Sambuc  // CHECK-LP64-NEXT: call void @use(i8* [[T0]])
172f4a2713aSLionel Sambuc  // CHECK-LP64-NEXT: br label [[L]]
173f4a2713aSLionel Sambuc}
174f4a2713aSLionel Sambuc
175*0a6a1f1dSLionel Sambuc// CHECK-LP64: attributes [[NUW]] = { nounwind }
176