• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -winehprepare  < %s | FileCheck %s
2
3declare i32 @__CxxFrameHandler3(...)
4
5declare void @f()
6
7declare i32 @g()
8
9declare void @h(i32)
10
11declare i1 @i()
12
13declare void @llvm.bar() nounwind
14
15; CHECK-LABEL: @test1(
16define void @test1(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
17entry:
18  ; Spill slot should be inserted here
19  ; CHECK: [[Slot:%[^ ]+]] = alloca
20  ; Can't store for %phi at these defs because the lifetimes overlap
21  ; CHECK-NOT: store
22  %x = call i32 @g()
23  %y = call i32 @g()
24  br i1 %B, label %left, label %right
25left:
26  ; CHECK: left:
27  ; CHECK-NEXT: store i32 %x, i32* [[Slot]]
28  ; CHECK-NEXT: invoke void @f
29  invoke void @f()
30          to label %exit unwind label %merge
31right:
32  ; CHECK: right:
33  ; CHECK-NEXT: store i32 %y, i32* [[Slot]]
34  ; CHECK-NEXT: invoke void @f
35  invoke void @f()
36          to label %exit unwind label %merge
37merge:
38  ; CHECK: merge:
39  ; CHECK-NOT: = phi
40  %phi = phi i32 [ %x, %left ], [ %y, %right ]
41  %cs1 = catchswitch within none [label %catch] unwind to caller
42
43catch:
44  %cp = catchpad within %cs1 []
45  ; CHECK: catch:
46  ; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]]
47  ; CHECK-NEXT: call void @h(i32 [[Reload]])
48  call void @h(i32 %phi) [ "funclet"(token %cp) ]
49  catchret from %cp to label %exit
50
51exit:
52  ret void
53}
54
55; CHECK-LABEL: @test2(
56define void @test2(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
57entry:
58  br i1 %B, label %left, label %right
59left:
60  ; Need two stores here because %x and %y interfere so they need 2 slots
61  ; CHECK: left:
62  ; CHECK:   store i32 1, i32* [[Slot1:%[^ ]+]]
63  ; CHECK:   store i32 1, i32* [[Slot2:%[^ ]+]]
64  ; CHECK-NEXT: invoke void @f
65  invoke void @f()
66          to label %exit unwind label %merge.inner
67right:
68  ; Need two stores here because %x and %y interfere so they need 2 slots
69  ; CHECK: right:
70  ; CHECK-DAG:   store i32 2, i32* [[Slot1]]
71  ; CHECK-DAG:   store i32 2, i32* [[Slot2]]
72  ; CHECK: invoke void @f
73  invoke void @f()
74          to label %exit unwind label %merge.inner
75merge.inner:
76  ; CHECK: merge.inner:
77  ; CHECK-NOT: = phi
78  ; CHECK: catchswitch within none
79  %x = phi i32 [ 1, %left ], [ 2, %right ]
80  %cs1 = catchswitch within none [label %catch.inner] unwind label %merge.outer
81
82catch.inner:
83  %cpinner = catchpad within %cs1 []
84  ; Need just one store here because only %y is affected
85  ; CHECK: catch.inner:
86  %z = call i32 @g() [ "funclet"(token %cpinner) ]
87  ; CHECK:   store i32 %z
88  ; CHECK-NEXT: invoke void @f
89  invoke void @f() [ "funclet"(token %cpinner) ]
90          to label %catchret.inner unwind label %merge.outer
91
92catchret.inner:
93  catchret from %cpinner to label %exit
94
95merge.outer:
96  %y = phi i32 [ %x, %merge.inner ], [ %z, %catch.inner ]
97  ; CHECK: merge.outer:
98  ; CHECK-NOT: = phi
99  ; CHECK: catchswitch within none
100  %cs2 = catchswitch within none [label %catch.outer] unwind to caller
101
102catch.outer:
103  %cpouter = catchpad within %cs2 []
104  ; CHECK: catch.outer:
105  ; CHECK: [[CatchPad:%[^ ]+]] = catchpad within %cs2 []
106  ; Need to load x and y from two different slots since they're both live
107  ; and can have different values (if we came from catch.inner)
108  ; CHECK-DAG: load i32, i32* [[Slot1]]
109  ; CHECK-DAG: load i32, i32* [[Slot2]]
110  ; CHECK: catchret from [[CatchPad]] to label
111  call void @h(i32 %x) [ "funclet"(token %cpouter) ]
112  call void @h(i32 %y) [ "funclet"(token %cpouter) ]
113  catchret from %cpouter to label %exit
114
115exit:
116  ret void
117}
118
119; test4: don't need stores for %phi.inner, as its only use is to feed %phi.outer
120;        %phi.outer needs stores in %left, %right, and %join
121; CHECK-LABEL: @test4(
122define void @test4(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
123entry:
124  ; CHECK:      entry:
125  ; CHECK:        [[Slot:%[^ ]+]] = alloca
126  ; CHECK-NEXT:   br
127  br i1 %B, label %left, label %right
128left:
129  ; CHECK: left:
130  ; CHECK-NOT: store
131  ; CHECK: store i32 %l, i32* [[Slot]]
132  ; CHECK-NEXT: invoke void @f
133  %l = call i32 @g()
134  invoke void @f()
135          to label %join unwind label %catchpad.inner
136right:
137  ; CHECK: right:
138  ; CHECK-NOT: store
139  ; CHECK: store i32 %r, i32* [[Slot]]
140  ; CHECK-NEXT: invoke void @f
141  %r = call i32 @g()
142  invoke void @f()
143          to label %join unwind label %catchpad.inner
144catchpad.inner:
145   ; CHECK: catchpad.inner:
146   ; CHECK-NEXT: catchswitch within none
147   %phi.inner = phi i32 [ %l, %left ], [ %r, %right ]
148   %cs1 = catchswitch within none [label %catch.inner] unwind label %catchpad.outer
149catch.inner:
150   %cp1 = catchpad within %cs1 []
151   catchret from %cp1 to label %join
152join:
153  ; CHECK: join:
154  ; CHECK-NOT: store
155  ; CHECK: store i32 %j, i32* [[Slot]]
156  ; CHECK-NEXT: invoke void @f
157   %j = call i32 @g()
158   invoke void @f()
159           to label %exit unwind label %catchpad.outer
160
161catchpad.outer:
162   ; CHECK: catchpad.outer:
163   ; CHECK-NEXT: catchswitch within none
164   %phi.outer = phi i32 [ %phi.inner, %catchpad.inner ], [ %j, %join ]
165   %cs2 = catchswitch within none [label %catch.outer] unwind to caller
166catch.outer:
167   ; CHECK: catch.outer:
168   ; CHECK:   [[Reload:%[^ ]+]] = load i32, i32* [[Slot]]
169   ; CHECK:   call void @h(i32 [[Reload]])
170   %cp2 = catchpad within %cs2 []
171   call void @h(i32 %phi.outer) [ "funclet"(token %cp2) ]
172   catchret from %cp2 to label %exit
173exit:
174   ret void
175}
176
177; CHECK-LABEL: @test5(
178define void @test5() personality i32 (...)* @__CxxFrameHandler3 {
179entry:
180  ; need store for %phi.cleanup
181  ; CHECK:      entry:
182  ; CHECK:        store i32 1, i32* [[CleanupSlot:%[^ ]+]]
183  ; CHECK-NEXT:   invoke void @f
184  invoke void @f()
185          to label %invoke.cont unwind label %cleanup
186
187invoke.cont:
188  ; need store for %phi.cleanup
189  ; CHECK:      invoke.cont:
190  ; CHECK-NEXT:   store i32 2, i32* [[CleanupSlot]]
191  ; CHECK-NEXT:   invoke void @f
192  invoke void @f()
193          to label %invoke.cont2 unwind label %cleanup
194
195cleanup:
196  ; cleanup phi can be loaded at cleanup entry
197  ; CHECK: cleanup:
198  ; CHECK-NEXT: cleanuppad within none []
199  ; CHECK: [[CleanupReload:%[^ ]+]] = load i32, i32* [[CleanupSlot]]
200  %phi.cleanup = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]
201  %cp = cleanuppad within none []
202  %b = call i1 @i() [ "funclet"(token %cp) ]
203  br i1 %b, label %left, label %right
204
205left:
206  ; CHECK: left:
207  ; CHECK:   call void @h(i32 [[CleanupReload]]
208  call void @h(i32 %phi.cleanup) [ "funclet"(token %cp) ]
209  br label %merge
210
211right:
212  ; CHECK: right:
213  ; CHECK:   call void @h(i32 [[CleanupReload]]
214  call void @h(i32 %phi.cleanup) [ "funclet"(token %cp) ]
215  br label %merge
216
217merge:
218  ; need store for %phi.catch
219  ; CHECK:      merge:
220  ; CHECK-NEXT:   store i32 [[CleanupReload]], i32* [[CatchSlot:%[^ ]+]]
221  ; CHECK-NEXT:   cleanupret
222  cleanupret from %cp unwind label %catchswitch
223
224invoke.cont2:
225  ; need store for %phi.catch
226  ; CHECK:      invoke.cont2:
227  ; CHECK-NEXT:   store i32 3, i32* [[CatchSlot]]
228  ; CHECK-NEXT:   invoke void @f
229  invoke void @f()
230          to label %exit unwind label %catchswitch
231
232catchswitch:
233  ; CHECK: catchswitch:
234  ; CHECK-NEXT: catchswitch within none
235  %phi.catch = phi i32 [ %phi.cleanup, %merge ], [ 3, %invoke.cont2 ]
236  %cs1 = catchswitch within none [label %catch] unwind to caller
237
238catch:
239  ; CHECK: catch:
240  ; CHECK:   catchpad within %cs1
241  ; CHECK:   [[CatchReload:%[^ ]+]] = load i32, i32* [[CatchSlot]]
242  ; CHECK:   call void @h(i32 [[CatchReload]]
243  %cp2 = catchpad within %cs1 []
244  call void @h(i32 %phi.catch) [ "funclet"(token %cp2) ]
245  catchret from %cp2 to label %exit
246
247exit:
248  ret void
249}
250
251; We used to demote %x, but we don't need to anymore.
252; CHECK-LABEL: @test6(
253define void @test6() personality i32 (...)* @__CxxFrameHandler3 {
254entry:
255  ; CHECK: entry:
256  ; CHECK: %x = invoke i32 @g()
257  ; CHECK-NEXT: to label %loop unwind label %to_caller
258  %x = invoke i32 @g()
259          to label %loop unwind label %to_caller
260to_caller:
261  %cp1 = cleanuppad within none []
262  cleanupret from %cp1 unwind to caller
263loop:
264  invoke void @f()
265          to label %loop unwind label %cleanup
266cleanup:
267  ; CHECK: cleanup:
268  ; CHECK:   call void @h(i32 %x)
269  %cp2 = cleanuppad within none []
270  call void @h(i32 %x) [ "funclet"(token %cp2) ]
271  cleanupret from %cp2 unwind to caller
272}
273
274; CHECK-LABEL: @test7(
275define void @test7() personality i32 (...)* @__CxxFrameHandler3 {
276entry:
277  ; %x is an EH pad phi, so gets stored in pred here
278  ; CHECK: entry:
279  ; CHECK:   store i32 1, i32* [[SlotX:%[^ ]+]]
280  ; CHECK:   invoke void @f()
281  invoke void @f()
282     to label %invoke.cont unwind label %catchpad
283invoke.cont:
284  ; %x is an EH pad phi, so gets stored in pred here
285  ; CHECK: invoke.cont:
286  ; CHECK:   store i32 2, i32* [[SlotX]]
287  ; CHECK:   invoke void @f()
288  invoke void @f()
289    to label %exit unwind label %catchpad
290catchpad:
291  ; %x phi should be eliminated
292  ; CHECK: catchpad:
293  ; CHECK-NEXT: catchswitch within none
294  %x = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]
295  %cs1 = catchswitch within none [label %catch] unwind to caller
296catch:
297  ; CHECK: catch:
298  ; CHECK-NEXT: %[[CatchPad:[^ ]+]] = catchpad within %cs1 []
299  %cp = catchpad within %cs1 []
300  %b = call i1 @i() [ "funclet"(token %cp) ]
301  br i1 %b, label %left, label %right
302left:
303  ; Edge from %left to %join needs to be split so that
304  ; the load of %x can be inserted *after* the catchret
305  ; CHECK: left:
306  ; CHECK-NEXT: catchret from %[[CatchPad]] to label %[[SplitLeft:[^ ]+]]
307  catchret from %cp to label %join
308  ; CHECK: [[SplitLeft]]:
309  ; CHECK:   [[LoadX:%[^ ]+]] = load i32, i32* [[SlotX]]
310  ; CHECK:   br label %join
311right:
312  ; Edge from %right to %join needs to be split so that
313  ; the load of %y can be inserted *after* the catchret
314  ; CHECK: right:
315  ; CHECK:   %y = call i32 @g()
316  ; CHECK:   catchret from %[[CatchPad]] to label %join
317  %y = call i32 @g() [ "funclet"(token %cp) ]
318  catchret from %cp to label %join
319join:
320  ; CHECK: join:
321  ; CHECK:   %phi = phi i32 [ [[LoadX]], %[[SplitLeft]] ], [ %y, %right ]
322  %phi = phi i32 [ %x, %left ], [ %y, %right ]
323  call void @h(i32 %phi)
324  br label %exit
325exit:
326  ret void
327}
328
329; CHECK-LABEL: @test8(
330define void @test8() personality i32 (...)* @__CxxFrameHandler3 { entry:
331  invoke void @f()
332          to label %done unwind label %cleanup1
333  invoke void @f()
334          to label %done unwind label %cleanup2
335
336done:
337  ret void
338
339cleanup1:
340  ; CHECK: [[CleanupPad1:%[^ ]+]] = cleanuppad within none []
341  ; CHECK-NEXT: call void @llvm.bar()
342  ; CHECK-NEXT: cleanupret from [[CleanupPad1]]
343  %cp0 = cleanuppad within none []
344  br label %cleanupexit
345
346cleanup2:
347  ; CHECK: cleanuppad within none []
348  ; CHECK-NEXT: call void @llvm.bar()
349  ; CHECK-NEXT: unreachable
350  %cp1 = cleanuppad within none []
351  br label %cleanupexit
352
353cleanupexit:
354  call void @llvm.bar()
355  cleanupret from %cp0 unwind label %cleanup2
356}
357