1 ; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s
3 declare i32 @__CxxFrameHandler3(...)
13 ; CHECK-LABEL: @test1(
14 define void @test1(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
16 ; Spill slot should be inserted here
17 ; CHECK: [[Slot:%[^ ]+]] = alloca
18 ; Can't store for %phi at these defs because the lifetimes overlap
22 br i1 %B, label %left, label %right
25 ; CHECK-NEXT: store i32 %x, i32* [[Slot]]
26 ; CHECK-NEXT: invoke void @f
28 to label %exit unwind label %merge
31 ; CHECK-NEXT: store i32 %y, i32* [[Slot]]
32 ; CHECK-NEXT: invoke void @f
34 to label %exit unwind label %merge
38 %phi = phi i32 [ %x, %left ], [ %y, %right ]
39 %cs1 = catchswitch within none [label %catch] unwind to caller
42 %cp = catchpad within %cs1 []
44 ; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]]
45 ; CHECK-NEXT: call void @h(i32 [[Reload]])
46 call void @h(i32 %phi)
47 catchret from %cp to label %exit
53 ; CHECK-LABEL: @test2(
54 define void @test2(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
56 br i1 %B, label %left, label %right
58 ; Need two stores here because %x and %y interfere so they need 2 slots
60 ; CHECK: store i32 1, i32* [[Slot1:%[^ ]+]]
61 ; CHECK: store i32 1, i32* [[Slot2:%[^ ]+]]
62 ; CHECK-NEXT: invoke void @f
64 to label %exit unwind label %merge.inner
66 ; Need two stores here because %x and %y interfere so they need 2 slots
68 ; CHECK-DAG: store i32 2, i32* [[Slot1]]
69 ; CHECK-DAG: store i32 2, i32* [[Slot2]]
70 ; CHECK: invoke void @f
72 to label %exit unwind label %merge.inner
76 ; CHECK: catchswitch within none
77 %x = phi i32 [ 1, %left ], [ 2, %right ]
78 %cs1 = catchswitch within none [label %catch.inner] unwind label %merge.outer
81 %cpinner = catchpad within %cs1 []
82 ; Need just one store here because only %y is affected
86 ; CHECK-NEXT: invoke void @f
88 to label %catchret.inner unwind label %merge.outer
91 catchret from %cpinner to label %exit
94 %y = phi i32 [ %x, %merge.inner ], [ %z, %catch.inner ]
97 ; CHECK: catchswitch within none
98 %cs2 = catchswitch within none [label %catch.outer] unwind to caller
101 %cpouter = catchpad within %cs2 []
102 ; CHECK: catch.outer:
103 ; CHECK: [[CatchPad:%[^ ]+]] = catchpad within %cs2 []
104 ; Need to load x and y from two different slots since they're both live
105 ; and can have different values (if we came from catch.inner)
106 ; CHECK-DAG: load i32, i32* [[Slot1]]
107 ; CHECK-DAG: load i32, i32* [[Slot2]]
108 ; CHECK: catchret from [[CatchPad]] to label
111 catchret from %cpouter to label %exit
117 ; test4: don't need stores for %phi.inner, as its only use is to feed %phi.outer
118 ; %phi.outer needs stores in %left, %right, and %join
119 ; CHECK-LABEL: @test4(
120 define void @test4(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
123 ; CHECK: [[Slot:%[^ ]+]] = alloca
125 br i1 %B, label %left, label %right
129 ; CHECK: store i32 %l, i32* [[Slot]]
130 ; CHECK-NEXT: invoke void @f
133 to label %join unwind label %catchpad.inner
137 ; CHECK: store i32 %r, i32* [[Slot]]
138 ; CHECK-NEXT: invoke void @f
141 to label %join unwind label %catchpad.inner
143 ; CHECK: catchpad.inner:
144 ; CHECK-NEXT: catchswitch within none
145 %phi.inner = phi i32 [ %l, %left ], [ %r, %right ]
146 %cs1 = catchswitch within none [label %catch.inner] unwind label %catchpad.outer
148 %cp1 = catchpad within %cs1 []
149 catchret from %cp1 to label %join
153 ; CHECK: store i32 %j, i32* [[Slot]]
154 ; CHECK-NEXT: invoke void @f
157 to label %exit unwind label %catchpad.outer
160 ; CHECK: catchpad.outer:
161 ; CHECK-NEXT: catchswitch within none
162 %phi.outer = phi i32 [ %phi.inner, %catchpad.inner ], [ %j, %join ]
163 %cs2 = catchswitch within none [label %catch.outer] unwind to caller
165 ; CHECK: catch.outer:
166 ; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]]
167 ; CHECK: call void @h(i32 [[Reload]])
168 %cp2 = catchpad within %cs2 []
169 call void @h(i32 %phi.outer)
170 catchret from %cp2 to label %exit
175 ; CHECK-LABEL: @test5(
176 define void @test5() personality i32 (...)* @__CxxFrameHandler3 {
178 ; need store for %phi.cleanup
180 ; CHECK: store i32 1, i32* [[CleanupSlot:%[^ ]+]]
181 ; CHECK-NEXT: invoke void @f
183 to label %invoke.cont unwind label %cleanup
186 ; need store for %phi.cleanup
187 ; CHECK: invoke.cont:
188 ; CHECK-NEXT: store i32 2, i32* [[CleanupSlot]]
189 ; CHECK-NEXT: invoke void @f
191 to label %invoke.cont2 unwind label %cleanup
194 ; cleanup phi can be loaded at cleanup entry
196 ; CHECK-NEXT: cleanuppad within none []
197 ; CHECK: [[CleanupReload:%[^ ]+]] = load i32, i32* [[CleanupSlot]]
198 %phi.cleanup = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]
199 %cp = cleanuppad within none []
201 br i1 %b, label %left, label %right
205 ; CHECK: call void @h(i32 [[CleanupReload]]
206 call void @h(i32 %phi.cleanup)
211 ; CHECK: call void @h(i32 [[CleanupReload]]
212 call void @h(i32 %phi.cleanup)
216 ; need store for %phi.catch
218 ; CHECK-NEXT: store i32 [[CleanupReload]], i32* [[CatchSlot:%[^ ]+]]
219 ; CHECK-NEXT: cleanupret
220 cleanupret from %cp unwind label %catchswitch
223 ; need store for %phi.catch
224 ; CHECK: invoke.cont2:
225 ; CHECK-NEXT: store i32 3, i32* [[CatchSlot]]
226 ; CHECK-NEXT: invoke void @f
228 to label %exit unwind label %catchswitch
231 ; CHECK: catchswitch:
232 ; CHECK-NEXT: catchswitch within none
233 %phi.catch = phi i32 [ %phi.cleanup, %merge ], [ 3, %invoke.cont2 ]
234 %cs1 = catchswitch within none [label %catch] unwind to caller
238 ; CHECK: catchpad within %cs1
239 ; CHECK: [[CatchReload:%[^ ]+]] = load i32, i32* [[CatchSlot]]
240 ; CHECK: call void @h(i32 [[CatchReload]]
241 %cp2 = catchpad within %cs1 []
242 call void @h(i32 %phi.catch)
243 catchret from %cp2 to label %exit
249 ; We used to demote %x, but we don't need to anymore.
250 ; CHECK-LABEL: @test6(
251 define void @test6() personality i32 (...)* @__CxxFrameHandler3 {
254 ; CHECK: %x = invoke i32 @g()
255 ; CHECK-NEXT: to label %loop unwind label %to_caller
257 to label %loop unwind label %to_caller
259 %cp1 = cleanuppad within none []
260 cleanupret from %cp1 unwind to caller
263 to label %loop unwind label %cleanup
266 ; CHECK: call void @h(i32 %x)
267 %cp2 = cleanuppad within none []
269 cleanupret from %cp2 unwind to caller
272 ; CHECK-LABEL: @test7(
273 define void @test7() personality i32 (...)* @__CxxFrameHandler3 {
275 ; %x is an EH pad phi, so gets stored in pred here
277 ; CHECK: store i32 1, i32* [[SlotX:%[^ ]+]]
278 ; CHECK: invoke void @f()
280 to label %invoke.cont unwind label %catchpad
282 ; %x is an EH pad phi, so gets stored in pred here
283 ; CHECK: invoke.cont:
284 ; CHECK: store i32 2, i32* [[SlotX]]
285 ; CHECK: invoke void @f()
287 to label %exit unwind label %catchpad
289 ; %x phi should be eliminated
291 ; CHECK-NEXT: catchswitch within none
292 %x = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]
293 %cs1 = catchswitch within none [label %catch] unwind to caller
296 ; CHECK-NEXT: %[[CatchPad:[^ ]+]] = catchpad within %cs1 []
297 %cp = catchpad within %cs1 []
299 br i1 %b, label %left, label %right
301 ; Edge from %left to %join needs to be split so that
302 ; the load of %x can be inserted *after* the catchret
304 ; CHECK-NEXT: catchret from %[[CatchPad]] to label %[[SplitLeft:[^ ]+]]
305 catchret from %cp to label %join
306 ; CHECK: [[SplitLeft]]:
307 ; CHECK: [[LoadX:%[^ ]+]] = load i32, i32* [[SlotX]]
308 ; CHECK: br label %join
310 ; Edge from %right to %join needs to be split so that
311 ; the load of %y can be inserted *after* the catchret
313 ; CHECK: %y = call i32 @g()
314 ; CHECK: catchret from %[[CatchPad]] to label %join
316 catchret from %cp to label %join
319 ; CHECK: %phi = phi i32 [ [[LoadX]], %[[SplitLeft]] ], [ %y, %right ]
320 %phi = phi i32 [ %x, %left ], [ %y, %right ]
321 call void @h(i32 %phi)
327 ; CHECK-LABEL: @test8(
328 define void @test8() personality i32 (...)* @__CxxFrameHandler3 { entry:
330 to label %done unwind label %cleanup1
332 to label %done unwind label %cleanup2
338 ; CHECK: [[CleanupPad1:%[^ ]+]] = cleanuppad within none []
339 ; CHECK-NEXT: call void @f()
340 ; CHECK-NEXT: cleanupret from [[CleanupPad1]]
341 %cp0 = cleanuppad within none []
342 br label %cleanupexit
345 ; CHECK: cleanuppad within none []
346 ; CHECK-NEXT: call void @f()
347 ; CHECK-NEXT: unreachable
348 %cp1 = cleanuppad within none []
349 br label %cleanupexit
353 cleanupret from %cp0 unwind label %cleanup2