• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -winehprepare  < %s | FileCheck %s
2
3declare i32 @__CxxFrameHandler3(...)
4declare i32 @__C_specific_handler(...)
5declare void @ProcessCLRException(...)
6
7declare void @f()
8
9declare void @llvm.foo(i32) nounwind
10declare void @llvm.bar() nounwind
11declare i32 @llvm.qux() nounwind
12declare i1 @llvm.baz() nounwind
13
14define void @test1() personality i32 (...)* @__CxxFrameHandler3 {
15entry:
16  ; %x def colors: {entry} subset of use colors; must spill
17  %x = call i32 @llvm.qux()
18  invoke void @f()
19    to label %noreturn unwind label %catch.switch
20catch.switch:
21  %cs = catchswitch within none [label %catch] unwind to caller
22catch:
23  %cp = catchpad within %cs []
24  br label %noreturn
25noreturn:
26  ; %x use colors: {entry, cleanup}
27  call void @llvm.foo(i32 %x)
28  unreachable
29}
30; Need two copies of the call to @h, one under entry and one under catch.
31; Currently we generate a load for each, though we shouldn't need one
32; for the use in entry's copy.
33; CHECK-LABEL: define void @test1(
34; CHECK: entry:
35; CHECK:   %x = call i32 @llvm.qux()
36; CHECK:   invoke void @f()
37; CHECK:     to label %[[EntryCopy:[^ ]+]] unwind label %catch
38; CHECK: catch.switch:
39; CHECK:   %cs = catchswitch within none [label %catch] unwind to caller
40; CHECK: catch:
41; CHECK:   catchpad within %cs []
42; CHECK-NEXT: call void @llvm.foo(i32 %x)
43; CHECK: [[EntryCopy]]:
44; CHECK:   call void @llvm.foo(i32 %x)
45
46
47define void @test2() personality i32 (...)* @__CxxFrameHandler3 {
48entry:
49  invoke void @f()
50    to label %exit unwind label %cleanup
51cleanup:
52  cleanuppad within none []
53  br label %exit
54exit:
55  call void @llvm.bar()
56  ret void
57}
58; Need two copies of %exit's call to @f -- the subsequent ret is only
59; valid when coming from %entry, but on the path from %cleanup, this
60; might be a valid call to @f which might dynamically not return.
61; CHECK-LABEL: define void @test2(
62; CHECK: entry:
63; CHECK:   invoke void @f()
64; CHECK:     to label %[[exit:[^ ]+]] unwind label %cleanup
65; CHECK: cleanup:
66; CHECK:   cleanuppad within none []
67; CHECK:   call void @llvm.bar()
68; CHECK-NEXT: unreachable
69; CHECK: [[exit]]:
70; CHECK:   call void @llvm.bar()
71; CHECK-NEXT: ret void
72
73
74define void @test3() personality i32 (...)* @__CxxFrameHandler3 {
75entry:
76  invoke void @f()
77    to label %invoke.cont unwind label %catch.switch
78invoke.cont:
79  invoke void @f()
80    to label %exit unwind label %cleanup
81catch.switch:
82  %cs = catchswitch within none [label %catch] unwind to caller
83catch:
84  catchpad within %cs []
85  br label %shared
86cleanup:
87  cleanuppad within none []
88  br label %shared
89shared:
90  call void @llvm.bar()
91  br label %exit
92exit:
93  ret void
94}
95; Need two copies of %shared's call to @f (similar to @test2 but
96; the two regions here are siblings, not parent-child).
97; CHECK-LABEL: define void @test3(
98; CHECK:   invoke void @f()
99; CHECK:   invoke void @f()
100; CHECK:     to label %[[exit:[^ ]+]] unwind
101; CHECK: catch:
102; CHECK:   catchpad within %cs []
103; CHECK-NEXT: call void @llvm.bar()
104; CHECK-NEXT: unreachable
105; CHECK: cleanup:
106; CHECK:   cleanuppad within none []
107; CHECK:   call void @llvm.bar()
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.switch
117catch.switch:
118  %cs = catchswitch within none [label %catch] unwind to caller
119catch:
120  catchpad within %cs []
121  br label %shared
122shared:
123  %x = call i32 @llvm.qux()
124  %i = call i32 @llvm.qux()
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 @llvm.baz()
130  br i1 %b, label %left, label %right
131left:
132  %y = call i32 @llvm.qux()
133  br label %loop.tail
134right:
135  call void @llvm.foo(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 @llvm.foo(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.
148; CHECK-LABEL: define void @test4(
149; CHECK:  entry:
150; CHECK:    to label %[[shared_E:[^ ]+]] unwind label %catch.switch
151; CHECK:  catch:
152; CHECK:    catchpad within %cs []
153; CHECK:    [[x_C:%[^ ]+]] = call i32 @llvm.qux()
154; CHECK:    [[i_C:%[^ ]+]] = call i32 @llvm.qux()
155; CHECK:    [[zt_C:%[^ ]+]] = icmp eq i32 [[i_C]], 0
156; CHECK:    br i1 [[zt_C]], label %[[exit_C:[^ ]+]], label %[[loop_C:[^ ]+]]
157; CHECK:  [[shared_E]]:
158; CHECK:    [[x_E:%[^ ]+]] = call i32 @llvm.qux()
159; CHECK:    [[i_E:%[^ ]+]] = call i32 @llvm.qux()
160; CHECK:    [[zt_E:%[^ ]+]] = icmp eq i32 [[i_E]], 0
161; CHECK:    br i1 [[zt_E]], label %[[exit_E:[^ ]+]], label %[[loop_E:[^ ]+]]
162; CHECK:  [[loop_C]]:
163; CHECK:    [[iloop_C:%[^ ]+]] = phi i32 [ [[i_C]], %catch ], [ [[idec_C:%[^ ]+]], %[[looptail_C:[^ ]+]] ]
164; CHECK:    [[b_C:%[^ ]+]] = call i1 @llvm.baz()
165; CHECK:    br i1 [[b_C]], label %[[left_C:[^ ]+]], label %[[right_C:[^ ]+]]
166; CHECK:  [[loop_E]]:
167; CHECK:    [[iloop_E:%[^ ]+]] = phi i32 [ [[i_E]], %[[shared_E]] ], [ [[idec_E:%[^ ]+]], %[[looptail_E:[^ ]+]] ]
168; CHECK:    [[b_E:%[^ ]+]] = call i1 @llvm.baz()
169; CHECK:    br i1 [[b_E]], label %[[left_E:[^ ]+]], label %[[right_E:[^ ]+]]
170; CHECK:  [[left_C]]:
171; CHECK:    [[y_C:%[^ ]+]] = call i32 @llvm.qux()
172; CHECK:    br label %[[looptail_C]]
173; CHECK:  [[left_E]]:
174; CHECK:    [[y_E:%[^ ]+]] = call i32 @llvm.qux()
175; CHECK:    br label %[[looptail_E]]
176; CHECK:  [[right_C]]:
177; CHECK:    call void @llvm.foo(i32 [[x_C]])
178; CHECK:    br label %[[looptail_C]]
179; CHECK:  [[right_E]]:
180; CHECK:    call void @llvm.foo(i32 [[x_E]])
181; CHECK:    br label %[[looptail_E]]
182; CHECK:  [[looptail_C]]:
183; CHECK:    [[idec_C]] = sub i32 [[iloop_C]], 1
184; CHECK:    [[done_C:%[^ ]+]] = icmp eq i32 [[idec_C]], 0
185; CHECK:    br i1 [[done_C]], label %[[exit_C]], label %[[loop_C]]
186; CHECK:  [[looptail_E]]:
187; CHECK:    [[idec_E]] = sub i32 [[iloop_E]], 1
188; CHECK:    [[done_E:%[^ ]+]] = icmp eq i32 [[idec_E]], 0
189; CHECK:    br i1 [[done_E]], label %[[exit_E]], label %[[loop_E]]
190; CHECK:  [[exit_C]]:
191; CHECK:    call void @llvm.foo(i32 [[x_C]])
192; CHECK:    unreachable
193; CHECK:  [[exit_E]]:
194; CHECK:    call void @llvm.foo(i32 [[x_E]])
195; CHECK:    unreachable
196
197
198define void @test5() personality i32 (...)* @__C_specific_handler {
199entry:
200  invoke void @f()
201    to label %exit unwind label %outer
202outer:
203  %o = cleanuppad within none []
204  %x = call i32 @llvm.qux()
205  invoke void @f() [ "funclet"(token %o) ]
206    to label %outer.ret unwind label %catch.switch
207catch.switch:
208  %cs = catchswitch within %o [label %inner] unwind to caller
209inner:
210  %i = catchpad within %cs []
211  catchret from %i to label %outer.post-inner
212outer.post-inner:
213  call void @llvm.foo(i32 %x)
214  br label %outer.ret
215outer.ret:
216  cleanupret from %o unwind to caller
217exit:
218  ret void
219}
220; Simple nested case (catch-inside-cleanup).  Nothing needs
221; to be cloned.  The def and use of %x are both in %outer
222; and so don't need to be spilled.
223; CHECK-LABEL: define void @test5(
224; CHECK:      outer:
225; CHECK:        %x = call i32 @llvm.qux()
226; CHECK-NEXT:   invoke void @f()
227; CHECK-NEXT:     to label %outer.ret unwind label %catch.switch
228; CHECK:      inner:
229; CHECK-NEXT:   %i = catchpad within %cs []
230; CHECK-NEXT:   catchret from %i to label %outer.post-inner
231; CHECK:      outer.post-inner:
232; CHECK-NEXT:   call void @llvm.foo(i32 %x)
233; CHECK-NEXT:   br label %outer.ret
234
235
236define void @test10() personality i32 (...)* @__CxxFrameHandler3 {
237entry:
238  invoke void @f()
239    to label %unreachable unwind label %inner
240inner:
241  %cleanup = cleanuppad within none []
242  ; make sure we don't overlook this cleanupret and try to process
243  ; successor %outer as a child of inner.
244  cleanupret from %cleanup unwind label %outer
245outer:
246  %cs = catchswitch within none [label %catch.body] unwind to caller
247
248catch.body:
249  %catch = catchpad within %cs []
250  catchret from %catch to label %exit
251exit:
252  ret void
253unreachable:
254  unreachable
255}
256; CHECK-LABEL: define void @test10(
257; CHECK-NEXT: entry:
258; CHECK-NEXT:   invoke
259; CHECK-NEXT:     to label %unreachable unwind label %inner
260; CHECK:      inner:
261; CHECK-NEXT:   %cleanup = cleanuppad within none []
262; CHECK-NEXT:   cleanupret from %cleanup unwind label %outer
263; CHECK:      outer:
264; CHECK-NEXT:   %cs = catchswitch within none [label %catch.body] unwind to caller
265; CHECK:      catch.body:
266; CHECK-NEXT:   %catch = catchpad within %cs []
267; CHECK-NEXT:   catchret from %catch to label %exit
268; CHECK:      exit:
269; CHECK-NEXT:   ret void
270
271define void @test11() personality i32 (...)* @__C_specific_handler {
272entry:
273  invoke void @f()
274    to label %exit unwind label %cleanup.outer
275cleanup.outer:
276  %outer = cleanuppad within none []
277  invoke void @f() [ "funclet"(token %outer) ]
278    to label %outer.cont unwind label %cleanup.inner
279outer.cont:
280  br label %merge
281cleanup.inner:
282  %inner = cleanuppad within %outer []
283  br label %merge
284merge:
285  call void @llvm.bar()
286  unreachable
287exit:
288  ret void
289}
290; merge.end will get cloned for outer and inner, but is implausible
291; from inner, so the call @f() in inner's copy of merge should be
292; rewritten to call @f()
293; CHECK-LABEL: define void @test11()
294; CHECK:      %inner = cleanuppad within %outer []
295; CHECK-NEXT: call void @llvm.bar()
296; CHECK-NEXT: unreachable
297
298define void @test12() personality i32 (...)* @__CxxFrameHandler3 !dbg !5 {
299entry:
300  invoke void @f()
301    to label %cont unwind label %left, !dbg !8
302cont:
303  invoke void @f()
304    to label %exit unwind label %right
305left:
306  cleanuppad within none []
307  br label %join
308right:
309  cleanuppad within none []
310  br label %join
311join:
312  ; This call will get cloned; make sure we can handle cloning
313  ; instructions with debug metadata attached.
314  call void @llvm.bar(), !dbg !9
315  unreachable
316exit:
317  ret void
318}
319
320; CHECK-LABEL: define void @test13()
321; CHECK: ret void
322define void @test13() personality i32 (...)* @__CxxFrameHandler3 {
323entry:
324  ret void
325
326unreachable:
327  cleanuppad within none []
328  unreachable
329}
330
331define void @test14() personality void (...)* @ProcessCLRException {
332entry:
333  invoke void @f()
334    to label %cont unwind label %cleanup
335cont:
336  invoke void @f()
337    to label %exit unwind label %switch.outer
338cleanup:
339  %cleanpad = cleanuppad within none []
340  invoke void @f() [ "funclet" (token %cleanpad) ]
341    to label %cleanret unwind label %switch.inner
342switch.inner:
343  %cs.inner = catchswitch within %cleanpad [label %pad.inner] unwind to caller
344pad.inner:
345  %cp.inner = catchpad within %cs.inner [i32 1]
346  catchret from %cp.inner to label %join
347cleanret:
348  cleanupret from %cleanpad unwind to caller
349switch.outer:
350  %cs.outer = catchswitch within none [label %pad.outer] unwind to caller
351pad.outer:
352  %cp.outer = catchpad within %cs.outer [i32 2]
353  catchret from %cp.outer to label %join
354join:
355  %phi = phi i32 [ 1, %pad.inner ], [ 2, %pad.outer ]
356  call void @llvm.foo(i32 %phi)
357  unreachable
358exit:
359  ret void
360}
361; Both catchrets target %join, but the catchret from %cp.inner
362; returns to %cleanpad and the catchret from %cp.outer returns to the
363; main function, so %join needs to get cloned and one of the cleanuprets
364; needs to be updated to target the clone
365; CHECK-LABEL: define void @test14()
366; CHECK: catchret from %cp.inner to label %[[Clone1:.+]]
367; CHECK: catchret from %cp.outer to label %[[Clone2:.+]]
368; CHECK: [[Clone1]]:
369; CHECK-NEXT: call void @llvm.foo(i32 1)
370; CHECK-NEXT: unreachable
371; CHECK: [[Clone2]]:
372; CHECK-NEXT: call void @llvm.foo(i32 2)
373; CHECK-NEXT: unreachable
374
375;; Debug info (from test12)
376
377; Make sure the DISubprogram doesn't get cloned
378; CHECK-LABEL: !llvm.module.flags
379; CHECK-NOT: !DISubprogram
380; CHECK: !{{[0-9]+}} = distinct !DISubprogram(name: "test12"
381; CHECK-NOT: !DISubprogram
382!llvm.module.flags = !{!0}
383!llvm.dbg.cu = !{!1}
384
385!0 = !{i32 2, !"Debug Info Version", i32 3}
386!1 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !2, producer: "compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !3)
387!2 = !DIFile(filename: "test.cpp", directory: ".")
388!3 = !{}
389!5 = distinct !DISubprogram(name: "test12", scope: !2, file: !2, type: !6, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !1, retainedNodes: !3)
390!6 = !DISubroutineType(types: !7)
391!7 = !{null}
392!8 = !DILocation(line: 1, scope: !5)
393!9 = !DILocation(line: 2, scope: !5)
394