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
9 ; CHECK: call i32 @load
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
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(
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:%.*]]
40 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[ISNULL:%.*]] ]
41 ; CHECK-NEXT: br i1 [[NULLCHK]], label [[ISNULL]], label [[NONNULLBB:%.*]]
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
52 %ret2 = call i32 @spec(ptr nonnull %q, ptr dereferenceable(12) %loc)
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
65 declare void @store(i32 %val, ptr %p) argmemonly writeonly nounwind
67 define void @test(ptr %loc) {
70 ; CHECK: call void @store
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
86 define void @test_multiexit(ptr %loc, i1 %earlycnd) {
87 ; CHECK-LABEL: @test_multiexit
89 ; CHECK: call void @store
90 ; CHECK-LABEL: backedge:
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
101 %cmp = icmp slt i32 %iv, 200
102 br i1 %cmp, label %loop, label %exit2
110 define void @neg_lv_value(ptr %loc) {
111 ; CHECK-LABEL: @neg_lv_value
113 ; CHECK: call void @store
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
129 define void @neg_lv_addr(ptr %loc) {
130 ; CHECK-LABEL: @neg_lv_addr
132 ; CHECK: call void @store
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
149 define void @neg_mod(ptr %loc) {
150 ; CHECK-LABEL: @neg_mod
152 ; CHECK: call void @store
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
169 define void @neg_ref(ptr %loc) {
170 ; CHECK-LABEL: @neg_ref
172 ; CHECK: call void @store
173 ; CHECK-LABEL: exit1:
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
185 %iv.next = add i32 %iv, 1
186 %cmp = icmp slt i32 %iv, 200
187 br i1 %cmp, label %loop, label %exit2
195 declare void @modref()
197 define void @neg_modref(ptr %loc) {
198 ; CHECK-LABEL: @neg_modref
200 ; CHECK: call void @store
206 %iv = phi i32 [0, %entry], [%iv.next, %loop]
207 call void @store(i32 0, ptr %loc)
209 %iv.next = add i32 %iv, 1
210 %cmp = icmp slt i32 %iv, 200
211 br i1 %cmp, label %loop, label %exit
217 define void @neg_fence(ptr %loc) {
218 ; CHECK-LABEL: @neg_fence
220 ; CHECK: call void @store
226 %iv = phi i32 [0, %entry], [%iv.next, %loop]
227 call void @store(i32 0, ptr %loc)
229 %iv.next = add i32 %iv, 1
230 %cmp = icmp slt i32 %iv, 200
231 br i1 %cmp, label %loop, label %exit
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
244 ; CHECK: call void @not_nounwind
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
260 define void @neg_not_argmemonly(ptr %loc) {
261 ; CHECK-LABEL: @neg_not_argmemonly
263 ; CHECK: call void @not_argmemonly
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
279 define void @neg_not_writeonly(ptr %loc) {
280 ; CHECK-LABEL: @neg_not_writeonly
282 ; CHECK: call void @not_writeonly
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