Bump version to 19.1.0-rc3
[llvm-project.git] / llvm / test / Transforms / LICM / call-hoisting.ll
blobe6d2e42e34e8182c6ca8e9a12f1d22701b43b2fe
1 ; RUN: opt -S -passes=licm %s | FileCheck %s
2 ; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<target-ir>,require<scalar-evolution>,require<opt-remark-emit>,loop-mssa(licm)' < %s -S | FileCheck %s
4 declare i32 @load(ptr %p) argmemonly readonly nounwind
6 define void @test_load(ptr noalias %loc, ptr noalias %sink) {
7 ; CHECK-LABEL: @test_load
8 ; CHECK-LABEL: entry:
9 ; CHECK: call i32 @load
10 ; CHECK-LABEL: loop:
11 entry:
12   br label %loop
14 loop:
15   %iv = phi i32 [0, %entry], [%iv.next, %loop]
16   %ret = call i32 @load(ptr %loc)
17   store volatile i32 %ret, ptr %sink
18   %iv.next = add i32 %iv, 1
19   %cmp = icmp slt i32 %iv, 200
20   br i1 %cmp, label %loop, label %exit
22 exit:
23   ret void
26 declare i32 @spec(ptr %p, ptr %q) readonly argmemonly nounwind speculatable
28 ; We should strip the dereferenceable callsite attribute on spec call's argument since it is
29 ; can cause UB in the speculatable call when hoisted to preheader.
30 ; However, we need not strip the nonnull attribute since it just propagates
31 ; poison if the parameter was indeed null.
32 define void @test_strip_attribute(ptr noalias %loc, ptr noalias %sink, ptr %q) {
33 ; CHECK-LABEL: @test_strip_attribute(
34 ; CHECK-NEXT:  entry:
35 ; CHECK-NEXT:    [[RET:%.*]] = call i32 @load(ptr [[LOC:%.*]])
36 ; CHECK-NEXT:    [[NULLCHK:%.*]] = icmp eq ptr [[Q:%.*]], null
37 ; CHECK-NEXT:    [[RET2:%.*]] = call i32 @spec(ptr nonnull [[Q]], ptr [[LOC]])
38 ; CHECK-NEXT:    br label [[LOOP:%.*]]
39 ; CHECK:       loop:
40 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[ISNULL:%.*]] ]
41 ; CHECK-NEXT:    br i1 [[NULLCHK]], label [[ISNULL]], label [[NONNULLBB:%.*]]
42 entry:
43   br label %loop
45 loop:
46   %iv = phi i32 [0, %entry], [%iv.next, %isnull ]
47   %ret = call i32 @load(ptr %loc)
48   %nullchk = icmp eq ptr %q, null
49   br i1 %nullchk, label %isnull, label %nonnullbb
51 nonnullbb:
52   %ret2 = call i32 @spec(ptr nonnull %q, ptr dereferenceable(12) %loc)
53   br label %isnull
55 isnull:
56   store volatile i32 %ret, ptr %sink
57   %iv.next = add i32 %iv, 1
58   %cmp = icmp slt i32 %iv, 200
59   br i1 %cmp, label %loop, label %exit
61 exit:
62   ret void
65 declare void @store(i32 %val, ptr %p) argmemonly writeonly nounwind
67 define void @test(ptr %loc) {
68 ; CHECK-LABEL: @test
69 ; CHECK-LABEL: loop:
70 ; CHECK: call void @store
71 ; CHECK-LABEL: exit:
72 entry:
73   br label %loop
75 loop:
76   %iv = phi i32 [0, %entry], [%iv.next, %loop]
77   call void @store(i32 0, ptr %loc)
78   %iv.next = add i32 %iv, 1
79   %cmp = icmp slt i32 %iv, 200
80   br i1 %cmp, label %loop, label %exit
82 exit:
83   ret void
86 define void @test_multiexit(ptr %loc, i1 %earlycnd) {
87 ; CHECK-LABEL: @test_multiexit
88 ; CHECK-LABEL: loop:
89 ; CHECK: call void @store
90 ; CHECK-LABEL: backedge:
91 entry:
92   br label %loop
94 loop:
95   %iv = phi i32 [0, %entry], [%iv.next, %backedge]
96   call void @store(i32 0, ptr %loc)
97   %iv.next = add i32 %iv, 1
98   br i1 %earlycnd, label %exit1, label %backedge
100 backedge:
101   %cmp = icmp slt i32 %iv, 200
102   br i1 %cmp, label %loop, label %exit2
104 exit1:
105   ret void
106 exit2:
107   ret void
110 define void @neg_lv_value(ptr %loc) {
111 ; CHECK-LABEL: @neg_lv_value
112 ; CHECK-LABEL: loop:
113 ; CHECK: call void @store
114 ; CHECK-LABEL: exit:
115 entry:
116   br label %loop
118 loop:
119   %iv = phi i32 [0, %entry], [%iv.next, %loop]
120   call void @store(i32 %iv, ptr %loc)
121   %iv.next = add i32 %iv, 1
122   %cmp = icmp slt i32 %iv, 200
123   br i1 %cmp, label %loop, label %exit
125 exit:
126   ret void
129 define void @neg_lv_addr(ptr %loc) {
130 ; CHECK-LABEL: @neg_lv_addr
131 ; CHECK-LABEL: loop:
132 ; CHECK: call void @store
133 ; CHECK-LABEL: exit:
134 entry:
135   br label %loop
137 loop:
138   %iv = phi i32 [0, %entry], [%iv.next, %loop]
139   %p = getelementptr i32, ptr %loc, i32 %iv
140   call void @store(i32 0, ptr %p)
141   %iv.next = add i32 %iv, 1
142   %cmp = icmp slt i32 %iv, 200
143   br i1 %cmp, label %loop, label %exit
145 exit:
146   ret void
149 define void @neg_mod(ptr %loc) {
150 ; CHECK-LABEL: @neg_mod
151 ; CHECK-LABEL: loop:
152 ; CHECK: call void @store
153 ; CHECK-LABEL: exit:
154 entry:
155   br label %loop
157 loop:
158   %iv = phi i32 [0, %entry], [%iv.next, %loop]
159   call void @store(i32 0, ptr %loc)
160   store i32 %iv, ptr %loc
161   %iv.next = add i32 %iv, 1
162   %cmp = icmp slt i32 %iv, 200
163   br i1 %cmp, label %loop, label %exit
165 exit:
166   ret void
169 define void @neg_ref(ptr %loc) {
170 ; CHECK-LABEL: @neg_ref
171 ; CHECK-LABEL: loop:
172 ; CHECK: call void @store
173 ; CHECK-LABEL: exit1:
174 entry:
175   br label %loop
177 loop:
178   %iv = phi i32 [0, %entry], [%iv.next, %backedge]
179   call void @store(i32 0, ptr %loc)
180   %v = load i32, ptr %loc
181   %earlycnd = icmp eq i32 %v, 198
182   br i1 %earlycnd, label %exit1, label %backedge
184 backedge:
185   %iv.next = add i32 %iv, 1
186   %cmp = icmp slt i32 %iv, 200
187   br i1 %cmp, label %loop, label %exit2
189 exit1:
190   ret void
191 exit2:
192   ret void
195 declare void @modref()
197 define void @neg_modref(ptr %loc) {
198 ; CHECK-LABEL: @neg_modref
199 ; CHECK-LABEL: loop:
200 ; CHECK: call void @store
201 ; CHECK-LABEL: exit:
202 entry:
203   br label %loop
205 loop:
206   %iv = phi i32 [0, %entry], [%iv.next, %loop]
207   call void @store(i32 0, ptr %loc)
208   call void @modref()
209   %iv.next = add i32 %iv, 1
210   %cmp = icmp slt i32 %iv, 200
211   br i1 %cmp, label %loop, label %exit
213 exit:
214   ret void
217 define void @neg_fence(ptr %loc) {
218 ; CHECK-LABEL: @neg_fence
219 ; CHECK-LABEL: loop:
220 ; CHECK: call void @store
221 ; CHECK-LABEL: exit:
222 entry:
223   br label %loop
225 loop:
226   %iv = phi i32 [0, %entry], [%iv.next, %loop]
227   call void @store(i32 0, ptr %loc)
228   fence seq_cst
229   %iv.next = add i32 %iv, 1
230   %cmp = icmp slt i32 %iv, 200
231   br i1 %cmp, label %loop, label %exit
233 exit:
234   ret void
237 declare void @not_nounwind(i32 %v, ptr %p) writeonly argmemonly
238 declare void @not_argmemonly(i32 %v, ptr %p) writeonly nounwind
239 declare void @not_writeonly(i32 %v, ptr %p) argmemonly nounwind
241 define void @neg_not_nounwind(ptr %loc) {
242 ; CHECK-LABEL: @neg_not_nounwind
243 ; CHECK-LABEL: loop:
244 ; CHECK: call void @not_nounwind
245 ; CHECK-LABEL: exit:
246 entry:
247   br label %loop
249 loop:
250   %iv = phi i32 [0, %entry], [%iv.next, %loop]
251   call void @not_nounwind(i32 0, ptr %loc)
252   %iv.next = add i32 %iv, 1
253   %cmp = icmp slt i32 %iv, 200
254   br i1 %cmp, label %loop, label %exit
256 exit:
257   ret void
260 define void @neg_not_argmemonly(ptr %loc) {
261 ; CHECK-LABEL: @neg_not_argmemonly
262 ; CHECK-LABEL: loop:
263 ; CHECK: call void @not_argmemonly
264 ; CHECK-LABEL: exit:
265 entry:
266   br label %loop
268 loop:
269   %iv = phi i32 [0, %entry], [%iv.next, %loop]
270   call void @not_argmemonly(i32 0, ptr %loc)
271   %iv.next = add i32 %iv, 1
272   %cmp = icmp slt i32 %iv, 200
273   br i1 %cmp, label %loop, label %exit
275 exit:
276   ret void
279 define void @neg_not_writeonly(ptr %loc) {
280 ; CHECK-LABEL: @neg_not_writeonly
281 ; CHECK-LABEL: loop:
282 ; CHECK: call void @not_writeonly
283 ; CHECK-LABEL: exit:
284 entry:
285   br label %loop
287 loop:
288   %iv = phi i32 [0, %entry], [%iv.next, %loop]
289   call void @not_writeonly(i32 0, ptr %loc)
290   %iv.next = add i32 %iv, 1
291   %cmp = icmp slt i32 %iv, 200
292   br i1 %cmp, label %loop, label %exit
294 exit:
295   ret void