wineh-demotion.ll
10.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s
declare i32 @__CxxFrameHandler3(...)
declare void @f()
declare i32 @g()
declare void @h(i32)
declare i1 @i()
declare void @llvm.bar() nounwind
; CHECK-LABEL: @test1(
define void @test1(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
entry:
; Spill slot should be inserted here
; CHECK: [[Slot:%[^ ]+]] = alloca
; Can't store for %phi at these defs because the lifetimes overlap
; CHECK-NOT: store
%x = call i32 @g()
%y = call i32 @g()
br i1 %B, label %left, label %right
left:
; CHECK: left:
; CHECK-NEXT: store i32 %x, i32* [[Slot]]
; CHECK-NEXT: invoke void @f
invoke void @f()
to label %exit unwind label %merge
right:
; CHECK: right:
; CHECK-NEXT: store i32 %y, i32* [[Slot]]
; CHECK-NEXT: invoke void @f
invoke void @f()
to label %exit unwind label %merge
merge:
; CHECK: merge:
; CHECK-NOT: = phi
%phi = phi i32 [ %x, %left ], [ %y, %right ]
%cs1 = catchswitch within none [label %catch] unwind to caller
catch:
%cp = catchpad within %cs1 []
; CHECK: catch:
; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]]
; CHECK-NEXT: call void @h(i32 [[Reload]])
call void @h(i32 %phi) [ "funclet"(token %cp) ]
catchret from %cp to label %exit
exit:
ret void
}
; CHECK-LABEL: @test2(
define void @test2(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
entry:
br i1 %B, label %left, label %right
left:
; Need two stores here because %x and %y interfere so they need 2 slots
; CHECK: left:
; CHECK: store i32 1, i32* [[Slot1:%[^ ]+]]
; CHECK: store i32 1, i32* [[Slot2:%[^ ]+]]
; CHECK-NEXT: invoke void @f
invoke void @f()
to label %exit unwind label %merge.inner
right:
; Need two stores here because %x and %y interfere so they need 2 slots
; CHECK: right:
; CHECK-DAG: store i32 2, i32* [[Slot1]]
; CHECK-DAG: store i32 2, i32* [[Slot2]]
; CHECK: invoke void @f
invoke void @f()
to label %exit unwind label %merge.inner
merge.inner:
; CHECK: merge.inner:
; CHECK-NOT: = phi
; CHECK: catchswitch within none
%x = phi i32 [ 1, %left ], [ 2, %right ]
%cs1 = catchswitch within none [label %catch.inner] unwind label %merge.outer
catch.inner:
%cpinner = catchpad within %cs1 []
; Need just one store here because only %y is affected
; CHECK: catch.inner:
%z = call i32 @g() [ "funclet"(token %cpinner) ]
; CHECK: store i32 %z
; CHECK-NEXT: invoke void @f
invoke void @f() [ "funclet"(token %cpinner) ]
to label %catchret.inner unwind label %merge.outer
catchret.inner:
catchret from %cpinner to label %exit
merge.outer:
%y = phi i32 [ %x, %merge.inner ], [ %z, %catch.inner ]
; CHECK: merge.outer:
; CHECK-NOT: = phi
; CHECK: catchswitch within none
%cs2 = catchswitch within none [label %catch.outer] unwind to caller
catch.outer:
%cpouter = catchpad within %cs2 []
; CHECK: catch.outer:
; CHECK: [[CatchPad:%[^ ]+]] = catchpad within %cs2 []
; Need to load x and y from two different slots since they're both live
; and can have different values (if we came from catch.inner)
; CHECK-DAG: load i32, i32* [[Slot1]]
; CHECK-DAG: load i32, i32* [[Slot2]]
; CHECK: catchret from [[CatchPad]] to label
call void @h(i32 %x) [ "funclet"(token %cpouter) ]
call void @h(i32 %y) [ "funclet"(token %cpouter) ]
catchret from %cpouter to label %exit
exit:
ret void
}
; test4: don't need stores for %phi.inner, as its only use is to feed %phi.outer
; %phi.outer needs stores in %left, %right, and %join
; CHECK-LABEL: @test4(
define void @test4(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
entry:
; CHECK: entry:
; CHECK: [[Slot:%[^ ]+]] = alloca
; CHECK-NEXT: br
br i1 %B, label %left, label %right
left:
; CHECK: left:
; CHECK-NOT: store
; CHECK: store i32 %l, i32* [[Slot]]
; CHECK-NEXT: invoke void @f
%l = call i32 @g()
invoke void @f()
to label %join unwind label %catchpad.inner
right:
; CHECK: right:
; CHECK-NOT: store
; CHECK: store i32 %r, i32* [[Slot]]
; CHECK-NEXT: invoke void @f
%r = call i32 @g()
invoke void @f()
to label %join unwind label %catchpad.inner
catchpad.inner:
; CHECK: catchpad.inner:
; CHECK-NEXT: catchswitch within none
%phi.inner = phi i32 [ %l, %left ], [ %r, %right ]
%cs1 = catchswitch within none [label %catch.inner] unwind label %catchpad.outer
catch.inner:
%cp1 = catchpad within %cs1 []
catchret from %cp1 to label %join
join:
; CHECK: join:
; CHECK-NOT: store
; CHECK: store i32 %j, i32* [[Slot]]
; CHECK-NEXT: invoke void @f
%j = call i32 @g()
invoke void @f()
to label %exit unwind label %catchpad.outer
catchpad.outer:
; CHECK: catchpad.outer:
; CHECK-NEXT: catchswitch within none
%phi.outer = phi i32 [ %phi.inner, %catchpad.inner ], [ %j, %join ]
%cs2 = catchswitch within none [label %catch.outer] unwind to caller
catch.outer:
; CHECK: catch.outer:
; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]]
; CHECK: call void @h(i32 [[Reload]])
%cp2 = catchpad within %cs2 []
call void @h(i32 %phi.outer) [ "funclet"(token %cp2) ]
catchret from %cp2 to label %exit
exit:
ret void
}
; CHECK-LABEL: @test5(
define void @test5() personality i32 (...)* @__CxxFrameHandler3 {
entry:
; need store for %phi.cleanup
; CHECK: entry:
; CHECK: store i32 1, i32* [[CleanupSlot:%[^ ]+]]
; CHECK-NEXT: invoke void @f
invoke void @f()
to label %invoke.cont unwind label %cleanup
invoke.cont:
; need store for %phi.cleanup
; CHECK: invoke.cont:
; CHECK-NEXT: store i32 2, i32* [[CleanupSlot]]
; CHECK-NEXT: invoke void @f
invoke void @f()
to label %invoke.cont2 unwind label %cleanup
cleanup:
; cleanup phi can be loaded at cleanup entry
; CHECK: cleanup:
; CHECK-NEXT: cleanuppad within none []
; CHECK: [[CleanupReload:%[^ ]+]] = load i32, i32* [[CleanupSlot]]
%phi.cleanup = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]
%cp = cleanuppad within none []
%b = call i1 @i() [ "funclet"(token %cp) ]
br i1 %b, label %left, label %right
left:
; CHECK: left:
; CHECK: call void @h(i32 [[CleanupReload]]
call void @h(i32 %phi.cleanup) [ "funclet"(token %cp) ]
br label %merge
right:
; CHECK: right:
; CHECK: call void @h(i32 [[CleanupReload]]
call void @h(i32 %phi.cleanup) [ "funclet"(token %cp) ]
br label %merge
merge:
; need store for %phi.catch
; CHECK: merge:
; CHECK-NEXT: store i32 [[CleanupReload]], i32* [[CatchSlot:%[^ ]+]]
; CHECK-NEXT: cleanupret
cleanupret from %cp unwind label %catchswitch
invoke.cont2:
; need store for %phi.catch
; CHECK: invoke.cont2:
; CHECK-NEXT: store i32 3, i32* [[CatchSlot]]
; CHECK-NEXT: invoke void @f
invoke void @f()
to label %exit unwind label %catchswitch
catchswitch:
; CHECK: catchswitch:
; CHECK-NEXT: catchswitch within none
%phi.catch = phi i32 [ %phi.cleanup, %merge ], [ 3, %invoke.cont2 ]
%cs1 = catchswitch within none [label %catch] unwind to caller
catch:
; CHECK: catch:
; CHECK: catchpad within %cs1
; CHECK: [[CatchReload:%[^ ]+]] = load i32, i32* [[CatchSlot]]
; CHECK: call void @h(i32 [[CatchReload]]
%cp2 = catchpad within %cs1 []
call void @h(i32 %phi.catch) [ "funclet"(token %cp2) ]
catchret from %cp2 to label %exit
exit:
ret void
}
; We used to demote %x, but we don't need to anymore.
; CHECK-LABEL: @test6(
define void @test6() personality i32 (...)* @__CxxFrameHandler3 {
entry:
; CHECK: entry:
; CHECK: %x = invoke i32 @g()
; CHECK-NEXT: to label %loop unwind label %to_caller
%x = invoke i32 @g()
to label %loop unwind label %to_caller
to_caller:
%cp1 = cleanuppad within none []
cleanupret from %cp1 unwind to caller
loop:
invoke void @f()
to label %loop unwind label %cleanup
cleanup:
; CHECK: cleanup:
; CHECK: call void @h(i32 %x)
%cp2 = cleanuppad within none []
call void @h(i32 %x) [ "funclet"(token %cp2) ]
cleanupret from %cp2 unwind to caller
}
; CHECK-LABEL: @test7(
define void @test7() personality i32 (...)* @__CxxFrameHandler3 {
entry:
; %x is an EH pad phi, so gets stored in pred here
; CHECK: entry:
; CHECK: store i32 1, i32* [[SlotX:%[^ ]+]]
; CHECK: invoke void @f()
invoke void @f()
to label %invoke.cont unwind label %catchpad
invoke.cont:
; %x is an EH pad phi, so gets stored in pred here
; CHECK: invoke.cont:
; CHECK: store i32 2, i32* [[SlotX]]
; CHECK: invoke void @f()
invoke void @f()
to label %exit unwind label %catchpad
catchpad:
; %x phi should be eliminated
; CHECK: catchpad:
; CHECK-NEXT: catchswitch within none
%x = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]
%cs1 = catchswitch within none [label %catch] unwind to caller
catch:
; CHECK: catch:
; CHECK-NEXT: %[[CatchPad:[^ ]+]] = catchpad within %cs1 []
%cp = catchpad within %cs1 []
%b = call i1 @i() [ "funclet"(token %cp) ]
br i1 %b, label %left, label %right
left:
; Edge from %left to %join needs to be split so that
; the load of %x can be inserted *after* the catchret
; CHECK: left:
; CHECK-NEXT: catchret from %[[CatchPad]] to label %[[SplitLeft:[^ ]+]]
catchret from %cp to label %join
; CHECK: [[SplitLeft]]:
; CHECK: [[LoadX:%[^ ]+]] = load i32, i32* [[SlotX]]
; CHECK: br label %join
right:
; Edge from %right to %join needs to be split so that
; the load of %y can be inserted *after* the catchret
; CHECK: right:
; CHECK: %y = call i32 @g()
; CHECK: catchret from %[[CatchPad]] to label %join
%y = call i32 @g() [ "funclet"(token %cp) ]
catchret from %cp to label %join
join:
; CHECK: join:
; CHECK: %phi = phi i32 [ [[LoadX]], %[[SplitLeft]] ], [ %y, %right ]
%phi = phi i32 [ %x, %left ], [ %y, %right ]
call void @h(i32 %phi)
br label %exit
exit:
ret void
}
; CHECK-LABEL: @test8(
define void @test8() personality i32 (...)* @__CxxFrameHandler3 { entry:
invoke void @f()
to label %done unwind label %cleanup1
invoke void @f()
to label %done unwind label %cleanup2
done:
ret void
cleanup1:
; CHECK: [[CleanupPad1:%[^ ]+]] = cleanuppad within none []
; CHECK-NEXT: call void @llvm.bar()
; CHECK-NEXT: cleanupret from [[CleanupPad1]]
%cp0 = cleanuppad within none []
br label %cleanupexit
cleanup2:
; CHECK: cleanuppad within none []
; CHECK-NEXT: call void @llvm.bar()
; CHECK-NEXT: unreachable
%cp1 = cleanuppad within none []
br label %cleanupexit
cleanupexit:
call void @llvm.bar()
cleanupret from %cp0 unwind label %cleanup2
}