Clang Project

clang_source_code/test/CodeGenCXX/trivial-auto-var-init.cpp
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
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(
25// ZERO: store i32 0, i32* %block
26// PATTERN-LABEL: test_block(
27// PATTERN: store i32 -1431655766, i32* %block
28void 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(
48using Block = void (^)();
49typedef struct XYZ {
50  Block block;
51} * xyz_t;
52void 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(
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);
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
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
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
196void 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
216void 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,
228void 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,
248void 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,
258void 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