1 ; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -win-eh-prepare < %s | FileCheck %s
2 ; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -passes=win-eh-prepare < %s | FileCheck %s
4 declare i32 @__CxxFrameHandler3(...)
14 declare void @llvm.bar() nounwind
16 ; CHECK-LABEL: @test1(
17 define void @test1(i1 %B) personality ptr @__CxxFrameHandler3 {
19 ; Spill slot should be inserted here
20 ; CHECK: [[Slot:%[^ ]+]] = alloca
21 ; Can't store for %phi at these defs because the lifetimes overlap
25 br i1 %B, label %left, label %right
28 ; CHECK-NEXT: store i32 %x, ptr [[Slot]]
29 ; CHECK-NEXT: invoke void @f
31 to label %exit unwind label %merge
34 ; CHECK-NEXT: store i32 %y, ptr [[Slot]]
35 ; CHECK-NEXT: invoke void @f
37 to label %exit unwind label %merge
41 %phi = phi i32 [ %x, %left ], [ %y, %right ]
42 %cs1 = catchswitch within none [label %catch] unwind to caller
45 %cp = catchpad within %cs1 []
47 ; CHECK: [[Reload:%[^ ]+]] = load i32, ptr [[Slot]]
48 ; CHECK-NEXT: call void @h(i32 [[Reload]])
49 call void @h(i32 %phi) [ "funclet"(token %cp) ]
50 catchret from %cp to label %exit
56 ; CHECK-LABEL: @test2(
57 define void @test2(i1 %B) personality ptr @__CxxFrameHandler3 {
59 br i1 %B, label %left, label %right
61 ; Need two stores here because %x and %y interfere so they need 2 slots
63 ; CHECK: store i32 1, ptr [[Slot1:%[^ ]+]]
64 ; CHECK: store i32 1, ptr [[Slot2:%[^ ]+]]
65 ; CHECK-NEXT: invoke void @f
67 to label %exit unwind label %merge.inner
69 ; Need two stores here because %x and %y interfere so they need 2 slots
71 ; CHECK-DAG: store i32 2, ptr [[Slot1]]
72 ; CHECK-DAG: store i32 2, ptr [[Slot2]]
73 ; CHECK: invoke void @f
75 to label %exit unwind label %merge.inner
79 ; CHECK: catchswitch within none
80 %x = phi i32 [ 1, %left ], [ 2, %right ]
81 %cs1 = catchswitch within none [label %catch.inner] unwind label %merge.outer
84 %cpinner = catchpad within %cs1 []
85 ; Need just one store here because only %y is affected
87 %z = call i32 @g() [ "funclet"(token %cpinner) ]
89 ; CHECK-NEXT: invoke void @f
90 invoke void @f() [ "funclet"(token %cpinner) ]
91 to label %catchret.inner unwind label %merge.outer
94 catchret from %cpinner to label %exit
97 %y = phi i32 [ %x, %merge.inner ], [ %z, %catch.inner ]
100 ; CHECK: catchswitch within none
101 %cs2 = catchswitch within none [label %catch.outer] unwind to caller
104 %cpouter = catchpad within %cs2 []
105 ; CHECK: catch.outer:
106 ; CHECK: [[CatchPad:%[^ ]+]] = catchpad within %cs2 []
107 ; Need to load x and y from two different slots since they're both live
108 ; and can have different values (if we came from catch.inner)
109 ; CHECK-DAG: load i32, ptr [[Slot1]]
110 ; CHECK-DAG: load i32, ptr [[Slot2]]
111 ; CHECK: catchret from [[CatchPad]] to label
112 call void @h(i32 %x) [ "funclet"(token %cpouter) ]
113 call void @h(i32 %y) [ "funclet"(token %cpouter) ]
114 catchret from %cpouter to label %exit
120 ; test4: don't need stores for %phi.inner, as its only use is to feed %phi.outer
121 ; %phi.outer needs stores in %left, %right, and %join
122 ; CHECK-LABEL: @test4(
123 define void @test4(i1 %B) personality ptr @__CxxFrameHandler3 {
126 ; CHECK: [[Slot:%[^ ]+]] = alloca
128 br i1 %B, label %left, label %right
132 ; CHECK: store i32 %l, ptr [[Slot]]
133 ; CHECK-NEXT: invoke void @f
136 to label %join unwind label %catchpad.inner
140 ; CHECK: store i32 %r, ptr [[Slot]]
141 ; CHECK-NEXT: invoke void @f
144 to label %join unwind label %catchpad.inner
146 ; CHECK: catchpad.inner:
147 ; CHECK-NEXT: catchswitch within none
148 %phi.inner = phi i32 [ %l, %left ], [ %r, %right ]
149 %cs1 = catchswitch within none [label %catch.inner] unwind label %catchpad.outer
151 %cp1 = catchpad within %cs1 []
152 catchret from %cp1 to label %join
156 ; CHECK: store i32 %j, ptr [[Slot]]
157 ; CHECK-NEXT: invoke void @f
160 to label %exit unwind label %catchpad.outer
163 ; CHECK: catchpad.outer:
164 ; CHECK-NEXT: catchswitch within none
165 %phi.outer = phi i32 [ %phi.inner, %catchpad.inner ], [ %j, %join ]
166 %cs2 = catchswitch within none [label %catch.outer] unwind to caller
168 ; CHECK: catch.outer:
169 ; CHECK: [[Reload:%[^ ]+]] = load i32, ptr [[Slot]]
170 ; CHECK: call void @h(i32 [[Reload]])
171 %cp2 = catchpad within %cs2 []
172 call void @h(i32 %phi.outer) [ "funclet"(token %cp2) ]
173 catchret from %cp2 to label %exit
178 ; CHECK-LABEL: @test5(
179 define void @test5() personality ptr @__CxxFrameHandler3 {
181 ; need store for %phi.cleanup
183 ; CHECK: store i32 1, ptr [[CleanupSlot:%[^ ]+]]
184 ; CHECK-NEXT: invoke void @f
186 to label %invoke.cont unwind label %cleanup
189 ; need store for %phi.cleanup
190 ; CHECK: invoke.cont:
191 ; CHECK-NEXT: store i32 2, ptr [[CleanupSlot]]
192 ; CHECK-NEXT: invoke void @f
194 to label %invoke.cont2 unwind label %cleanup
197 ; cleanup phi can be loaded at cleanup entry
199 ; CHECK-NEXT: cleanuppad within none []
200 ; CHECK: [[CleanupReload:%[^ ]+]] = load i32, ptr [[CleanupSlot]]
201 %phi.cleanup = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]
202 %cp = cleanuppad within none []
203 %b = call i1 @i() [ "funclet"(token %cp) ]
204 br i1 %b, label %left, label %right
208 ; CHECK: call void @h(i32 [[CleanupReload]]
209 call void @h(i32 %phi.cleanup) [ "funclet"(token %cp) ]
214 ; CHECK: call void @h(i32 [[CleanupReload]]
215 call void @h(i32 %phi.cleanup) [ "funclet"(token %cp) ]
219 ; need store for %phi.catch
221 ; CHECK-NEXT: store i32 [[CleanupReload]], ptr [[CatchSlot:%[^ ]+]]
222 ; CHECK-NEXT: cleanupret
223 cleanupret from %cp unwind label %catchswitch
226 ; need store for %phi.catch
227 ; CHECK: invoke.cont2:
228 ; CHECK-NEXT: store i32 3, ptr [[CatchSlot]]
229 ; CHECK-NEXT: invoke void @f
231 to label %exit unwind label %catchswitch
234 ; CHECK: catchswitch:
235 ; CHECK-NEXT: catchswitch within none
236 %phi.catch = phi i32 [ %phi.cleanup, %merge ], [ 3, %invoke.cont2 ]
237 %cs1 = catchswitch within none [label %catch] unwind to caller
241 ; CHECK: catchpad within %cs1
242 ; CHECK: [[CatchReload:%[^ ]+]] = load i32, ptr [[CatchSlot]]
243 ; CHECK: call void @h(i32 [[CatchReload]]
244 %cp2 = catchpad within %cs1 []
245 call void @h(i32 %phi.catch) [ "funclet"(token %cp2) ]
246 catchret from %cp2 to label %exit
252 ; We used to demote %x, but we don't need to anymore.
253 ; CHECK-LABEL: @test6(
254 define void @test6() personality ptr @__CxxFrameHandler3 {
257 ; CHECK: %x = invoke i32 @g()
258 ; CHECK-NEXT: to label %loop unwind label %to_caller
260 to label %loop unwind label %to_caller
262 %cp1 = cleanuppad within none []
263 cleanupret from %cp1 unwind to caller
266 to label %loop unwind label %cleanup
269 ; CHECK: call void @h(i32 %x)
270 %cp2 = cleanuppad within none []
271 call void @h(i32 %x) [ "funclet"(token %cp2) ]
272 cleanupret from %cp2 unwind to caller
275 ; CHECK-LABEL: @test7(
276 define void @test7() personality ptr @__CxxFrameHandler3 {
278 ; %x is an EH pad phi, so gets stored in pred here
280 ; CHECK: store i32 1, ptr [[SlotX:%[^ ]+]]
281 ; CHECK: invoke void @f()
283 to label %invoke.cont unwind label %catchpad
285 ; %x is an EH pad phi, so gets stored in pred here
286 ; CHECK: invoke.cont:
287 ; CHECK: store i32 2, ptr [[SlotX]]
288 ; CHECK: invoke void @f()
290 to label %exit unwind label %catchpad
292 ; %x phi should be eliminated
294 ; CHECK-NEXT: catchswitch within none
295 %x = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]
296 %cs1 = catchswitch within none [label %catch] unwind to caller
299 ; CHECK-NEXT: %[[CatchPad:[^ ]+]] = catchpad within %cs1 []
300 %cp = catchpad within %cs1 []
301 %b = call i1 @i() [ "funclet"(token %cp) ]
302 br i1 %b, label %left, label %right
304 ; Edge from %left to %join needs to be split so that
305 ; the load of %x can be inserted *after* the catchret
307 ; CHECK-NEXT: catchret from %[[CatchPad]] to label %[[SplitLeft:[^ ]+]]
308 catchret from %cp to label %join
309 ; CHECK: [[SplitLeft]]:
310 ; CHECK: [[LoadX:%[^ ]+]] = load i32, ptr [[SlotX]]
311 ; CHECK: br label %join
313 ; Edge from %right to %join needs to be split so that
314 ; the load of %y can be inserted *after* the catchret
316 ; CHECK: %y = call i32 @g()
317 ; CHECK: catchret from %[[CatchPad]] to label %join
318 %y = call i32 @g() [ "funclet"(token %cp) ]
319 catchret from %cp to label %join
322 ; CHECK: %phi = phi i32 [ [[LoadX]], %[[SplitLeft]] ], [ %y, %right ]
323 %phi = phi i32 [ %x, %left ], [ %y, %right ]
324 call void @h(i32 %phi)
330 ; CHECK-LABEL: @test8(
331 define void @test8() personality ptr @__CxxFrameHandler3 { entry:
333 to label %done unwind label %cleanup1
335 to label %done unwind label %cleanup2
341 ; CHECK: [[CleanupPad1:%[^ ]+]] = cleanuppad within none []
342 ; CHECK-NEXT: call void @llvm.bar()
343 ; CHECK-NEXT: cleanupret from [[CleanupPad1]]
344 %cp0 = cleanuppad within none []
345 br label %cleanupexit
348 ; CHECK: cleanuppad within none []
349 ; CHECK-NEXT: call void @llvm.bar()
350 ; CHECK-NEXT: unreachable
351 %cp1 = cleanuppad within none []
352 br label %cleanupexit
355 call void @llvm.bar()
356 cleanupret from %cp0 unwind label %cleanup2