blob: 2cc63a47dd195c991bf940335017ee84d505e9ce [file] [log] [blame]
JF Bastien14daa202018-12-18 05:12:21 +00001// 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
9template<typename T> void used(T &) noexcept;
10
11extern "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
18void test_selfinit() {
19 int self = self + 1;
20 used(self);
21}
22
23// UNINIT-LABEL: test_block(
24// ZERO-LABEL: test_block(
JF Bastienab4820f2019-01-08 18:51:38 +000025// ZERO: store i32 0, i32* %block
JF Bastien14daa202018-12-18 05:12:21 +000026// PATTERN-LABEL: test_block(
JF Bastienab4820f2019-01-08 18:51:38 +000027// PATTERN: store i32 -1431655766, i32* %block
JF Bastien14daa202018-12-18 05:12:21 +000028void test_block() {
29 __block int block;
30 used(block);
31}
32
JF Bastienb347e752019-02-08 01:29:17 +000033// 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(
JF Bastien0bae08a2019-02-15 17:26:29 +000048using Block = void (^)();
49typedef struct XYZ {
50 Block block;
51} * xyz_t;
JF Bastienb347e752019-02-08 01:29:17 +000052void test_block_self_init() {
JF Bastienb347e752019-02-08 01:29:17 +000053 extern xyz_t create(Block block);
54 __block xyz_t captured = create(^() {
JF Bastien0bae08a2019-02-15 17:26:29 +000055 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(
72void test_block_captures_self_after_init() {
73 extern xyz_t create(Block block);
74 __block xyz_t captured;
75 captured = create(^() {
76 used(captured);
JF Bastienb347e752019-02-08 01:29:17 +000077 });
78}
79
JF Bastien14daa202018-12-18 05:12:21 +000080// 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
87void 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:
109void 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
130void 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
160void 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
JF Bastienef202c32019-04-12 00:11:27 +0000176// UNINIT-LABEL: test_alloca(
177// ZERO-LABEL: test_alloca(
178// ZERO: %[[SIZE:[a-z0-9]+]] = sext i32 %{{.*}} to i64
179// ZERO-NEXT: %[[ALLOCA:[a-z0-9]+]] = alloca i8, i64 %[[SIZE]], align [[ALIGN:[0-9]+]]
180// ZERO-NEXT: call void @llvm.memset{{.*}}(i8* align [[ALIGN]] %[[ALLOCA]], i8 0, i64 %[[SIZE]], i1 false)
181// PATTERN-LABEL: test_alloca(
182// PATTERN: %[[SIZE:[a-z0-9]+]] = sext i32 %{{.*}} to i64
183// PATTERN-NEXT: %[[ALLOCA:[a-z0-9]+]] = alloca i8, i64 %[[SIZE]], align [[ALIGN:[0-9]+]]
184// PATTERN-NEXT: call void @llvm.memset{{.*}}(i8* align [[ALIGN]] %[[ALLOCA]], i8 -86, i64 %[[SIZE]], i1 false)
185void test_alloca(int size) {
186 void *ptr = __builtin_alloca(size);
187 used(ptr);
188}
189
190// UNINIT-LABEL: test_alloca_with_align(
191// ZERO-LABEL: test_alloca_with_align(
192// ZERO: %[[SIZE:[a-z0-9]+]] = sext i32 %{{.*}} to i64
193// ZERO-NEXT: %[[ALLOCA:[a-z0-9]+]] = alloca i8, i64 %[[SIZE]], align 128
194// ZERO-NEXT: call void @llvm.memset{{.*}}(i8* align 128 %[[ALLOCA]], i8 0, i64 %[[SIZE]], i1 false)
195// PATTERN-LABEL: test_alloca_with_align(
196// PATTERN: %[[SIZE:[a-z0-9]+]] = sext i32 %{{.*}} to i64
197// PATTERN-NEXT: %[[ALLOCA:[a-z0-9]+]] = alloca i8, i64 %[[SIZE]], align 128
198// PATTERN-NEXT: call void @llvm.memset{{.*}}(i8* align 128 %[[ALLOCA]], i8 -86, i64 %[[SIZE]], i1 false)
199void test_alloca_with_align(int size) {
200 void *ptr = __builtin_alloca_with_align(size, 1024);
201 used(ptr);
202}
203
JF Bastien14daa202018-12-18 05:12:21 +0000204// UNINIT-LABEL: test_struct_vla(
205// ZERO-LABEL: test_struct_vla(
206// ZERO: %[[SIZE:[0-9]+]] = mul nuw i64 %{{.*}}, 16
207// ZERO: call void @llvm.memset{{.*}}(i8* align 16 %{{.*}}, i8 0, i64 %[[SIZE]], i1 false)
208// PATTERN-LABEL: test_struct_vla(
209// PATTERN: %vla.iszerosized = icmp eq i64 %{{.*}}, 0
210// PATTERN: br i1 %vla.iszerosized, label %vla-init.cont, label %vla-setup.loop
211// PATTERN: vla-setup.loop:
212// PATTERN: %[[SIZE:[0-9]+]] = mul nuw i64 %{{.*}}, 16
213// PATTERN: %vla.begin = bitcast %struct.anon* %vla to i8*
214// PATTERN: %vla.end = getelementptr inbounds i8, i8* %vla.begin, i64 %[[SIZE]]
215// PATTERN: br label %vla-init.loop
216// PATTERN: vla-init.loop:
217// PATTERN: %vla.cur = phi i8* [ %vla.begin, %vla-setup.loop ], [ %vla.next, %vla-init.loop ]
218// PATTERN: call void @llvm.memcpy{{.*}} %vla.cur, {{.*}}@__const.test_struct_vla.vla
219// PATTERN: %vla.next = getelementptr inbounds i8, i8* %vla.cur, i64 16
220// PATTERN: %vla-init.isdone = icmp eq i8* %vla.next, %vla.end
221// PATTERN: br i1 %vla-init.isdone, label %vla-init.cont, label %vla-init.loop
222// PATTERN: vla-init.cont:
223// PATTERN: call void @{{.*}}used
224void test_struct_vla(int size) {
225 // Same as above, but with a struct that doesn't just memcpy.
226 struct {
227 float f;
228 char c;
229 void *ptr;
230 } vla[size];
231 void *ptr = static_cast<void*>(vla);
232 used(ptr);
233}
234
235// UNINIT-LABEL: test_zsa(
236// ZERO-LABEL: test_zsa(
237// ZERO: %zsa = alloca [0 x i32], align 4
238// ZERO-NOT: %zsa
239// ZERO: call void @{{.*}}used
240// PATTERN-LABEL: test_zsa(
241// PATTERN: %zsa = alloca [0 x i32], align 4
242// PATTERN-NOT: %zsa
243// PATTERN: call void @{{.*}}used
244void test_zsa(int size) {
245 // Technically not valid, but as long as clang accepts them we should do
246 // something sensible (i.e. not store to the zero-size array).
247 int zsa[0];
248 used(zsa);
249}
250
251// UNINIT-LABEL: test_huge_uninit(
252// ZERO-LABEL: test_huge_uninit(
253// ZERO: call void @llvm.memset{{.*}}, i8 0, i64 65536,
254// PATTERN-LABEL: test_huge_uninit(
255// PATTERN: call void @llvm.memset{{.*}}, i8 -86, i64 65536,
256void test_huge_uninit() {
257 // We can't emit this as an inline constant to a store instruction because
258 // SDNode hits an internal size limit.
259 char big[65536];
260 used(big);
261}
262
263// UNINIT-LABEL: test_huge_small_init(
264// ZERO-LABEL: test_huge_small_init(
265// ZERO: call void @llvm.memset{{.*}}, i8 0, i64 65536,
266// ZERO: store i8 97,
267// ZERO: store i8 98,
268// ZERO: store i8 99,
269// ZERO: store i8 100,
270// PATTERN-LABEL: test_huge_small_init(
271// PATTERN: call void @llvm.memset{{.*}}, i8 0, i64 65536,
272// PATTERN: store i8 97,
273// PATTERN: store i8 98,
274// PATTERN: store i8 99,
275// PATTERN: store i8 100,
276void test_huge_small_init() {
277 char big[65536] = { 'a', 'b', 'c', 'd' };
278 used(big);
279}
280
281// UNINIT-LABEL: test_huge_larger_init(
282// ZERO-LABEL: test_huge_larger_init(
283// ZERO: call void @llvm.memcpy{{.*}} @__const.test_huge_larger_init.big, {{.*}}, i64 65536,
284// PATTERN-LABEL: test_huge_larger_init(
285// PATTERN: call void @llvm.memcpy{{.*}} @__const.test_huge_larger_init.big, {{.*}}, i64 65536,
286void test_huge_larger_init() {
287 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' };
288 used(big);
289}
290
291} // extern "C"