1 | // RUN: %clang_cc1 -triple x86_64-unknown-unknown -fblocks %s -emit-llvm -o - | FileCheck %s -check-prefix=UNINIT |
2 | // RUN: %clang_cc1 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=pattern %s -emit-llvm -o - | FileCheck %s -check-prefix=PATTERN |
3 | // RUN: %clang_cc1 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=zero %s -emit-llvm -o - | FileCheck %s -check-prefix=ZERO |
4 | |
5 | // None of the synthesized globals should contain `undef`. |
6 | // PATTERN-NOT: undef |
7 | // ZERO-NOT: undef |
8 | |
9 | template<typename T> void used(T &) noexcept; |
10 | |
11 | extern "C" { |
12 | |
13 | // UNINIT-LABEL: test_selfinit( |
14 | // ZERO-LABEL: test_selfinit( |
15 | // ZERO: store i32 0, i32* %self, align 4 |
16 | // PATTERN-LABEL: test_selfinit( |
17 | // PATTERN: store i32 -1431655766, i32* %self, align 4 |
18 | void test_selfinit() { |
19 | int self = self + 1; |
20 | used(self); |
21 | } |
22 | |
23 | // UNINIT-LABEL: test_block( |
24 | // ZERO-LABEL: test_block( |
25 | // ZERO: store i32 0, i32* %block |
26 | // PATTERN-LABEL: test_block( |
27 | // PATTERN: store i32 -1431655766, i32* %block |
28 | void test_block() { |
29 | __block int block; |
30 | used(block); |
31 | } |
32 | |
33 | // Using the variable being initialized is typically UB in C, but for blocks we |
34 | // can be nice: they imply extra book-keeping and we can do the auto-init before |
35 | // any of said book-keeping. |
36 | // |
37 | // UNINIT-LABEL: test_block_self_init( |
38 | // ZERO-LABEL: test_block_self_init( |
39 | // ZERO: %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>, align 8 |
40 | // ZERO: %captured1 = getelementptr inbounds %struct.__block_byref_captured, %struct.__block_byref_captured* %captured, i32 0, i32 4 |
41 | // ZERO-NEXT: store %struct.XYZ* null, %struct.XYZ** %captured1, align 8 |
42 | // ZERO: %call = call %struct.XYZ* @create( |
43 | // PATTERN-LABEL: test_block_self_init( |
44 | // PATTERN: %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>, align 8 |
45 | // PATTERN: %captured1 = getelementptr inbounds %struct.__block_byref_captured, %struct.__block_byref_captured* %captured, i32 0, i32 4 |
46 | // PATTERN-NEXT: store %struct.XYZ* inttoptr (i64 -6148914691236517206 to %struct.XYZ*), %struct.XYZ** %captured1, align 8 |
47 | // PATTERN: %call = call %struct.XYZ* @create( |
48 | using Block = void (^)(); |
49 | typedef struct XYZ { |
50 | Block block; |
51 | } * xyz_t; |
52 | void test_block_self_init() { |
53 | extern xyz_t create(Block block); |
54 | __block xyz_t captured = create(^() { |
55 | used(captured); |
56 | }); |
57 | } |
58 | |
59 | // Capturing with escape after initialization is also an edge case. |
60 | // |
61 | // UNINIT-LABEL: test_block_captures_self_after_init( |
62 | // ZERO-LABEL: test_block_captures_self_after_init( |
63 | // ZERO: %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>, align 8 |
64 | // ZERO: %captured1 = getelementptr inbounds %struct.__block_byref_captured.1, %struct.__block_byref_captured.1* %captured, i32 0, i32 4 |
65 | // ZERO-NEXT: store %struct.XYZ* null, %struct.XYZ** %captured1, align 8 |
66 | // ZERO: %call = call %struct.XYZ* @create( |
67 | // PATTERN-LABEL: test_block_captures_self_after_init( |
68 | // PATTERN: %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>, align 8 |
69 | // PATTERN: %captured1 = getelementptr inbounds %struct.__block_byref_captured.1, %struct.__block_byref_captured.1* %captured, i32 0, i32 4 |
70 | // PATTERN-NEXT: store %struct.XYZ* inttoptr (i64 -6148914691236517206 to %struct.XYZ*), %struct.XYZ** %captured1, align 8 |
71 | // PATTERN: %call = call %struct.XYZ* @create( |
72 | void test_block_captures_self_after_init() { |
73 | extern xyz_t create(Block block); |
74 | __block xyz_t captured; |
75 | captured = create(^() { |
76 | used(captured); |
77 | }); |
78 | } |
79 | |
80 | // This type of code is currently not handled by zero / pattern initialization. |
81 | // The test will break when that is fixed. |
82 | // UNINIT-LABEL: test_goto_unreachable_value( |
83 | // ZERO-LABEL: test_goto_unreachable_value( |
84 | // ZERO-NOT: store {{.*}}%oops |
85 | // PATTERN-LABEL: test_goto_unreachable_value( |
86 | // PATTERN-NOT: store {{.*}}%oops |
87 | void test_goto_unreachable_value() { |
88 | goto jump; |
89 | int oops; |
90 | jump: |
91 | used(oops); |
92 | } |
93 | |
94 | // This type of code is currently not handled by zero / pattern initialization. |
95 | // The test will break when that is fixed. |
96 | // UNINIT-LABEL: test_goto( |
97 | // ZERO-LABEL: test_goto( |
98 | // ZERO: if.then: |
99 | // ZERO: br label %jump |
100 | // ZERO: store i32 0, i32* %oops, align 4 |
101 | // ZERO: br label %jump |
102 | // ZERO: jump: |
103 | // PATTERN-LABEL: test_goto( |
104 | // PATTERN: if.then: |
105 | // PATTERN: br label %jump |
106 | // PATTERN: store i32 -1431655766, i32* %oops, align 4 |
107 | // PATTERN: br label %jump |
108 | // PATTERN: jump: |
109 | void test_goto(int i) { |
110 | if (i) |
111 | goto jump; |
112 | int oops; |
113 | jump: |
114 | used(oops); |
115 | } |
116 | |
117 | // This type of code is currently not handled by zero / pattern initialization. |
118 | // The test will break when that is fixed. |
119 | // UNINIT-LABEL: test_switch( |
120 | // ZERO-LABEL: test_switch( |
121 | // ZERO: sw.bb: |
122 | // ZERO-NEXT: store i32 0, i32* %oops, align 4 |
123 | // ZERO: sw.bb1: |
124 | // ZERO-NEXT: call void @{{.*}}used |
125 | // PATTERN-LABEL: test_switch( |
126 | // PATTERN: sw.bb: |
127 | // PATTERN-NEXT: store i32 -1431655766, i32* %oops, align 4 |
128 | // PATTERN: sw.bb1: |
129 | // PATTERN-NEXT: call void @{{.*}}used |
130 | void test_switch(int i) { |
131 | switch (i) { |
132 | case 0: |
133 | int oops; |
134 | break; |
135 | case 1: |
136 | used(oops); |
137 | } |
138 | } |
139 | |
140 | // UNINIT-LABEL: test_vla( |
141 | // ZERO-LABEL: test_vla( |
142 | // ZERO: %[[SIZE:[0-9]+]] = mul nuw i64 %{{.*}}, 4 |
143 | // ZERO: call void @llvm.memset{{.*}}(i8* align 16 %{{.*}}, i8 0, i64 %[[SIZE]], i1 false) |
144 | // PATTERN-LABEL: test_vla( |
145 | // PATTERN: %vla.iszerosized = icmp eq i64 %{{.*}}, 0 |
146 | // PATTERN: br i1 %vla.iszerosized, label %vla-init.cont, label %vla-setup.loop |
147 | // PATTERN: vla-setup.loop: |
148 | // PATTERN: %[[SIZE:[0-9]+]] = mul nuw i64 %{{.*}}, 4 |
149 | // PATTERN: %vla.begin = bitcast i32* %vla to i8* |
150 | // PATTERN: %vla.end = getelementptr inbounds i8, i8* %vla.begin, i64 %[[SIZE]] |
151 | // PATTERN: br label %vla-init.loop |
152 | // PATTERN: vla-init.loop: |
153 | // PATTERN: %vla.cur = phi i8* [ %vla.begin, %vla-setup.loop ], [ %vla.next, %vla-init.loop ] |
154 | // PATTERN: call void @llvm.memcpy{{.*}} %vla.cur, {{.*}}@__const.test_vla.vla |
155 | // PATTERN: %vla.next = getelementptr inbounds i8, i8* %vla.cur, i64 4 |
156 | // PATTERN: %vla-init.isdone = icmp eq i8* %vla.next, %vla.end |
157 | // PATTERN: br i1 %vla-init.isdone, label %vla-init.cont, label %vla-init.loop |
158 | // PATTERN: vla-init.cont: |
159 | // PATTERN: call void @{{.*}}used |
160 | void test_vla(int size) { |
161 | // Variable-length arrays can't have a zero size according to C11 6.7.6.2/5. |
162 | // Neither can they be negative-sized. |
163 | // |
164 | // We don't use the former fact because some code creates zero-sized VLAs and |
165 | // doesn't use them. clang makes these share locations with other stack |
166 | // values, which leads to initialization of the wrong values. |
167 | // |
168 | // We rely on the later fact because it generates better code. |
169 | // |
170 | // Both cases are caught by UBSan. |
171 | int vla[size]; |
172 | int *ptr = vla; |
173 | used(ptr); |
174 | } |
175 | |
176 | // UNINIT-LABEL: test_struct_vla( |
177 | // ZERO-LABEL: test_struct_vla( |
178 | // ZERO: %[[SIZE:[0-9]+]] = mul nuw i64 %{{.*}}, 16 |
179 | // ZERO: call void @llvm.memset{{.*}}(i8* align 16 %{{.*}}, i8 0, i64 %[[SIZE]], i1 false) |
180 | // PATTERN-LABEL: test_struct_vla( |
181 | // PATTERN: %vla.iszerosized = icmp eq i64 %{{.*}}, 0 |
182 | // PATTERN: br i1 %vla.iszerosized, label %vla-init.cont, label %vla-setup.loop |
183 | // PATTERN: vla-setup.loop: |
184 | // PATTERN: %[[SIZE:[0-9]+]] = mul nuw i64 %{{.*}}, 16 |
185 | // PATTERN: %vla.begin = bitcast %struct.anon* %vla to i8* |
186 | // PATTERN: %vla.end = getelementptr inbounds i8, i8* %vla.begin, i64 %[[SIZE]] |
187 | // PATTERN: br label %vla-init.loop |
188 | // PATTERN: vla-init.loop: |
189 | // PATTERN: %vla.cur = phi i8* [ %vla.begin, %vla-setup.loop ], [ %vla.next, %vla-init.loop ] |
190 | // PATTERN: call void @llvm.memcpy{{.*}} %vla.cur, {{.*}}@__const.test_struct_vla.vla |
191 | // PATTERN: %vla.next = getelementptr inbounds i8, i8* %vla.cur, i64 16 |
192 | // PATTERN: %vla-init.isdone = icmp eq i8* %vla.next, %vla.end |
193 | // PATTERN: br i1 %vla-init.isdone, label %vla-init.cont, label %vla-init.loop |
194 | // PATTERN: vla-init.cont: |
195 | // PATTERN: call void @{{.*}}used |
196 | void test_struct_vla(int size) { |
197 | // Same as above, but with a struct that doesn't just memcpy. |
198 | struct { |
199 | float f; |
200 | char c; |
201 | void *ptr; |
202 | } vla[size]; |
203 | void *ptr = static_cast<void*>(vla); |
204 | used(ptr); |
205 | } |
206 | |
207 | // UNINIT-LABEL: test_zsa( |
208 | // ZERO-LABEL: test_zsa( |
209 | // ZERO: %zsa = alloca [0 x i32], align 4 |
210 | // ZERO-NOT: %zsa |
211 | // ZERO: call void @{{.*}}used |
212 | // PATTERN-LABEL: test_zsa( |
213 | // PATTERN: %zsa = alloca [0 x i32], align 4 |
214 | // PATTERN-NOT: %zsa |
215 | // PATTERN: call void @{{.*}}used |
216 | void test_zsa(int size) { |
217 | // Technically not valid, but as long as clang accepts them we should do |
218 | // something sensible (i.e. not store to the zero-size array). |
219 | int zsa[0]; |
220 | used(zsa); |
221 | } |
222 | |
223 | // UNINIT-LABEL: test_huge_uninit( |
224 | // ZERO-LABEL: test_huge_uninit( |
225 | // ZERO: call void @llvm.memset{{.*}}, i8 0, i64 65536, |
226 | // PATTERN-LABEL: test_huge_uninit( |
227 | // PATTERN: call void @llvm.memset{{.*}}, i8 -86, i64 65536, |
228 | void test_huge_uninit() { |
229 | // We can't emit this as an inline constant to a store instruction because |
230 | // SDNode hits an internal size limit. |
231 | char big[65536]; |
232 | used(big); |
233 | } |
234 | |
235 | // UNINIT-LABEL: test_huge_small_init( |
236 | // ZERO-LABEL: test_huge_small_init( |
237 | // ZERO: call void @llvm.memset{{.*}}, i8 0, i64 65536, |
238 | // ZERO: store i8 97, |
239 | // ZERO: store i8 98, |
240 | // ZERO: store i8 99, |
241 | // ZERO: store i8 100, |
242 | // PATTERN-LABEL: test_huge_small_init( |
243 | // PATTERN: call void @llvm.memset{{.*}}, i8 0, i64 65536, |
244 | // PATTERN: store i8 97, |
245 | // PATTERN: store i8 98, |
246 | // PATTERN: store i8 99, |
247 | // PATTERN: store i8 100, |
248 | void test_huge_small_init() { |
249 | char big[65536] = { 'a', 'b', 'c', 'd' }; |
250 | used(big); |
251 | } |
252 | |
253 | // UNINIT-LABEL: test_huge_larger_init( |
254 | // ZERO-LABEL: test_huge_larger_init( |
255 | // ZERO: call void @llvm.memcpy{{.*}} @__const.test_huge_larger_init.big, {{.*}}, i64 65536, |
256 | // PATTERN-LABEL: test_huge_larger_init( |
257 | // PATTERN: call void @llvm.memcpy{{.*}} @__const.test_huge_larger_init.big, {{.*}}, i64 65536, |
258 | void test_huge_larger_init() { |
259 | char big[65536] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; |
260 | used(big); |
261 | } |
262 | |
263 | } // extern "C" |
264 | |