blob: 1ed71ef8375e7f37ed6116dd5b75411f3b179e29 [file] [log] [blame]
Joseph Tremouletec182852015-08-28 01:12:35 +00001; RUN: opt -mtriple=x86_x64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s
2
3declare i32 @__CxxFrameHandler3(...)
4
5declare void @f()
6declare i32 @g()
7declare void @h(i32)
8declare i1 @b()
9
10
11define void @test1() personality i32 (...)* @__CxxFrameHandler3 {
12entry:
13 ; %x def colors: {entry} subset of use colors; must spill
14 %x = call i32 @g()
15 invoke void @f()
16 to label %noreturn unwind label %catch
17catch:
18 catchpad []
19 to label %noreturn unwind label %endcatch
20noreturn:
21 ; %x use colors: {entry, cleanup}
22 call void @h(i32 %x)
23 unreachable
24endcatch:
25 catchendpad unwind to caller
26}
27; Need two copies of the call to @h, one under entry and one under catch.
28; Currently we generate a load for each, though we shouldn't need one
29; for the use in entry's copy.
Joseph Tremouletf3aff312015-09-10 16:51:25 +000030; CHECK-LABEL: define void @test1(
Joseph Tremouletec182852015-08-28 01:12:35 +000031; CHECK: entry:
32; CHECK: store i32 %x, i32* [[Slot:%[^ ]+]]
33; CHECK: invoke void @f()
34; CHECK: to label %[[EntryCopy:[^ ]+]] unwind label %catch
35; CHECK: catch:
Reid Kleckner5dbee7b2015-09-11 17:27:52 +000036; CHECK: catchpad []
37; CHECK-NEXT: to label %[[CatchCopy:[^ ]+]] unwind
Joseph Tremouletec182852015-08-28 01:12:35 +000038; CHECK: [[CatchCopy]]:
39; CHECK: [[LoadX2:%[^ ]+]] = load i32, i32* [[Slot]]
40; CHECK: call void @h(i32 [[LoadX2]]
41; CHECK: [[EntryCopy]]:
42; CHECK: [[LoadX1:%[^ ]+]] = load i32, i32* [[Slot]]
43; CHECK: call void @h(i32 [[LoadX1]]
44
45
46define void @test2() personality i32 (...)* @__CxxFrameHandler3 {
47entry:
48 invoke void @f()
49 to label %exit unwind label %cleanup
50cleanup:
51 cleanuppad []
52 br label %exit
53exit:
54 call void @f()
55 ret void
56}
57; Need two copies of %exit's call to @f -- the subsequent ret is only
58; valid when coming from %entry, but on the path from %cleanup, this
59; might be a valid call to @f which might dynamically not return.
Joseph Tremouletf3aff312015-09-10 16:51:25 +000060; CHECK-LABEL: define void @test2(
Joseph Tremouletec182852015-08-28 01:12:35 +000061; CHECK: entry:
62; CHECK: invoke void @f()
63; CHECK: to label %[[exit:[^ ]+]] unwind label %cleanup
64; CHECK: cleanup:
65; CHECK: cleanuppad []
66; CHECK: call void @f()
67; CHECK-NEXT: unreachable
68; CHECK: [[exit]]:
69; CHECK: call void @f()
70; CHECK-NEXT: ret void
71
72
73define void @test3() personality i32 (...)* @__CxxFrameHandler3 {
74entry:
75 invoke void @f()
76 to label %invoke.cont unwind label %catch
77invoke.cont:
78 invoke void @f()
79 to label %exit unwind label %cleanup
80catch:
81 catchpad [] to label %shared unwind label %endcatch
82endcatch:
83 catchendpad unwind to caller
84cleanup:
85 cleanuppad []
86 br label %shared
87shared:
88 call void @f()
89 br label %exit
90exit:
91 ret void
92}
93; Need two copies of %shared's call to @f (similar to @test2 but
94; the two regions here are siblings, not parent-child).
Joseph Tremouletf3aff312015-09-10 16:51:25 +000095; CHECK-LABEL: define void @test3(
Joseph Tremouletec182852015-08-28 01:12:35 +000096; CHECK: invoke void @f()
97; CHECK: invoke void @f()
98; CHECK: to label %[[exit:[^ ]+]] unwind
99; CHECK: catch:
Reid Kleckner5dbee7b2015-09-11 17:27:52 +0000100; CHECK: catchpad []
101; CHECK-NEXT: to label %[[shared:[^ ]+]] unwind
Joseph Tremouletec182852015-08-28 01:12:35 +0000102; CHECK: cleanup:
103; CHECK: cleanuppad []
104; CHECK: call void @f()
105; CHECK-NEXT: unreachable
106; CHECK: [[shared]]:
107; CHECK: call void @f()
108; CHECK-NEXT: unreachable
109; CHECK: [[exit]]:
110; CHECK: ret void
111
112
113define void @test4() personality i32 (...)* @__CxxFrameHandler3 {
114entry:
115 invoke void @f()
116 to label %shared unwind label %catch
117catch:
118 catchpad []
119 to label %shared unwind label %endcatch
120endcatch:
121 catchendpad unwind to caller
122shared:
123 %x = call i32 @g()
124 %i = call i32 @g()
125 %zero.trip = icmp eq i32 %i, 0
126 br i1 %zero.trip, label %exit, label %loop
127loop:
128 %i.loop = phi i32 [ %i, %shared ], [ %i.dec, %loop.tail ]
129 %b = call i1 @b()
130 br i1 %b, label %left, label %right
131left:
132 %y = call i32 @g()
133 br label %loop.tail
134right:
135 call void @h(i32 %x)
136 br label %loop.tail
137loop.tail:
138 %i.dec = sub i32 %i.loop, 1
139 %done = icmp eq i32 %i.dec, 0
140 br i1 %done, label %exit, label %loop
141exit:
142 call void @h(i32 %x)
143 unreachable
144}
145; Make sure we can clone regions that have internal control
146; flow and SSA values. Here we need two copies of everything
147; from %shared to %exit.
Joseph Tremouletf3aff312015-09-10 16:51:25 +0000148; CHECK-LABEL: define void @test4(
Joseph Tremouletec182852015-08-28 01:12:35 +0000149; CHECK: entry:
150; CHECK: to label %[[shared_E:[^ ]+]] unwind label %catch
151; CHECK: catch:
152; CHECK: to label %[[shared_C:[^ ]+]] unwind label %endcatch
153; CHECK: [[shared_C]]:
154; CHECK: [[x_C:%[^ ]+]] = call i32 @g()
155; CHECK: [[i_C:%[^ ]+]] = call i32 @g()
156; CHECK: [[zt_C:%[^ ]+]] = icmp eq i32 [[i_C]], 0
157; CHECK: br i1 [[zt_C]], label %[[exit_C:[^ ]+]], label %[[loop_C:[^ ]+]]
158; CHECK: [[shared_E]]:
159; CHECK: [[x_E:%[^ ]+]] = call i32 @g()
160; CHECK: [[i_E:%[^ ]+]] = call i32 @g()
161; CHECK: [[zt_E:%[^ ]+]] = icmp eq i32 [[i_E]], 0
162; CHECK: br i1 [[zt_E]], label %[[exit_E:[^ ]+]], label %[[loop_E:[^ ]+]]
163; CHECK: [[loop_C]]:
164; CHECK: [[iloop_C:%[^ ]+]] = phi i32 [ [[i_C]], %[[shared_C]] ], [ [[idec_C:%[^ ]+]], %[[looptail_C:[^ ]+]] ]
165; CHECK: [[b_C:%[^ ]+]] = call i1 @b()
166; CHECK: br i1 [[b_C]], label %[[left_C:[^ ]+]], label %[[right_C:[^ ]+]]
167; CHECK: [[loop_E]]:
168; CHECK: [[iloop_E:%[^ ]+]] = phi i32 [ [[i_E]], %[[shared_E]] ], [ [[idec_E:%[^ ]+]], %[[looptail_E:[^ ]+]] ]
169; CHECK: [[b_E:%[^ ]+]] = call i1 @b()
170; CHECK: br i1 [[b_E]], label %[[left_E:[^ ]+]], label %[[right_E:[^ ]+]]
171; CHECK: [[left_C]]:
172; CHECK: [[y_C:%[^ ]+]] = call i32 @g()
Hans Wennborg4a613702015-08-31 21:10:35 +0000173; CHECK: br label %[[looptail_C]]
Joseph Tremouletec182852015-08-28 01:12:35 +0000174; CHECK: [[left_E]]:
175; CHECK: [[y_E:%[^ ]+]] = call i32 @g()
Hans Wennborg4a613702015-08-31 21:10:35 +0000176; CHECK: br label %[[looptail_E]]
Joseph Tremouletec182852015-08-28 01:12:35 +0000177; CHECK: [[right_C]]:
178; CHECK: call void @h(i32 [[x_C]])
179; CHECK: br label %[[looptail_C]]
180; CHECK: [[right_E]]:
181; CHECK: call void @h(i32 [[x_E]])
182; CHECK: br label %[[looptail_E]]
183; CHECK: [[looptail_C]]:
184; CHECK: [[idec_C]] = sub i32 [[iloop_C]], 1
185; CHECK: [[done_C:%[^ ]+]] = icmp eq i32 [[idec_C]], 0
186; CHECK: br i1 [[done_C]], label %[[exit_C]], label %[[loop_C]]
187; CHECK: [[looptail_E]]:
188; CHECK: [[idec_E]] = sub i32 [[iloop_E]], 1
189; CHECK: [[done_E:%[^ ]+]] = icmp eq i32 [[idec_E]], 0
190; CHECK: br i1 [[done_E]], label %[[exit_E]], label %[[loop_E]]
191; CHECK: [[exit_C]]:
192; CHECK: call void @h(i32 [[x_C]])
193; CHECK: unreachable
194; CHECK: [[exit_E]]:
195; CHECK: call void @h(i32 [[x_E]])
196; CHECK: unreachable
197
198
199define void @test5() personality i32 (...)* @__CxxFrameHandler3 {
200entry:
201 invoke void @f()
202 to label %exit unwind label %outer
203outer:
204 %o = cleanuppad []
205 %x = call i32 @g()
206 invoke void @f()
207 to label %outer.ret unwind label %inner
208inner:
209 %i = catchpad []
210 to label %inner.catch unwind label %inner.endcatch
211inner.catch:
212 catchret %i to label %outer.post-inner
213inner.endcatch:
214 catchendpad unwind to caller
215outer.post-inner:
216 call void @h(i32 %x)
217 br label %outer.ret
218outer.ret:
219 cleanupret %o unwind to caller
220exit:
221 ret void
222}
223; Simple nested case (catch-inside-cleanup). Nothing needs
224; to be cloned. The def and use of %x are both in %outer
225; and so don't need to be spilled.
Joseph Tremouletf3aff312015-09-10 16:51:25 +0000226; CHECK-LABEL: define void @test5(
Joseph Tremouletec182852015-08-28 01:12:35 +0000227; CHECK: outer:
228; CHECK: %x = call i32 @g()
229; CHECK-NEXT: invoke void @f()
230; CHECK-NEXT: to label %outer.ret unwind label %inner
231; CHECK: inner:
232; CHECK: to label %inner.catch unwind label %inner.endcatch
233; CHECK: inner.catch:
234; CHECK-NEXT: catchret %i to label %outer.post-inner
235; CHECK: outer.post-inner:
236; CHECK-NEXT: call void @h(i32 %x)
237; CHECK-NEXT: br label %outer.ret
238
239
240define void @test6() personality i32 (...)* @__CxxFrameHandler3 {
241entry:
242 invoke void @f()
243 to label %invoke.cont unwind label %left
244invoke.cont:
245 invoke void @f()
246 to label %exit unwind label %right
247left:
248 cleanuppad []
249 br label %shared
250right:
251 catchpad []
252 to label %right.catch unwind label %right.end
253right.catch:
254 br label %shared
255right.end:
256 catchendpad unwind to caller
257shared:
258 %x = call i32 @g()
259 invoke void @f()
260 to label %shared.cont unwind label %inner
261shared.cont:
262 unreachable
263inner:
264 %i = cleanuppad []
265 call void @h(i32 %x)
266 cleanupret %i unwind label %right.end
267exit:
268 ret void
269}
270; %inner is a cleanup which appears both as a child of
271; %left and as a child of %right. Since statically we
272; need each funclet to have a single parent, we need to
273; clone the entire %inner funclet so we can have one
274; copy under each parent. The cleanupret in %inner
275; unwinds to the catchendpad for %right, so the copy
276; of %inner under %right should include it; the copy
277; of %inner under %left should instead have an
278; `unreachable` inserted there, but the copy under
279; %left still needs to be created because it's possible
280; the dynamic path enters %left, then enters %inner,
281; then calls @h, and that the call to @h doesn't return.
Joseph Tremouletf3aff312015-09-10 16:51:25 +0000282; CHECK-LABEL: define void @test6(
Joseph Tremouletec182852015-08-28 01:12:35 +0000283; TODO: CHECKs
284
285
286define void @test7() personality i32 (...)* @__CxxFrameHandler3 {
287entry:
288 invoke void @f()
289 to label %invoke.cont unwind label %left
290invoke.cont:
291 invoke void @f()
292 to label %unreachable unwind label %right
293left:
294 cleanuppad []
295 invoke void @f() to label %unreachable unwind label %inner
296right:
297 catchpad []
298 to label %right.catch unwind label %right.end
299right.catch:
300 invoke void @f() to label %unreachable unwind label %inner
301right.end:
302 catchendpad unwind to caller
303inner:
304 %i = cleanuppad []
305 %x = call i32 @g()
306 call void @h(i32 %x)
307 cleanupret %i unwind label %right.end
308unreachable:
309 unreachable
310}
311; Another case of a two-parent child (like @test6), this time
312; with the join at the entry itself instead of following a
313; non-pad join.
Joseph Tremouletf3aff312015-09-10 16:51:25 +0000314; CHECK-LABEL: define void @test7(
Joseph Tremouletec182852015-08-28 01:12:35 +0000315; TODO: CHECKs
316
317
318define void @test8() personality i32 (...)* @__CxxFrameHandler3 {
319entry:
320 invoke void @f()
321 to label %invoke.cont unwind label %left
322invoke.cont:
323 invoke void @f()
324 to label %unreachable unwind label %right
325left:
326 cleanuppad []
327 br label %shared
328right:
329 catchpad []
330 to label %right.catch unwind label %right.end
331right.catch:
332 br label %shared
333right.end:
334 catchendpad unwind to caller
335shared:
336 invoke void @f()
337 to label %unreachable unwind label %inner
338inner:
339 cleanuppad []
340 invoke void @f()
341 to label %unreachable unwind label %inner.child
342inner.child:
343 cleanuppad []
344 %x = call i32 @g()
345 call void @h(i32 %x)
346 unreachable
347unreachable:
348 unreachable
349}
350; %inner is a two-parent child which itself has a child; need
351; to make two copies of both the %inner and %inner.child.
Joseph Tremouletf3aff312015-09-10 16:51:25 +0000352; CHECK-LABEL: define void @test8(
Joseph Tremouletec182852015-08-28 01:12:35 +0000353; TODO: CHECKs
354
355
356define void @test9() personality i32 (...)* @__CxxFrameHandler3 {
357entry:
358 invoke void @f()
359 to label %invoke.cont unwind label %left
360invoke.cont:
361 invoke void @f()
362 to label %unreachable unwind label %right
363left:
364 cleanuppad []
365 call void @h(i32 1)
366 invoke void @f()
367 to label %unreachable unwind label %right
368right:
369 cleanuppad []
370 call void @h(i32 2)
371 invoke void @f()
372 to label %unreachable unwind label %left
373unreachable:
374 unreachable
375}
376; This is an irreducible loop with two funclets that enter each other;
377; need to make two copies of each funclet (one a child of root, the
378; other a child of the opposite funclet), but also make sure not to
379; clone self-descendants (if we tried to do that we'd need to make an
380; infinite number of them). Presumably if optimizations ever generated
381; such a thing it would mean that one of the two cleanups was originally
382; the parent of the other, but that we'd somehow lost track in the CFG
383; of which was which along the way; generating each possibility lets
384; whichever case was correct execute correctly.
Joseph Tremouletf3aff312015-09-10 16:51:25 +0000385; CHECK-LABEL: define void @test9(
Joseph Tremouletec182852015-08-28 01:12:35 +0000386; TODO: CHECKs
Joseph Tremouletf3aff312015-09-10 16:51:25 +0000387
388define void @test10() personality i32 (...)* @__CxxFrameHandler3 {
389entry:
390 invoke void @f()
391 to label %unreachable unwind label %inner
392inner:
393 %cleanup = cleanuppad []
394 ; make sure we don't overlook this cleanupret and try to process
395 ; successor %outer as a child of inner.
396 cleanupret %cleanup unwind label %outer
397outer:
398 %catch = catchpad [] to label %catch.body unwind label %endpad
399catch.body:
400 catchret %catch to label %exit
401endpad:
402 catchendpad unwind to caller
403exit:
404 ret void
405unreachable:
406 unreachable
407}
408; CHECK-LABEL: define void @test10(
409; CHECK-NEXT: entry:
410; CHECK-NEXT: invoke
411; CHECK-NEXT: to label %unreachable unwind label %inner
412; CHECK: inner:
413; CHECK-NEXT: %cleanup = cleanuppad
414; CHECK-NEXT: cleanupret %cleanup unwind label %outer
415; CHECK: outer:
Reid Kleckner5dbee7b2015-09-11 17:27:52 +0000416; CHECK-NEXT: %catch = catchpad []
417; CHECK-NEXT: to label %catch.body unwind label %endpad
Joseph Tremouletf3aff312015-09-10 16:51:25 +0000418; CHECK: catch.body:
419; CHECK-NEXT: catchret %catch to label %exit
420; CHECK: endpad:
421; CHECK-NEXT: catchendpad unwind to caller
422; CHECK: exit:
423; CHECK-NEXT: ret void
Joseph Tremoulet09af67a2015-09-27 01:47:46 +0000424
425define void @test11() personality i32 (...)* @__CxxFrameHandler3 {
426entry:
427 invoke void @f()
428 to label %exit unwind label %cleanup.outer
429cleanup.outer:
430 %outer = cleanuppad []
431 invoke void @f()
432 to label %outer.cont unwind label %cleanup.inner
433outer.cont:
434 br label %merge
435cleanup.inner:
436 %inner = cleanuppad []
437 br label %merge
438merge:
439 invoke void @f()
440 to label %unreachable unwind label %merge.end
441unreachable:
442 unreachable
443merge.end:
444 cleanupendpad %outer unwind to caller
445exit:
446 ret void
447}
448; merge.end will get cloned for outer and inner, but is implausible
449; from inner, so the invoke @f() in inner's copy of merge should be
450; rewritten to call @f()
451; CHECK-LABEL: define void @test11()
452; CHECK: %inner = cleanuppad []
453; CHECK-NEXT: call void @f()
454; CHECK-NEXT: unreachable