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 catchpad void [] 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)
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
78 ; CHECK: catchpad void
79 %x = phi i32 [ 1, %left ], [ 2, %right ]
80 catchpad void [] 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 %merge.outer
94 catchendpad unwind label %merge.outer
99 ; CHECK: catchpad void
100 %y = phi i32 [ %x, %catchend.inner ], [ %z, %catch.inner ]
101 catchpad void [] 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 label
121 ; CHECK-LABEL: @test3(
122 define void @test3(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
124 ; need to spill parameter %B and def %x since they're used in a funclet
126 ; CHECK-DAG: store i1 %B, i1* [[SlotB:%[^ ]+]]
127 ; CHECK-DAG: store i32 %x, i32* [[SlotX:%[^ ]+]]
128 ; CHECK: invoke void @f
131 to label %exit unwind label %catchpad
134 catchpad void [] to label %catch unwind label %catchend
137 ; Need to reload %B here
139 ; CHECK: [[ReloadB:%[^ ]+]] = load i1, i1* [[SlotB]]
140 ; CHECK: br i1 [[ReloadB]]
141 br i1 %B, label %left, label %right
143 ; Use of %x is in a phi, so need reload here in pred
145 ; CHECK: [[ReloadX:%[^ ]+]] = load i32, i32* [[SlotX]]
146 ; CHECK: br label %merge
152 ; CHECK: %phi = phi i32 [ [[ReloadX]], %left ]
153 %phi = phi i32 [ %x, %left ], [ 42, %right ]
154 call void @h(i32 %phi)
158 catchendpad unwind to caller
164 ; test4: don't need stores for %phi.inner, as its only use is to feed %phi.outer
165 ; %phi.outer needs stores in %left, %right, and %join
166 ; CHECK-LABEL: @test4(
167 define void @test4(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
170 ; CHECK: [[Slot:%[^ ]+]] = alloca
172 br i1 %B, label %left, label %right
176 ; CHECK: store i32 %l, i32* [[Slot]]
177 ; CHECK-NEXT: invoke void @f
180 to label %join unwind label %catchpad.inner
184 ; CHECK: store i32 %r, i32* [[Slot]]
185 ; CHECK-NEXT: invoke void @f
188 to label %join unwind label %catchpad.inner
190 ; CHECK: catchpad.inner:
191 ; CHECK-NEXT: catchpad void
192 %phi.inner = phi i32 [ %l, %left ], [ %r, %right ]
193 catchpad void [] to label %catch.inner unwind label %catchend.inner
197 catchendpad unwind label %catchpad.outer
201 ; CHECK: store i32 %j, i32* [[Slot]]
202 ; CHECK-NEXT: invoke void @f
205 to label %exit unwind label %catchpad.outer
207 ; CHECK: catchpad.outer:
208 ; CHECK-NEXT: catchpad void
209 %phi.outer = phi i32 [ %phi.inner, %catchend.inner ], [ %j, %join ]
210 catchpad void [] to label %catch.outer unwind label %catchend.outer
212 ; CHECK: catch.outer:
213 ; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]]
214 ; CHECK: call void @h(i32 [[Reload]])
215 call void @h(i32 %phi.outer)
218 catchendpad unwind to caller
223 ; CHECK-LABEL: @test5(
224 define void @test5() personality i32 (...)* @__CxxFrameHandler3 {
226 ; need store for %phi.cleanup
228 ; CHECK: store i32 1, i32* [[CleanupSlot:%[^ ]+]]
229 ; CHECK-NEXT: invoke void @f
231 to label %invoke.cont unwind label %cleanup
234 ; need store for %phi.cleanup
235 ; CHECK: invoke.cont:
236 ; CHECK-NEXT: store i32 2, i32* [[CleanupSlot]]
237 ; CHECK-NEXT: invoke void @f
239 to label %invoke.cont2 unwind label %cleanup
242 ; cleanup phi can be loaded at cleanup entry
244 ; CHECK-NEXT: cleanuppad void
245 ; CHECK: [[CleanupReload:%[^ ]+]] = load i32, i32* [[CleanupSlot]]
246 %phi.cleanup = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]
249 br i1 %b, label %left, label %right
253 ; CHECK: call void @h(i32 [[CleanupReload]]
254 call void @h(i32 %phi.cleanup)
259 ; CHECK: call void @h(i32 [[CleanupReload]]
260 call void @h(i32 %phi.cleanup)
264 ; need store for %phi.catch
266 ; CHECK-NEXT: store i32 [[CleanupReload]], i32* [[CatchSlot:%[^ ]+]]
267 ; CHECK-NEXT: cleanupret void
268 cleanupret void unwind label %catchpad
271 ; need store for %phi.catch
272 ; CHECK: invoke.cont2:
273 ; CHECK-NEXT: store i32 3, i32* [[CatchSlot]]
274 ; CHECK-NEXT: invoke void @f
276 to label %exit unwind label %catchpad
280 ; CHECK-NEXT: catchpad void
281 %phi.catch = phi i32 [ %phi.cleanup, %merge ], [ 3, %invoke.cont2 ]
282 catchpad void [] to label %catch unwind label %catchend
286 ; CHECK: [[CatchReload:%[^ ]+]] = load i32, i32* [[CatchSlot]]
287 ; CHECK: call void @h(i32 [[CatchReload]]
288 call void @h(i32 %phi.catch)
292 catchendpad unwind to caller