[InstCombine] Preserve NSW flags for `lshr (mul nuw X, C1), C2 -> mul nuw nsw X,...
[llvm-project.git] / clang / test / CodeGenCXX / trivial-auto-var-init.cpp
blobeed9868cad07f8496ab70c0ad2b0c7fdc45cdb49
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
5 // None of the synthesized globals should contain `undef`.
6 // PATTERN-NOT: undef
7 // ZERO-NOT: undef
9 template<typename T> void used(T &) noexcept;
11 extern "C" {
13 // UNINIT-LABEL: test_selfinit(
14 // ZERO-LABEL: test_selfinit(
15 // ZERO: store i32 0, ptr %self, align 4, !annotation [[AUTO_INIT:!.+]]
16 // PATTERN-LABEL: test_selfinit(
17 // PATTERN: store i32 -1431655766, ptr %self, align 4, !annotation [[AUTO_INIT:!.+]]
18 void test_selfinit() {
19 int self = self + 1;
20 used(self);
23 // UNINIT-LABEL: test_block(
24 // ZERO-LABEL: test_block(
25 // ZERO: store i32 0, ptr %block, align 4, !annotation [[AUTO_INIT:!.+]]
26 // PATTERN-LABEL: test_block(
27 // PATTERN: store i32 -1431655766, ptr %block, align 4, !annotation [[AUTO_INIT:!.+]]
28 void test_block() {
29 __block int block;
30 used(block);
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.
37 // UNINIT-LABEL: test_block_self_init(
38 // ZERO-LABEL: test_block_self_init(
39 // ZERO: %block = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8
40 // ZERO: %captured1 = getelementptr inbounds %struct.__block_byref_captured, ptr %captured, i32 0, i32 4
41 // ZERO-NEXT: store ptr null, ptr %captured1, align 8, !annotation [[AUTO_INIT:!.+]]
42 // ZERO: %call = call ptr @create(
43 // PATTERN-LABEL: test_block_self_init(
44 // PATTERN: %block = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8
45 // PATTERN: %captured1 = getelementptr inbounds %struct.__block_byref_captured, ptr %captured, i32 0, i32 4
46 // PATTERN-NEXT: store ptr inttoptr (i64 -6148914691236517206 to ptr), ptr %captured1, align 8, !annotation [[AUTO_INIT:!.+]]
47 // PATTERN: %call = call ptr @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 });
59 // Capturing with escape after initialization is also an edge case.
61 // UNINIT-LABEL: test_block_captures_self_after_init(
62 // ZERO-LABEL: test_block_captures_self_after_init(
63 // ZERO: %block = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8
64 // ZERO: %captured1 = getelementptr inbounds %struct.__block_byref_captured.1, ptr %captured, i32 0, i32 4
65 // ZERO-NEXT: store ptr null, ptr %captured1, align 8, !annotation [[AUTO_INIT:!.+]]
66 // ZERO: %call = call ptr @create(
67 // PATTERN-LABEL: test_block_captures_self_after_init(
68 // PATTERN: %block = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8
69 // PATTERN: %captured1 = getelementptr inbounds %struct.__block_byref_captured.1, ptr %captured, i32 0, i32 4
70 // PATTERN-NEXT: store ptr inttoptr (i64 -6148914691236517206 to ptr), ptr %captured1, align 8, !annotation [[AUTO_INIT:!.+]]
71 // PATTERN: %call = call ptr @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 });
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);
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, ptr %oops, align 4, !annotation [[AUTO_INIT:!.+]]
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, ptr %oops, align 4, !annotation [[AUTO_INIT:!.+]]
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);
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, ptr %oops, align 4, !annotation [[AUTO_INIT:!.+]]
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, ptr %oops, align 4, !annotation [[AUTO_INIT:!.+]]
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);
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{{.*}}(ptr align 16 %{{.*}}, i8 0, i64 %[[SIZE]], i1 false), !annotation [[AUTO_INIT:!.+]]
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.end = getelementptr inbounds i8, ptr %vla, i64 %[[SIZE]]
150 // PATTERN: br label %vla-init.loop
151 // PATTERN: vla-init.loop:
152 // PATTERN: %vla.cur = phi ptr [ %vla, %vla-setup.loop ], [ %vla.next, %vla-init.loop ]
153 // PATTERN: call void @llvm.memcpy{{.*}} %vla.cur, {{.*}}@__const.test_vla.vla{{.*}}), !annotation [[AUTO_INIT:!.+]]
154 // PATTERN: %vla.next = getelementptr inbounds i8, ptr %vla.cur, i64 4
155 // PATTERN: %vla-init.isdone = icmp eq ptr %vla.next, %vla.end
156 // PATTERN: br i1 %vla-init.isdone, label %vla-init.cont, label %vla-init.loop
157 // PATTERN: vla-init.cont:
158 // PATTERN: call void @{{.*}}used
159 void test_vla(int size) {
160 // Variable-length arrays can't have a zero size according to C11 6.7.6.2/5.
161 // Neither can they be negative-sized.
163 // We don't use the former fact because some code creates zero-sized VLAs and
164 // doesn't use them. clang makes these share locations with other stack
165 // values, which leads to initialization of the wrong values.
167 // We rely on the later fact because it generates better code.
169 // Both cases are caught by UBSan.
170 int vla[size];
171 int *ptr = vla;
172 used(ptr);
175 // UNINIT-LABEL: test_alloca(
176 // ZERO-LABEL: test_alloca(
177 // ZERO: %[[SIZE:[a-z0-9]+]] = sext i32 %{{.*}} to i64
178 // ZERO-NEXT: %[[ALLOCA:[a-z0-9]+]] = alloca i8, i64 %[[SIZE]], align [[ALIGN:[0-9]+]]
179 // ZERO-NEXT: call void @llvm.memset{{.*}}(ptr align [[ALIGN]] %[[ALLOCA]], i8 0, i64 %[[SIZE]], i1 false), !annotation [[AUTO_INIT:!.+]]
180 // PATTERN-LABEL: test_alloca(
181 // PATTERN: %[[SIZE:[a-z0-9]+]] = sext i32 %{{.*}} to i64
182 // PATTERN-NEXT: %[[ALLOCA:[a-z0-9]+]] = alloca i8, i64 %[[SIZE]], align [[ALIGN:[0-9]+]]
183 // PATTERN-NEXT: call void @llvm.memset{{.*}}(ptr align [[ALIGN]] %[[ALLOCA]], i8 -86, i64 %[[SIZE]], i1 false), !annotation [[AUTO_INIT:!.+]]
184 void test_alloca(int size) {
185 void *ptr = __builtin_alloca(size);
186 used(ptr);
189 // UNINIT-LABEL: test_alloca_with_align(
190 // ZERO-LABEL: test_alloca_with_align(
191 // ZERO: %[[SIZE:[a-z0-9]+]] = sext i32 %{{.*}} to i64
192 // ZERO-NEXT: %[[ALLOCA:[a-z0-9]+]] = alloca i8, i64 %[[SIZE]], align 128
193 // ZERO-NEXT: call void @llvm.memset{{.*}}(ptr align 128 %[[ALLOCA]], i8 0, i64 %[[SIZE]], i1 false), !annotation [[AUTO_INIT:!.+]]
194 // PATTERN-LABEL: test_alloca_with_align(
195 // PATTERN: %[[SIZE:[a-z0-9]+]] = sext i32 %{{.*}} to i64
196 // PATTERN-NEXT: %[[ALLOCA:[a-z0-9]+]] = alloca i8, i64 %[[SIZE]], align 128
197 // PATTERN-NEXT: call void @llvm.memset{{.*}}(ptr align 128 %[[ALLOCA]], i8 -86, i64 %[[SIZE]], i1 false), !annotation [[AUTO_INIT:!.+]]
198 void test_alloca_with_align(int size) {
199 void *ptr = __builtin_alloca_with_align(size, 1024);
200 used(ptr);
203 // UNINIT-LABEL: test_alloca_uninitialized(
204 // ZERO-LABEL: test_alloca_uninitialized(
205 // ZERO: %[[SIZE:[a-z0-9]+]] = sext i32 %{{.*}} to i64
206 // ZERO-NEXT: %[[ALLOCA:[a-z0-9]+]] = alloca i8, i64 %[[SIZE]], align [[ALIGN:[0-9]+]]
207 // ZERO-NOT: call void @llvm.memset
208 // PATTERN-LABEL: test_alloca_uninitialized(
209 // PATTERN: %[[SIZE:[a-z0-9]+]] = sext i32 %{{.*}} to i64
210 // PATTERN-NEXT: %[[ALLOCA:[a-z0-9]+]] = alloca i8, i64 %[[SIZE]], align [[ALIGN:[0-9]+]]
211 // PATTERN-NOT: call void @llvm.memset
212 void test_alloca_uninitialized(int size) {
213 void *ptr = __builtin_alloca_uninitialized(size);
214 used(ptr);
217 // UNINIT-LABEL: test_alloca_with_align_uninitialized(
218 // ZERO-LABEL: test_alloca_with_align_uninitialized(
219 // ZERO: %[[SIZE:[a-z0-9]+]] = sext i32 %{{.*}} to i64
220 // ZERO-NEXT: %[[ALLOCA:[a-z0-9]+]] = alloca i8, i64 %[[SIZE]], align 128
221 // ZERO-NOT: call void @llvm.memset
222 // PATTERN-LABEL: test_alloca_with_align_uninitialized(
223 // PATTERN: %[[SIZE:[a-z0-9]+]] = sext i32 %{{.*}} to i64
224 // PATTERN-NEXT: %[[ALLOCA:[a-z0-9]+]] = alloca i8, i64 %[[SIZE]], align 128
225 // PATTERN-NOT: call void @llvm.memset
226 void test_alloca_with_align_uninitialized(int size) {
227 void *ptr = __builtin_alloca_with_align_uninitialized(size, 1024);
228 used(ptr);
231 // UNINIT-LABEL: test_struct_vla(
232 // ZERO-LABEL: test_struct_vla(
233 // ZERO: %[[SIZE:[0-9]+]] = mul nuw i64 %{{.*}}, 16
234 // ZERO: call void @llvm.memset{{.*}}(ptr align 16 %{{.*}}, i8 0, i64 %[[SIZE]], i1 false), !annotation [[AUTO_INIT:!.+]]
235 // PATTERN-LABEL: test_struct_vla(
236 // PATTERN: %vla.iszerosized = icmp eq i64 %{{.*}}, 0
237 // PATTERN: br i1 %vla.iszerosized, label %vla-init.cont, label %vla-setup.loop
238 // PATTERN: vla-setup.loop:
239 // PATTERN: %[[SIZE:[0-9]+]] = mul nuw i64 %{{.*}}, 16
240 // PATTERN: %vla.end = getelementptr inbounds i8, ptr %vla, i64 %[[SIZE]]
241 // PATTERN: br label %vla-init.loop
242 // PATTERN: vla-init.loop:
243 // PATTERN: %vla.cur = phi ptr [ %vla, %vla-setup.loop ], [ %vla.next, %vla-init.loop ]
244 // PATTERN: call void @llvm.memcpy{{.*}} %vla.cur, {{.*}}@__const.test_struct_vla.vla{{.*}}), !annotation [[AUTO_INIT:!.+]]
245 // PATTERN: %vla.next = getelementptr inbounds i8, ptr %vla.cur, i64 16
246 // PATTERN: %vla-init.isdone = icmp eq ptr %vla.next, %vla.end
247 // PATTERN: br i1 %vla-init.isdone, label %vla-init.cont, label %vla-init.loop
248 // PATTERN: vla-init.cont:
249 // PATTERN: call void @{{.*}}used
250 void test_struct_vla(int size) {
251 // Same as above, but with a struct that doesn't just memcpy.
252 struct {
253 float f;
254 char c;
255 void *ptr;
256 } vla[size];
257 void *ptr = static_cast<void*>(vla);
258 used(ptr);
261 // UNINIT-LABEL: test_zsa(
262 // ZERO-LABEL: test_zsa(
263 // ZERO: %zsa = alloca [0 x i32], align 4
264 // ZERO-NOT: %zsa
265 // ZERO: call void @{{.*}}used
266 // PATTERN-LABEL: test_zsa(
267 // PATTERN: %zsa = alloca [0 x i32], align 4
268 // PATTERN-NOT: %zsa
269 // PATTERN: call void @{{.*}}used
270 void test_zsa(int size) {
271 // Technically not valid, but as long as clang accepts them we should do
272 // something sensible (i.e. not store to the zero-size array).
273 int zsa[0];
274 used(zsa);
277 // UNINIT-LABEL: test_huge_uninit(
278 // ZERO-LABEL: test_huge_uninit(
279 // ZERO: call void @llvm.memset{{.*}}, i8 0, i64 65536, {{.*}}), !annotation [[AUTO_INIT:!.+]]
280 // PATTERN-LABEL: test_huge_uninit(
281 // PATTERN: call void @llvm.memset{{.*}}, i8 -86, i64 65536, {{.*}}), !annotation [[AUTO_INIT:!.+]]
282 void test_huge_uninit() {
283 // We can't emit this as an inline constant to a store instruction because
284 // SDNode hits an internal size limit.
285 char big[65536];
286 used(big);
289 // UNINIT-LABEL: test_huge_small_init(
290 // ZERO-LABEL: test_huge_small_init(
291 // ZERO: call void @llvm.memset{{.*}}, i8 0, i64 65536,
292 // ZERO-NOT: !annotation
293 // ZERO: store i8 97,
294 // ZERO: store i8 98,
295 // ZERO: store i8 99,
296 // ZERO: store i8 100,
297 // PATTERN-LABEL: test_huge_small_init(
298 // PATTERN: call void @llvm.memset{{.*}}, i8 0, i64 65536,
299 // PATTERN-NOT: !annotation
300 // PATTERN: store i8 97,
301 // PATTERN: store i8 98,
302 // PATTERN: store i8 99,
303 // PATTERN: store i8 100,
304 void test_huge_small_init() {
305 char big[65536] = { 'a', 'b', 'c', 'd' };
306 used(big);
309 // UNINIT-LABEL: test_huge_larger_init(
310 // ZERO-LABEL: test_huge_larger_init(
311 // ZERO: call void @llvm.memcpy{{.*}} @__const.test_huge_larger_init.big, i64 65536,
312 // ZERO-NOT: !annotation
313 // PATTERN-LABEL: test_huge_larger_init(
314 // PATTERN: call void @llvm.memcpy{{.*}} @__const.test_huge_larger_init.big, i64 65536,
315 // PATTERN-NOT: !annotation
316 void test_huge_larger_init() {
317 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' };
318 used(big);
321 } // extern "C"
323 // CHECK: [[AUTO_INIT]] = !{ !"auto-init" }