[TTI] getTypeBasedIntrinsicInstrCost - add basic handling for strided load/store...
[llvm-project.git] / llvm / test / CodeGen / WinEH / wineh-demotion.ll
blob36a21e29f9c389932dcbaf94abf6ccbe3927a3ae
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(...)
6 declare void @f()
8 declare i32 @g()
10 declare void @h(i32)
12 declare i1 @i()
14 declare void @llvm.bar() nounwind
16 ; CHECK-LABEL: @test1(
17 define void @test1(i1 %B) personality ptr @__CxxFrameHandler3 {
18 entry:
19   ; Spill slot should be inserted here
20   ; CHECK: [[Slot:%[^ ]+]] = alloca
21   ; Can't store for %phi at these defs because the lifetimes overlap
22   ; CHECK-NOT: store
23   %x = call i32 @g()
24   %y = call i32 @g()
25   br i1 %B, label %left, label %right
26 left:
27   ; CHECK: left:
28   ; CHECK-NEXT: store i32 %x, ptr [[Slot]]
29   ; CHECK-NEXT: invoke void @f
30   invoke void @f()
31           to label %exit unwind label %merge
32 right:
33   ; CHECK: right:
34   ; CHECK-NEXT: store i32 %y, ptr [[Slot]]
35   ; CHECK-NEXT: invoke void @f
36   invoke void @f()
37           to label %exit unwind label %merge
38 merge:
39   ; CHECK: merge:
40   ; CHECK-NOT: = phi
41   %phi = phi i32 [ %x, %left ], [ %y, %right ]
42   %cs1 = catchswitch within none [label %catch] unwind to caller
44 catch:
45   %cp = catchpad within %cs1 []
46   ; CHECK: catch:
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
52 exit:
53   ret void
56 ; CHECK-LABEL: @test2(
57 define void @test2(i1 %B) personality ptr @__CxxFrameHandler3 {
58 entry:
59   br i1 %B, label %left, label %right
60 left:
61   ; Need two stores here because %x and %y interfere so they need 2 slots
62   ; CHECK: left:
63   ; CHECK:   store i32 1, ptr [[Slot1:%[^ ]+]]
64   ; CHECK:   store i32 1, ptr [[Slot2:%[^ ]+]]
65   ; CHECK-NEXT: invoke void @f
66   invoke void @f()
67           to label %exit unwind label %merge.inner
68 right:
69   ; Need two stores here because %x and %y interfere so they need 2 slots
70   ; CHECK: right:
71   ; CHECK-DAG:   store i32 2, ptr [[Slot1]]
72   ; CHECK-DAG:   store i32 2, ptr [[Slot2]]
73   ; CHECK: invoke void @f
74   invoke void @f()
75           to label %exit unwind label %merge.inner
76 merge.inner:
77   ; CHECK: merge.inner:
78   ; CHECK-NOT: = phi
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
83 catch.inner:
84   %cpinner = catchpad within %cs1 []
85   ; Need just one store here because only %y is affected
86   ; CHECK: catch.inner:
87   %z = call i32 @g() [ "funclet"(token %cpinner) ]
88   ; CHECK:   store i32 %z
89   ; CHECK-NEXT: invoke void @f
90   invoke void @f() [ "funclet"(token %cpinner) ]
91           to label %catchret.inner unwind label %merge.outer
93 catchret.inner:
94   catchret from %cpinner to label %exit
96 merge.outer:
97   %y = phi i32 [ %x, %merge.inner ], [ %z, %catch.inner ]
98   ; CHECK: merge.outer:
99   ; CHECK-NOT: = phi
100   ; CHECK: catchswitch within none
101   %cs2 = catchswitch within none [label %catch.outer] unwind to caller
103 catch.outer:
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
116 exit:
117   ret void
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 {
124 entry:
125   ; CHECK:      entry:
126   ; CHECK:        [[Slot:%[^ ]+]] = alloca
127   ; CHECK-NEXT:   br
128   br i1 %B, label %left, label %right
129 left:
130   ; CHECK: left:
131   ; CHECK-NOT: store
132   ; CHECK: store i32 %l, ptr [[Slot]]
133   ; CHECK-NEXT: invoke void @f
134   %l = call i32 @g()
135   invoke void @f()
136           to label %join unwind label %catchpad.inner
137 right:
138   ; CHECK: right:
139   ; CHECK-NOT: store
140   ; CHECK: store i32 %r, ptr [[Slot]]
141   ; CHECK-NEXT: invoke void @f
142   %r = call i32 @g()
143   invoke void @f()
144           to label %join unwind label %catchpad.inner
145 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
150 catch.inner:
151    %cp1 = catchpad within %cs1 []
152    catchret from %cp1 to label %join
153 join:
154   ; CHECK: join:
155   ; CHECK-NOT: store
156   ; CHECK: store i32 %j, ptr [[Slot]]
157   ; CHECK-NEXT: invoke void @f
158    %j = call i32 @g()
159    invoke void @f()
160            to label %exit unwind label %catchpad.outer
162 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
167 catch.outer:
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
174 exit:
175    ret void
178 ; CHECK-LABEL: @test5(
179 define void @test5() personality ptr @__CxxFrameHandler3 {
180 entry:
181   ; need store for %phi.cleanup
182   ; CHECK:      entry:
183   ; CHECK:        store i32 1, ptr [[CleanupSlot:%[^ ]+]]
184   ; CHECK-NEXT:   invoke void @f
185   invoke void @f()
186           to label %invoke.cont unwind label %cleanup
188 invoke.cont:
189   ; need store for %phi.cleanup
190   ; CHECK:      invoke.cont:
191   ; CHECK-NEXT:   store i32 2, ptr [[CleanupSlot]]
192   ; CHECK-NEXT:   invoke void @f
193   invoke void @f()
194           to label %invoke.cont2 unwind label %cleanup
196 cleanup:
197   ; cleanup phi can be loaded at cleanup entry
198   ; CHECK: cleanup:
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
206 left:
207   ; CHECK: left:
208   ; CHECK:   call void @h(i32 [[CleanupReload]]
209   call void @h(i32 %phi.cleanup) [ "funclet"(token %cp) ]
210   br label %merge
212 right:
213   ; CHECK: right:
214   ; CHECK:   call void @h(i32 [[CleanupReload]]
215   call void @h(i32 %phi.cleanup) [ "funclet"(token %cp) ]
216   br label %merge
218 merge:
219   ; need store for %phi.catch
220   ; CHECK:      merge:
221   ; CHECK-NEXT:   store i32 [[CleanupReload]], ptr [[CatchSlot:%[^ ]+]]
222   ; CHECK-NEXT:   cleanupret
223   cleanupret from %cp unwind label %catchswitch
225 invoke.cont2:
226   ; need store for %phi.catch
227   ; CHECK:      invoke.cont2:
228   ; CHECK-NEXT:   store i32 3, ptr [[CatchSlot]]
229   ; CHECK-NEXT:   invoke void @f
230   invoke void @f()
231           to label %exit unwind label %catchswitch
233 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
239 catch:
240   ; CHECK: catch:
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
248 exit:
249   ret void
252 ; We used to demote %x, but we don't need to anymore.
253 ; CHECK-LABEL: @test6(
254 define void @test6() personality ptr @__CxxFrameHandler3 {
255 entry:
256   ; CHECK: entry:
257   ; CHECK: %x = invoke i32 @g()
258   ; CHECK-NEXT: to label %loop unwind label %to_caller
259   %x = invoke i32 @g()
260           to label %loop unwind label %to_caller
261 to_caller:
262   %cp1 = cleanuppad within none []
263   cleanupret from %cp1 unwind to caller
264 loop:
265   invoke void @f()
266           to label %loop unwind label %cleanup
267 cleanup:
268   ; CHECK: 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 {
277 entry:
278   ; %x is an EH pad phi, so gets stored in pred here
279   ; CHECK: entry:
280   ; CHECK:   store i32 1, ptr [[SlotX:%[^ ]+]]
281   ; CHECK:   invoke void @f()
282   invoke void @f()
283      to label %invoke.cont unwind label %catchpad
284 invoke.cont:
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()
289   invoke void @f()
290     to label %exit unwind label %catchpad
291 catchpad:
292   ; %x phi should be eliminated
293   ; CHECK: catchpad:
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
297 catch:
298   ; CHECK: catch:
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
303 left:
304   ; Edge from %left to %join needs to be split so that
305   ; the load of %x can be inserted *after* the catchret
306   ; CHECK: left:
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
312 right:
313   ; Edge from %right to %join needs to be split so that
314   ; the load of %y can be inserted *after* the catchret
315   ; CHECK: right:
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
320 join:
321   ; CHECK: join:
322   ; CHECK:   %phi = phi i32 [ [[LoadX]], %[[SplitLeft]] ], [ %y, %right ]
323   %phi = phi i32 [ %x, %left ], [ %y, %right ]
324   call void @h(i32 %phi)
325   br label %exit
326 exit:
327   ret void
330 ; CHECK-LABEL: @test8(
331 define void @test8() personality ptr @__CxxFrameHandler3 { entry:
332   invoke void @f()
333           to label %done unwind label %cleanup1
334   invoke void @f()
335           to label %done unwind label %cleanup2
337 done:
338   ret void
340 cleanup1:
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
347 cleanup2:
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
354 cleanupexit:
355   call void @llvm.bar()
356   cleanupret from %cp0 unwind label %cleanup2