1 ; RUN: opt -mtriple=x86_x64-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 %cp = catchpad [] to label %catch unwind label %catchend
43 ; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]]
44 ; CHECK-NEXT: call void @h(i32 [[Reload]])
45 call void @h(i32 %phi)
46 catchret %cp to label %exit
49 catchendpad unwind to caller
55 ; CHECK-LABEL: @test2(
56 define void @test2(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
58 br i1 %B, label %left, label %right
60 ; Need two stores here because %x and %y interfere so they need 2 slots
62 ; CHECK: store i32 1, i32* [[Slot1:%[^ ]+]]
63 ; CHECK: store i32 1, i32* [[Slot2:%[^ ]+]]
64 ; CHECK-NEXT: invoke void @f
66 to label %exit unwind label %merge.inner
68 ; Need two stores here because %x and %y interfere so they need 2 slots
70 ; CHECK-DAG: store i32 2, i32* [[Slot1]]
71 ; CHECK-DAG: store i32 2, i32* [[Slot2]]
72 ; CHECK: invoke void @f
74 to label %exit unwind label %merge.inner
79 %x = phi i32 [ 1, %left ], [ 2, %right ]
80 %cpinner = catchpad [] to label %catch.inner unwind label %catchend.inner
83 ; Need just one store here because only %y is affected
87 ; CHECK-NEXT: invoke void @f
89 to label %catchret.inner unwind label %catchend.inner
92 catchret %cpinner to label %exit
95 %y = phi i32 [ %x, %merge.inner ], [ %z, %catch.inner ]
96 catchendpad unwind label %merge.outer
100 ; CHECK: [[CatchPad:%[^ ]+]] = catchpad []
101 %cpouter = catchpad [] to label %catch.outer unwind label %catchend.outer
104 catchendpad unwind to caller
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: catch.outer:
110 ; CHECK-DAG: load i32, i32* [[Slot1]]
111 ; CHECK-DAG: load i32, i32* [[Slot2]]
112 ; CHECK: catchret [[CatchPad]] to label
115 catchret %cpouter to label %exit
121 ; test4: don't need stores for %phi.inner, as its only use is to feed %phi.outer
122 ; %phi.outer needs stores in %left, %right, and %join
123 ; CHECK-LABEL: @test4(
124 define void @test4(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
127 ; CHECK: [[Slot:%[^ ]+]] = alloca
129 br i1 %B, label %left, label %right
133 ; CHECK: store i32 %l, i32* [[Slot]]
134 ; CHECK-NEXT: invoke void @f
137 to label %join unwind label %catchpad.inner
141 ; CHECK: store i32 %r, i32* [[Slot]]
142 ; CHECK-NEXT: invoke void @f
145 to label %join unwind label %catchpad.inner
147 ; CHECK: catchpad.inner:
148 ; CHECK-NEXT: catchpad []
149 %phi.inner = phi i32 [ %l, %left ], [ %r, %right ]
150 %cp1 = catchpad [] to label %catch.inner unwind label %catchend.inner
152 catchret %cp1 to label %join
154 catchendpad unwind label %catchpad.outer
158 ; CHECK: store i32 %j, i32* [[Slot]]
159 ; CHECK-NEXT: invoke void @f
162 to label %exit unwind label %catchpad.outer
164 ; CHECK: catchpad.outer:
165 ; CHECK-NEXT: catchpad []
166 %phi.outer = phi i32 [ %phi.inner, %catchend.inner ], [ %j, %join ]
167 %cp2 = catchpad [] to label %catch.outer unwind label %catchend.outer
169 ; CHECK: catch.outer:
170 ; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]]
171 ; CHECK: call void @h(i32 [[Reload]])
172 call void @h(i32 %phi.outer)
173 catchret %cp2 to label %exit
175 catchendpad unwind to caller
180 ; CHECK-LABEL: @test5(
181 define void @test5() personality i32 (...)* @__CxxFrameHandler3 {
183 ; need store for %phi.cleanup
185 ; CHECK: store i32 1, i32* [[CleanupSlot:%[^ ]+]]
186 ; CHECK-NEXT: invoke void @f
188 to label %invoke.cont unwind label %cleanup
191 ; need store for %phi.cleanup
192 ; CHECK: invoke.cont:
193 ; CHECK-NEXT: store i32 2, i32* [[CleanupSlot]]
194 ; CHECK-NEXT: invoke void @f
196 to label %invoke.cont2 unwind label %cleanup
199 ; cleanup phi can be loaded at cleanup entry
201 ; CHECK-NEXT: cleanuppad []
202 ; CHECK: [[CleanupReload:%[^ ]+]] = load i32, i32* [[CleanupSlot]]
203 %phi.cleanup = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]
206 br i1 %b, label %left, label %right
210 ; CHECK: call void @h(i32 [[CleanupReload]]
211 call void @h(i32 %phi.cleanup)
216 ; CHECK: call void @h(i32 [[CleanupReload]]
217 call void @h(i32 %phi.cleanup)
221 ; need store for %phi.catch
223 ; CHECK-NEXT: store i32 [[CleanupReload]], i32* [[CatchSlot:%[^ ]+]]
224 ; CHECK-NEXT: cleanupret
225 cleanupret %cp unwind label %catchpad
228 ; need store for %phi.catch
229 ; CHECK: invoke.cont2:
230 ; CHECK-NEXT: store i32 3, i32* [[CatchSlot]]
231 ; CHECK-NEXT: invoke void @f
233 to label %exit unwind label %catchpad
237 ; CHECK-NEXT: catchpad []
238 %phi.catch = phi i32 [ %phi.cleanup, %merge ], [ 3, %invoke.cont2 ]
239 %cp2 = catchpad [] to label %catch unwind label %catchend
243 ; CHECK: [[CatchReload:%[^ ]+]] = load i32, i32* [[CatchSlot]]
244 ; CHECK: call void @h(i32 [[CatchReload]]
245 call void @h(i32 %phi.catch)
246 catchret %cp2 to label %exit
249 catchendpad unwind to caller
255 ; We used to demote %x, but we don't need to anymore.
256 ; CHECK-LABEL: @test6(
257 define void @test6() personality i32 (...)* @__CxxFrameHandler3 {
260 ; CHECK: %x = invoke i32 @g()
261 ; CHECK-NEXT: to label %loop unwind label %to_caller
263 to label %loop unwind label %to_caller
266 cleanupret %cp1 unwind to caller
269 to label %loop unwind label %cleanup
272 ; CHECK: call void @h(i32 %x)
275 cleanupret %cp2 unwind to caller
278 ; CHECK-LABEL: @test7(
279 define void @test7() personality i32 (...)* @__CxxFrameHandler3 {
281 ; %x is an EH pad phi, so gets stored in pred here
283 ; CHECK: store i32 1, i32* [[SlotX:%[^ ]+]]
284 ; CHECK: invoke void @f()
286 to label %invoke.cont unwind label %catchpad
288 ; %x is an EH pad phi, so gets stored in pred here
289 ; CHECK: invoke.cont:
290 ; CHECK: store i32 2, i32* [[SlotX]]
291 ; CHECK: invoke void @f()
293 to label %exit unwind label %catchpad
295 ; %x phi should be eliminated
297 ; CHECK-NEXT: %[[CatchPad:[^ ]+]] = catchpad []
298 %x = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]
299 %cp = catchpad [] to label %catch unwind label %catchend
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 %[[CatchPad]] to label %[[SplitLeft:[^ ]+]]
308 catchret %cp to label %join
309 ; CHECK: [[SplitLeft]]:
310 ; CHECK: [[LoadX:%[^ ]+]] = load i32, i32* [[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 %[[CatchPad]] to label %join
319 catchret %cp to label %join
321 catchendpad unwind to caller
324 ; CHECK: %phi = phi i32 [ [[LoadX]], %[[SplitLeft]] ], [ %y, %right ]
325 %phi = phi i32 [ %x, %left ], [ %y, %right ]
326 call void @h(i32 %phi)
332 ; CHECK-LABEL: @test8(
333 define void @test8() personality i32 (...)* @__CxxFrameHandler3 { entry:
335 to label %done unwind label %cleanup1
337 to label %done unwind label %cleanup2
343 ; CHECK: [[CleanupPad1:%[^ ]+]] = cleanuppad []
344 ; CHECK-NEXT: call void @f()
345 ; CHECK-NEXT: cleanupret [[CleanupPad1]]
347 br label %cleanupexit
350 ; CHECK: cleanuppad []
351 ; CHECK-NEXT: call void @f()
352 ; CHECK-NEXT: unreachable
354 br label %cleanupexit
358 cleanupret %cp0 unwind label %cleanup2