xref: /llvm-project/llvm/test/Transforms/DivRemPairs/X86/div-rem-pairs.ll (revision 88e85aa580062c0f2b5882eef71bed498a6af159)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=div-rem-pairs -S -mtriple=x86_64-unknown-unknown    | FileCheck %s
3
4declare void @foo(i32, i32)
5
6define void @decompose_illegal_srem_same_block(i32 %a, i32 %b) {
7; CHECK-LABEL: @decompose_illegal_srem_same_block(
8; CHECK-NEXT:    [[REM:%.*]] = srem i32 [[A:%.*]], [[B:%.*]]
9; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 [[A]], [[B]]
10; CHECK-NEXT:    call void @foo(i32 [[REM]], i32 [[DIV]])
11; CHECK-NEXT:    ret void
12;
13  %rem = srem i32 %a, %b
14  %div = sdiv i32 %a, %b
15  call void @foo(i32 %rem, i32 %div)
16  ret void
17}
18
19define void @decompose_illegal_urem_same_block(i32 %a, i32 %b) {
20; CHECK-LABEL: @decompose_illegal_urem_same_block(
21; CHECK-NEXT:    [[DIV:%.*]] = udiv i32 [[A:%.*]], [[B:%.*]]
22; CHECK-NEXT:    [[REM:%.*]] = urem i32 [[A]], [[B]]
23; CHECK-NEXT:    call void @foo(i32 [[REM]], i32 [[DIV]])
24; CHECK-NEXT:    ret void
25;
26  %div = udiv i32 %a, %b
27  %rem = urem i32 %a, %b
28  call void @foo(i32 %rem, i32 %div)
29  ret void
30}
31
32; Hoist and optionally decompose the sdiv because it's safe and free.
33; PR31028 - https://bugs.llvm.org/show_bug.cgi?id=31028
34
35define i32 @hoist_sdiv(i32 %a, i32 %b) {
36; CHECK-LABEL: @hoist_sdiv(
37; CHECK-NEXT:  entry:
38; CHECK-NEXT:    [[REM:%.*]] = srem i32 [[A:%.*]], [[B:%.*]]
39; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 [[A]], [[B]]
40; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[REM]], 42
41; CHECK-NEXT:    br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
42; CHECK:       if:
43; CHECK-NEXT:    br label [[END]]
44; CHECK:       end:
45; CHECK-NEXT:    [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
46; CHECK-NEXT:    ret i32 [[RET]]
47;
48entry:
49  %rem = srem i32 %a, %b
50  %cmp = icmp eq i32 %rem, 42
51  br i1 %cmp, label %if, label %end
52
53if:
54  %div = sdiv i32 %a, %b
55  br label %end
56
57end:
58  %ret = phi i32 [ %div, %if ], [ 3, %entry ]
59  ret i32 %ret
60}
61
62; Hoist and optionally decompose the udiv because it's safe and free.
63
64define i64 @hoist_udiv(i64 %a, i64 %b) {
65; CHECK-LABEL: @hoist_udiv(
66; CHECK-NEXT:  entry:
67; CHECK-NEXT:    [[REM:%.*]] = urem i64 [[A:%.*]], [[B:%.*]]
68; CHECK-NEXT:    [[DIV:%.*]] = udiv i64 [[A]], [[B]]
69; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 [[REM]], 42
70; CHECK-NEXT:    br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
71; CHECK:       if:
72; CHECK-NEXT:    br label [[END]]
73; CHECK:       end:
74; CHECK-NEXT:    [[RET:%.*]] = phi i64 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
75; CHECK-NEXT:    ret i64 [[RET]]
76;
77entry:
78  %rem = urem i64 %a, %b
79  %cmp = icmp eq i64 %rem, 42
80  br i1 %cmp, label %if, label %end
81
82if:
83  %div = udiv i64 %a, %b
84  br label %end
85
86end:
87  %ret = phi i64 [ %div, %if ], [ 3, %entry ]
88  ret i64 %ret
89}
90
91; Hoist the srem if it's safe and free, otherwise decompose it.
92
93define i16 @hoist_srem(i16 %a, i16 %b) {
94; CHECK-LABEL: @hoist_srem(
95; CHECK-NEXT:  entry:
96; CHECK-NEXT:    [[DIV:%.*]] = sdiv i16 [[A:%.*]], [[B:%.*]]
97; CHECK-NEXT:    [[REM:%.*]] = srem i16 [[A]], [[B]]
98; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i16 [[DIV]], 42
99; CHECK-NEXT:    br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
100; CHECK:       if:
101; CHECK-NEXT:    br label [[END]]
102; CHECK:       end:
103; CHECK-NEXT:    [[RET:%.*]] = phi i16 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
104; CHECK-NEXT:    ret i16 [[RET]]
105;
106entry:
107  %div = sdiv i16 %a, %b
108  %cmp = icmp eq i16 %div, 42
109  br i1 %cmp, label %if, label %end
110
111if:
112  %rem = srem i16 %a, %b
113  br label %end
114
115end:
116  %ret = phi i16 [ %rem, %if ], [ 3, %entry ]
117  ret i16 %ret
118}
119
120; Hoist the urem if it's safe and free, otherwise decompose it.
121
122define i8 @hoist_urem(i8 %a, i8 %b) {
123; CHECK-LABEL: @hoist_urem(
124; CHECK-NEXT:  entry:
125; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[A:%.*]], [[B:%.*]]
126; CHECK-NEXT:    [[REM:%.*]] = urem i8 [[A]], [[B]]
127; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[DIV]], 42
128; CHECK-NEXT:    br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
129; CHECK:       if:
130; CHECK-NEXT:    br label [[END]]
131; CHECK:       end:
132; CHECK-NEXT:    [[RET:%.*]] = phi i8 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
133; CHECK-NEXT:    ret i8 [[RET]]
134;
135entry:
136  %div = udiv i8 %a, %b
137  %cmp = icmp eq i8 %div, 42
138  br i1 %cmp, label %if, label %end
139
140if:
141  %rem = urem i8 %a, %b
142  br label %end
143
144end:
145  %ret = phi i8 [ %rem, %if ], [ 3, %entry ]
146  ret i8 %ret
147}
148
149; Be careful with RAUW/invalidation if this is a srem-of-srem.
150
151define i32 @srem_of_srem_unexpanded(i32 %X, i32 %Y, i32 %Z) {
152; CHECK-LABEL: @srem_of_srem_unexpanded(
153; CHECK-NEXT:    [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]]
154; CHECK-NEXT:    [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]]
155; CHECK-NEXT:    [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]]
156; CHECK-NEXT:    [[T3:%.*]] = srem i32 [[X]], [[T0]]
157; CHECK-NEXT:    [[T4:%.*]] = sdiv i32 [[T3]], [[Y]]
158; CHECK-NEXT:    [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]]
159; CHECK-NEXT:    [[T6:%.*]] = srem i32 [[T3]], [[Y]]
160; CHECK-NEXT:    ret i32 [[T6]]
161;
162  %t0 = mul nsw i32 %Z, %Y
163  %t1 = sdiv i32 %X, %t0
164  %t2 = mul nsw i32 %t0, %t1
165  %t3 = srem i32 %X, %t0
166  %t4 = sdiv i32 %t3, %Y
167  %t5 = mul nsw i32 %t4, %Y
168  %t6 = srem i32 %t3, %Y
169  ret i32 %t6
170}
171define i32 @srem_of_srem_expanded(i32 %X, i32 %Y, i32 %Z) {
172; CHECK-LABEL: @srem_of_srem_expanded(
173; CHECK-NEXT:    [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]]
174; CHECK-NEXT:    [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]]
175; CHECK-NEXT:    [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]]
176; CHECK-NEXT:    [[T3_RECOMPOSED:%.*]] = srem i32 [[X]], [[T0]]
177; CHECK-NEXT:    [[T4:%.*]] = sdiv i32 [[T3_RECOMPOSED]], [[Y]]
178; CHECK-NEXT:    [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]]
179; CHECK-NEXT:    [[T6_RECOMPOSED:%.*]] = srem i32 [[T3_RECOMPOSED]], [[Y]]
180; CHECK-NEXT:    ret i32 [[T6_RECOMPOSED]]
181;
182  %t0 = mul nsw i32 %Z, %Y
183  %t1 = sdiv i32 %X, %t0
184  %t2 = mul nsw i32 %t0, %t1
185  %t3 = sub nsw i32 %X, %t2
186  %t4 = sdiv i32 %t3, %Y
187  %t5 = mul nsw i32 %t4, %Y
188  %t6 = sub nsw i32 %t3, %t5
189  ret i32 %t6
190}
191
192; If the ops don't match, don't do anything: signedness.
193
194define i32 @dont_hoist_udiv(i32 %a, i32 %b) {
195; CHECK-LABEL: @dont_hoist_udiv(
196; CHECK-NEXT:  entry:
197; CHECK-NEXT:    [[REM:%.*]] = srem i32 [[A:%.*]], [[B:%.*]]
198; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[REM]], 42
199; CHECK-NEXT:    br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
200; CHECK:       if:
201; CHECK-NEXT:    [[DIV:%.*]] = udiv i32 [[A]], [[B]]
202; CHECK-NEXT:    br label [[END]]
203; CHECK:       end:
204; CHECK-NEXT:    [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
205; CHECK-NEXT:    ret i32 [[RET]]
206;
207entry:
208  %rem = srem i32 %a, %b
209  %cmp = icmp eq i32 %rem, 42
210  br i1 %cmp, label %if, label %end
211
212if:
213  %div = udiv i32 %a, %b
214  br label %end
215
216end:
217  %ret = phi i32 [ %div, %if ], [ 3, %entry ]
218  ret i32 %ret
219}
220
221; If the ops don't match, don't do anything: operation.
222
223define i32 @dont_hoist_srem(i32 %a, i32 %b) {
224; CHECK-LABEL: @dont_hoist_srem(
225; CHECK-NEXT:  entry:
226; CHECK-NEXT:    [[REM:%.*]] = urem i32 [[A:%.*]], [[B:%.*]]
227; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[REM]], 42
228; CHECK-NEXT:    br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
229; CHECK:       if:
230; CHECK-NEXT:    [[REM2:%.*]] = srem i32 [[A]], [[B]]
231; CHECK-NEXT:    br label [[END]]
232; CHECK:       end:
233; CHECK-NEXT:    [[RET:%.*]] = phi i32 [ [[REM2]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
234; CHECK-NEXT:    ret i32 [[RET]]
235;
236entry:
237  %rem = urem i32 %a, %b
238  %cmp = icmp eq i32 %rem, 42
239  br i1 %cmp, label %if, label %end
240
241if:
242  %rem2 = srem i32 %a, %b
243  br label %end
244
245end:
246  %ret = phi i32 [ %rem2, %if ], [ 3, %entry ]
247  ret i32 %ret
248}
249
250; If the ops don't match, don't do anything: operands.
251
252define i32 @dont_hoist_sdiv(i32 %a, i32 %b, i32 %c) {
253; CHECK-LABEL: @dont_hoist_sdiv(
254; CHECK-NEXT:  entry:
255; CHECK-NEXT:    [[REM:%.*]] = srem i32 [[A:%.*]], [[B:%.*]]
256; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[REM]], 42
257; CHECK-NEXT:    br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
258; CHECK:       if:
259; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 [[A]], [[C:%.*]]
260; CHECK-NEXT:    br label [[END]]
261; CHECK:       end:
262; CHECK-NEXT:    [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
263; CHECK-NEXT:    ret i32 [[RET]]
264;
265entry:
266  %rem = srem i32 %a, %b
267  %cmp = icmp eq i32 %rem, 42
268  br i1 %cmp, label %if, label %end
269
270if:
271  %div = sdiv i32 %a, %c
272  br label %end
273
274end:
275  %ret = phi i32 [ %div, %if ], [ 3, %entry ]
276  ret i32 %ret
277}
278
279; If the target doesn't have a unified div/rem op for the type, decompose rem in-place to mul+sub.
280
281define i128 @dont_hoist_urem(i128 %a, i128 %b) {
282; CHECK-LABEL: @dont_hoist_urem(
283; CHECK-NEXT:  entry:
284; CHECK-NEXT:    [[A_FROZEN:%.*]] = freeze i128 [[A:%.*]]
285; CHECK-NEXT:    [[B_FROZEN:%.*]] = freeze i128 [[B:%.*]]
286; CHECK-NEXT:    [[DIV:%.*]] = udiv i128 [[A_FROZEN]], [[B_FROZEN]]
287; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i128 [[DIV]], 42
288; CHECK-NEXT:    br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
289; CHECK:       if:
290; CHECK-NEXT:    [[TMP0:%.*]] = mul i128 [[DIV]], [[B_FROZEN]]
291; CHECK-NEXT:    [[REM_DECOMPOSED:%.*]] = sub i128 [[A_FROZEN]], [[TMP0]]
292; CHECK-NEXT:    br label [[END]]
293; CHECK:       end:
294; CHECK-NEXT:    [[RET:%.*]] = phi i128 [ [[REM_DECOMPOSED]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
295; CHECK-NEXT:    ret i128 [[RET]]
296;
297entry:
298  %div = udiv i128 %a, %b
299  %cmp = icmp eq i128 %div, 42
300  br i1 %cmp, label %if, label %end
301
302if:
303  %rem = urem i128 %a, %b
304  br label %end
305
306end:
307  %ret = phi i128 [ %rem, %if ], [ 3, %entry ]
308  ret i128 %ret
309}
310
311; Hoist both ops to the common predecessor block.
312
313define i32 @no_domination(i1 %cmp, i32 %a, i32 %b) {
314; CHECK-LABEL: @no_domination(
315; CHECK-NEXT:  entry:
316; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]]
317; CHECK-NEXT:    [[REM:%.*]] = srem i32 [[A]], [[B]]
318; CHECK-NEXT:    br i1 [[CMP:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
319; CHECK:       if:
320; CHECK-NEXT:    br label [[END:%.*]]
321; CHECK:       else:
322; CHECK-NEXT:    br label [[END]]
323; CHECK:       end:
324; CHECK-NEXT:    [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ [[REM]], [[ELSE]] ]
325; CHECK-NEXT:    ret i32 [[RET]]
326;
327entry:
328  br i1 %cmp, label %if, label %else
329
330if:
331  %div = sdiv i32 %a, %b
332  br label %end
333
334else:
335  %rem = srem i32 %a, %b
336  br label %end
337
338end:
339  %ret = phi i32 [ %div, %if ], [ %rem, %else ]
340  ret i32 %ret
341}
342
343define i64 @diamond_pred_has_other_sucessors(i64 %a, i64 %b, i64 %c) {
344; CHECK-LABEL: @diamond_pred_has_other_sucessors(
345; CHECK-NEXT:  entry:
346; CHECK-NEXT:    switch i64 [[A:%.*]], label [[RETURN:%.*]] [
347; CHECK-NEXT:    i64 0, label [[SW_BB:%.*]]
348; CHECK-NEXT:    i64 1, label [[SW_BB1:%.*]]
349; CHECK-NEXT:    ]
350; CHECK:       sw.bb:
351; CHECK-NEXT:    [[DIV:%.*]] = udiv i64 [[B:%.*]], [[C:%.*]]
352; CHECK-NEXT:    br label [[RETURN]]
353; CHECK:       sw.bb1:
354; CHECK-NEXT:    [[REM:%.*]] = urem i64 [[B]], [[C]]
355; CHECK-NEXT:    br label [[RETURN]]
356; CHECK:       return:
357; CHECK-NEXT:    [[RETVAL_0:%.*]] = phi i64 [ [[REM]], [[SW_BB1]] ], [ [[DIV]], [[SW_BB]] ], [ 0, [[ENTRY:%.*]] ]
358; CHECK-NEXT:    ret i64 [[RETVAL_0]]
359;
360entry:
361  switch i64 %a, label %return [
362  i64 0, label %sw.bb
363  i64 1, label %sw.bb1
364  ]
365
366sw.bb:                                            ; preds = %entry
367  %div = udiv i64 %b, %c
368  br label %return
369
370sw.bb1:                                           ; preds = %entry
371  %rem = urem i64 %b, %c
372  br label %return
373
374return:                                           ; preds = %entry, %sw.bb1, %sw.bb
375  %retval.0 = phi i64 [ %rem, %sw.bb1 ], [ %div, %sw.bb ], [ 0, %entry ]
376  ret i64 %retval.0
377}
378
379define i64 @diamond_div_no_unique_predecessor(i64 %a, i64 %b, i64 %c) {
380; CHECK-LABEL: @diamond_div_no_unique_predecessor(
381; CHECK-NEXT:  entry:
382; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[A:%.*]], -1
383; CHECK-NEXT:    br i1 [[CMP]], label [[FOO:%.*]], label [[IF_END:%.*]]
384; CHECK:       if.end:
385; CHECK-NEXT:    [[CMP1:%.*]] = icmp sgt i64 [[A]], 1
386; CHECK-NEXT:    br i1 [[CMP1]], label [[BAR:%.*]], label [[BAZ:%.*]]
387; CHECK:       baz:
388; CHECK-NEXT:    [[DIV:%.*]] = udiv i64 [[B:%.*]], [[C:%.*]]
389; CHECK-NEXT:    br label [[RETURN:%.*]]
390; CHECK:       foo:
391; CHECK-NEXT:    br label [[BAZ]]
392; CHECK:       bar:
393; CHECK-NEXT:    [[REM:%.*]] = urem i64 [[B]], [[C]]
394; CHECK-NEXT:    br label [[RETURN]]
395; CHECK:       return:
396; CHECK-NEXT:    [[RETVAL_0:%.*]] = phi i64 [ [[DIV]], [[BAZ]] ], [ [[REM]], [[BAR]] ]
397; CHECK-NEXT:    ret i64 [[RETVAL_0]]
398;
399entry:
400  %cmp = icmp slt i64 %a, -1
401  br i1 %cmp, label %foo, label %if.end
402
403if.end:
404  %cmp1 = icmp sgt i64 %a, 1
405  br i1 %cmp1, label %bar, label %baz
406
407baz:
408  %div = udiv i64 %b, %c
409  br label %return
410
411foo:
412  br label %baz
413
414bar:
415  %rem = urem i64 %b, %c
416  br label %return
417
418return:
419  %retval.0 = phi i64 [ %div, %baz ], [ %rem, %bar ]
420  ret i64 %retval.0
421}
422
423define i64 @diamond_rem_no_unique_predecessor(i64 %a, i64 %b, i64 %c) {
424; CHECK-LABEL: @diamond_rem_no_unique_predecessor(
425; CHECK-NEXT:  entry:
426; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[A:%.*]], -1
427; CHECK-NEXT:    br i1 [[CMP]], label [[FOO:%.*]], label [[IF_END:%.*]]
428; CHECK:       if.end:
429; CHECK-NEXT:    [[CMP1:%.*]] = icmp sgt i64 [[A]], 1
430; CHECK-NEXT:    br i1 [[CMP1]], label [[BAR:%.*]], label [[BAZ:%.*]]
431; CHECK:       baz:
432; CHECK-NEXT:    [[REM:%.*]] = urem i64 [[B:%.*]], [[C:%.*]]
433; CHECK-NEXT:    br label [[RETURN:%.*]]
434; CHECK:       foo:
435; CHECK-NEXT:    br label [[BAZ]]
436; CHECK:       bar:
437; CHECK-NEXT:    [[DIV:%.*]] = udiv i64 [[B]], [[C]]
438; CHECK-NEXT:    br label [[RETURN]]
439; CHECK:       return:
440; CHECK-NEXT:    [[RETVAL_0:%.*]] = phi i64 [ [[REM]], [[BAZ]] ], [ [[DIV]], [[BAR]] ]
441; CHECK-NEXT:    ret i64 [[RETVAL_0]]
442;
443entry:
444  %cmp = icmp slt i64 %a, -1
445  br i1 %cmp, label %foo, label %if.end
446
447if.end:
448  %cmp1 = icmp sgt i64 %a, 1
449  br i1 %cmp1, label %bar, label %baz
450
451baz:
452  %rem = urem i64 %b, %c
453  br label %return
454
455foo:
456  br label %baz
457
458bar:
459  %div = udiv i64 %b, %c
460  br label %return
461
462return:
463  %retval.0 = phi i64 [ %rem, %baz ], [ %div, %bar ]
464  ret i64 %retval.0
465}
466
467declare void @dummy()
468
469define i32 @invoke_not_willreturn(i32 %a, i32 %b) personality ptr null {
470; CHECK-LABEL: @invoke_not_willreturn(
471; CHECK-NEXT:  entry:
472; CHECK-NEXT:    invoke void @dummy()
473; CHECK-NEXT:    to label [[CONT:%.*]] unwind label [[LPAD:%.*]]
474; CHECK:       cont:
475; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]]
476; CHECK-NEXT:    ret i32 [[DIV]]
477; CHECK:       lpad:
478; CHECK-NEXT:    [[TMP0:%.*]] = landingpad { ptr, i32 }
479; CHECK-NEXT:    cleanup
480; CHECK-NEXT:    [[REM:%.*]] = srem i32 [[A]], [[B]]
481; CHECK-NEXT:    ret i32 [[REM]]
482;
483entry:
484  invoke void @dummy()
485  to label %cont unwind label %lpad
486
487cont:
488  %div = sdiv i32 %a, %b
489  ret i32 %div
490
491lpad:
492  landingpad { ptr, i32 }
493  cleanup
494  %rem = srem i32 %a, %b
495  ret i32 %rem
496}
497
498define i32 @invoke_willreturn(i32 %a, i32 %b) personality ptr null {
499; CHECK-LABEL: @invoke_willreturn(
500; CHECK-NEXT:  entry:
501; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]]
502; CHECK-NEXT:    [[REM:%.*]] = srem i32 [[A]], [[B]]
503; CHECK-NEXT:    invoke void @dummy() #[[ATTR0:[0-9]+]]
504; CHECK-NEXT:    to label [[CONT:%.*]] unwind label [[LPAD:%.*]]
505; CHECK:       cont:
506; CHECK-NEXT:    ret i32 [[DIV]]
507; CHECK:       lpad:
508; CHECK-NEXT:    [[TMP0:%.*]] = landingpad { ptr, i32 }
509; CHECK-NEXT:    cleanup
510; CHECK-NEXT:    ret i32 [[REM]]
511;
512entry:
513  invoke void @dummy() willreturn
514  to label %cont unwind label %lpad
515
516cont:
517  %div = sdiv i32 %a, %b
518  ret i32 %div
519
520lpad:
521  landingpad { ptr, i32 }
522  cleanup
523  %rem = srem i32 %a, %b
524  ret i32 %rem
525}
526
527; Use this personality function so that catchpad is guaranteed to transfer.
528declare void @ProcessCLRException()
529
530define i32 @catchswitch(i32 %a, i32 %b) personality ptr @ProcessCLRException {
531; CHECK-LABEL: @catchswitch(
532; CHECK-NEXT:  entry:
533; CHECK-NEXT:    invoke void @dummy() #[[ATTR0]]
534; CHECK-NEXT:    to label [[CONT:%.*]] unwind label [[LPAD:%.*]]
535; CHECK:       cont:
536; CHECK-NEXT:    ret i32 0
537; CHECK:       lpad:
538; CHECK-NEXT:    [[CS:%.*]] = catchswitch within none [label %cp] unwind label [[LPAD_END:%.*]]
539; CHECK:       cp:
540; CHECK-NEXT:    [[TMP0:%.*]] = catchpad within [[CS]] []
541; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]]
542; CHECK-NEXT:    ret i32 [[DIV]]
543; CHECK:       lpad.end:
544; CHECK-NEXT:    [[TMP1:%.*]] = cleanuppad within none []
545; CHECK-NEXT:    [[REM:%.*]] = srem i32 [[A]], [[B]]
546; CHECK-NEXT:    ret i32 [[REM]]
547;
548entry:
549  invoke void @dummy() willreturn
550  to label %cont unwind label %lpad
551
552cont:
553  ret i32 0
554
555lpad:
556  %cs = catchswitch within none [label %cp] unwind label %lpad.end
557
558cp:
559  catchpad within %cs []
560  %div = sdiv i32 %a, %b
561  ret i32 %div
562
563lpad.end:
564  cleanuppad within none []
565  %rem = srem i32 %a, %b
566  ret i32 %rem
567}
568