1; RUN: opt -S -licm < %s | FileCheck %s
2; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,require<opt-remark-emit>,loop(licm)' -S %s | FileCheck %s
3
4declare void @use_nothrow(i64 %a) nounwind
5declare void @use(i64 %a)
6declare void @maythrow()
7
8define void @nothrow(i64 %x, i64 %y, i1* %cond) {
9; CHECK-LABEL: nothrow
10; CHECK-LABEL: entry
11; CHECK: %div = udiv i64 %x, %y
12; CHECK-LABEL: loop
13; CHECK: call void @use_nothrow(i64 %div)
14entry:
15  br label %loop
16
17loop:                                         ; preds = %entry, %for.inc
18  %div = udiv i64 %x, %y
19  br label %loop2
20
21loop2:
22  call void @use_nothrow(i64 %div)
23  br label %loop
24}
25
26; The udiv is guarantee to execute if the loop is
27define void @throw_header_after(i64 %x, i64 %y, i1* %cond) {
28; CHECK-LABEL: throw_header_after
29; CHECK: %div = udiv i64 %x, %y
30; CHECK-LABEL: loop
31; CHECK: call void @use(i64 %div)
32entry:
33  br label %loop
34
35loop:                                         ; preds = %entry, %for.inc
36  %div = udiv i64 %x, %y
37  call void @use(i64 %div)
38  br label %loop
39}
40define void @throw_header_after_rec(i64* %xp, i64* %yp, i1* %cond) {
41; CHECK-LABEL: throw_header_after_rec
42; CHECK: %x = load i64, i64* %xp
43; CHECK: %y = load i64, i64* %yp
44; CHECK: %div = udiv i64 %x, %y
45; CHECK-LABEL: loop
46; CHECK: call void @use(i64 %div)
47entry:
48  br label %loop
49
50loop:                                         ; preds = %entry, %for.inc
51  %x = load i64, i64* %xp
52  %y = load i64, i64* %yp
53  %div = udiv i64 %x, %y
54  call void @use(i64 %div) readonly
55  br label %loop
56}
57
58; Similiar to the above, but the hoistable instruction (%y in this case)
59; happens not to be the first instruction in the block.
60define void @throw_header_after_nonfirst(i64* %xp, i64* %yp, i1* %cond) {
61; CHECK-LABEL: throw_header_after_nonfirst
62; CHECK: %y = load i64, i64* %yp
63; CHECK-LABEL: loop
64; CHECK: %x = load i64, i64* %gep
65; CHECK: %div = udiv i64 %x, %y
66; CHECK: call void @use(i64 %div)
67entry:
68  br label %loop
69
70loop:                                         ; preds = %entry, %for.inc
71  %iv = phi i64 [0, %entry], [%div, %loop]
72  %gep = getelementptr i64, i64* %xp, i64 %iv
73  %x = load i64, i64* %gep
74  %y = load i64, i64* %yp
75  %div = udiv i64 %x, %y
76  call void @use(i64 %div) readonly
77  br label %loop
78}
79
80; Negative test
81define void @throw_header_before(i64 %x, i64 %y, i1* %cond) {
82; CHECK-LABEL: throw_header_before
83; CHECK-LABEL: loop
84; CHECK: %div = udiv i64 %x, %y
85; CHECK: call void @use(i64 %div)
86entry:
87  br label %loop
88
89loop:                                         ; preds = %entry, %for.inc
90  call void @maythrow()
91  %div = udiv i64 %x, %y
92  call void @use(i64 %div)
93  br label %loop
94}
95
96; The header is known no throw, but the loop is not.  We can
97; still lift out of the header.
98define void @nothrow_header(i64 %x, i64 %y, i1 %cond) {
99; CHECK-LABEL: nothrow_header
100; CHECK-LABEL: entry
101; CHECK: %div = udiv i64 %x, %y
102; CHECK-LABEL: loop
103  ; CHECK: call void @use(i64 %div)
104entry:
105  br label %loop
106loop:                                         ; preds = %entry, %for.inc
107  %div = udiv i64 %x, %y
108  br i1 %cond, label %loop-if, label %exit
109loop-if:
110  call void @use(i64 %div)
111  br label %loop
112exit:
113  ret void
114}
115; Negative test - can't move out of throwing block
116define void @nothrow_header_neg(i64 %x, i64 %y, i1 %cond) {
117; CHECK-LABEL: nothrow_header_neg
118; CHECK-LABEL: entry
119; CHECK-LABEL: loop
120; CHECK: %div = udiv i64 %x, %y
121; CHECK: call void @use(i64 %div)
122entry:
123  br label %loop
124loop:                                         ; preds = %entry, %for.inc
125  br label %loop-if
126loop-if:
127  %div = udiv i64 %x, %y
128  call void @use(i64 %div)
129  br label %loop
130}
131