252
|
1 ; RUN: opt -S -passes=licm %s | FileCheck %s
|
236
|
2 ; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,require<opt-remark-emit>,loop-mssa(licm)' < %s -S | FileCheck %s
|
150
|
3
|
236
|
4 declare i32 @load(ptr %p) argmemonly readonly nounwind
|
150
|
5
|
236
|
6 define void @test_load(ptr noalias %loc, ptr noalias %sink) {
|
150
|
7 ; CHECK-LABEL: @test_load
|
|
8 ; CHECK-LABEL: entry:
|
|
9 ; CHECK: call i32 @load
|
|
10 ; CHECK-LABEL: loop:
|
|
11 entry:
|
|
12 br label %loop
|
|
13
|
|
14 loop:
|
|
15 %iv = phi i32 [0, %entry], [%iv.next, %loop]
|
236
|
16 %ret = call i32 @load(ptr %loc)
|
|
17 store volatile i32 %ret, ptr %sink
|
150
|
18 %iv.next = add i32 %iv, 1
|
|
19 %cmp = icmp slt i32 %iv, 200
|
|
20 br i1 %cmp, label %loop, label %exit
|
|
21
|
|
22 exit:
|
|
23 ret void
|
|
24 }
|
|
25
|
236
|
26 declare i32 @spec(ptr %p, ptr %q) readonly argmemonly nounwind speculatable
|
223
|
27
|
236
|
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:%.*]]
|
223
|
42 entry:
|
|
43 br label %loop
|
|
44
|
|
45 loop:
|
|
46 %iv = phi i32 [0, %entry], [%iv.next, %isnull ]
|
236
|
47 %ret = call i32 @load(ptr %loc)
|
|
48 %nullchk = icmp eq ptr %q, null
|
223
|
49 br i1 %nullchk, label %isnull, label %nonnullbb
|
|
50
|
236
|
51 nonnullbb:
|
|
52 %ret2 = call i32 @spec(ptr nonnull %q, ptr dereferenceable(12) %loc)
|
223
|
53 br label %isnull
|
|
54
|
236
|
55 isnull:
|
|
56 store volatile i32 %ret, ptr %sink
|
223
|
57 %iv.next = add i32 %iv, 1
|
|
58 %cmp = icmp slt i32 %iv, 200
|
|
59 br i1 %cmp, label %loop, label %exit
|
|
60
|
|
61 exit:
|
|
62 ret void
|
|
63 }
|
150
|
64
|
236
|
65 declare void @store(i32 %val, ptr %p) argmemonly writeonly nounwind
|
150
|
66
|
236
|
67 define void @test(ptr %loc) {
|
150
|
68 ; CHECK-LABEL: @test
|
|
69 ; CHECK-LABEL: loop:
|
|
70 ; CHECK: call void @store
|
|
71 ; CHECK-LABEL: exit:
|
|
72 entry:
|
|
73 br label %loop
|
|
74
|
|
75 loop:
|
|
76 %iv = phi i32 [0, %entry], [%iv.next, %loop]
|
236
|
77 call void @store(i32 0, ptr %loc)
|
150
|
78 %iv.next = add i32 %iv, 1
|
|
79 %cmp = icmp slt i32 %iv, 200
|
|
80 br i1 %cmp, label %loop, label %exit
|
|
81
|
|
82 exit:
|
|
83 ret void
|
|
84 }
|
|
85
|
236
|
86 define void @test_multiexit(ptr %loc, i1 %earlycnd) {
|
150
|
87 ; CHECK-LABEL: @test_multiexit
|
|
88 ; CHECK-LABEL: loop:
|
|
89 ; CHECK: call void @store
|
|
90 ; CHECK-LABEL: backedge:
|
|
91 entry:
|
|
92 br label %loop
|
|
93
|
|
94 loop:
|
|
95 %iv = phi i32 [0, %entry], [%iv.next, %backedge]
|
236
|
96 call void @store(i32 0, ptr %loc)
|
150
|
97 %iv.next = add i32 %iv, 1
|
|
98 br i1 %earlycnd, label %exit1, label %backedge
|
236
|
99
|
150
|
100 backedge:
|
|
101 %cmp = icmp slt i32 %iv, 200
|
|
102 br i1 %cmp, label %loop, label %exit2
|
|
103
|
|
104 exit1:
|
|
105 ret void
|
|
106 exit2:
|
|
107 ret void
|
|
108 }
|
|
109
|
236
|
110 define void @neg_lv_value(ptr %loc) {
|
150
|
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
|
|
117
|
|
118 loop:
|
|
119 %iv = phi i32 [0, %entry], [%iv.next, %loop]
|
236
|
120 call void @store(i32 %iv, ptr %loc)
|
150
|
121 %iv.next = add i32 %iv, 1
|
|
122 %cmp = icmp slt i32 %iv, 200
|
|
123 br i1 %cmp, label %loop, label %exit
|
|
124
|
|
125 exit:
|
|
126 ret void
|
|
127 }
|
|
128
|
236
|
129 define void @neg_lv_addr(ptr %loc) {
|
150
|
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
|
|
136
|
|
137 loop:
|
|
138 %iv = phi i32 [0, %entry], [%iv.next, %loop]
|
236
|
139 %p = getelementptr i32, ptr %loc, i32 %iv
|
|
140 call void @store(i32 0, ptr %p)
|
150
|
141 %iv.next = add i32 %iv, 1
|
|
142 %cmp = icmp slt i32 %iv, 200
|
|
143 br i1 %cmp, label %loop, label %exit
|
|
144
|
|
145 exit:
|
|
146 ret void
|
|
147 }
|
|
148
|
236
|
149 define void @neg_mod(ptr %loc) {
|
150
|
150 ; CHECK-LABEL: @neg_mod
|
|
151 ; CHECK-LABEL: loop:
|
|
152 ; CHECK: call void @store
|
|
153 ; CHECK-LABEL: exit:
|
|
154 entry:
|
|
155 br label %loop
|
|
156
|
|
157 loop:
|
|
158 %iv = phi i32 [0, %entry], [%iv.next, %loop]
|
236
|
159 call void @store(i32 0, ptr %loc)
|
|
160 store i32 %iv, ptr %loc
|
150
|
161 %iv.next = add i32 %iv, 1
|
|
162 %cmp = icmp slt i32 %iv, 200
|
|
163 br i1 %cmp, label %loop, label %exit
|
|
164
|
|
165 exit:
|
|
166 ret void
|
|
167 }
|
|
168
|
236
|
169 define void @neg_ref(ptr %loc) {
|
150
|
170 ; CHECK-LABEL: @neg_ref
|
|
171 ; CHECK-LABEL: loop:
|
|
172 ; CHECK: call void @store
|
|
173 ; CHECK-LABEL: exit1:
|
|
174 entry:
|
|
175 br label %loop
|
|
176
|
|
177 loop:
|
|
178 %iv = phi i32 [0, %entry], [%iv.next, %backedge]
|
236
|
179 call void @store(i32 0, ptr %loc)
|
|
180 %v = load i32, ptr %loc
|
150
|
181 %earlycnd = icmp eq i32 %v, 198
|
|
182 br i1 %earlycnd, label %exit1, label %backedge
|
236
|
183
|
150
|
184 backedge:
|
|
185 %iv.next = add i32 %iv, 1
|
|
186 %cmp = icmp slt i32 %iv, 200
|
|
187 br i1 %cmp, label %loop, label %exit2
|
|
188
|
|
189 exit1:
|
|
190 ret void
|
|
191 exit2:
|
|
192 ret void
|
|
193 }
|
|
194
|
|
195 declare void @modref()
|
|
196
|
236
|
197 define void @neg_modref(ptr %loc) {
|
150
|
198 ; CHECK-LABEL: @neg_modref
|
|
199 ; CHECK-LABEL: loop:
|
|
200 ; CHECK: call void @store
|
|
201 ; CHECK-LABEL: exit:
|
|
202 entry:
|
|
203 br label %loop
|
|
204
|
|
205 loop:
|
|
206 %iv = phi i32 [0, %entry], [%iv.next, %loop]
|
236
|
207 call void @store(i32 0, ptr %loc)
|
150
|
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
|
|
212
|
|
213 exit:
|
|
214 ret void
|
|
215 }
|
|
216
|
236
|
217 define void @neg_fence(ptr %loc) {
|
150
|
218 ; CHECK-LABEL: @neg_fence
|
|
219 ; CHECK-LABEL: loop:
|
|
220 ; CHECK: call void @store
|
|
221 ; CHECK-LABEL: exit:
|
|
222 entry:
|
|
223 br label %loop
|
|
224
|
|
225 loop:
|
|
226 %iv = phi i32 [0, %entry], [%iv.next, %loop]
|
236
|
227 call void @store(i32 0, ptr %loc)
|
150
|
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
|
|
232
|
|
233 exit:
|
|
234 ret void
|
|
235 }
|
|
236
|
236
|
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
|
150
|
240
|
236
|
241 define void @neg_not_nounwind(ptr %loc) {
|
150
|
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
|
|
248
|
|
249 loop:
|
|
250 %iv = phi i32 [0, %entry], [%iv.next, %loop]
|
236
|
251 call void @not_nounwind(i32 0, ptr %loc)
|
150
|
252 %iv.next = add i32 %iv, 1
|
|
253 %cmp = icmp slt i32 %iv, 200
|
|
254 br i1 %cmp, label %loop, label %exit
|
|
255
|
|
256 exit:
|
|
257 ret void
|
|
258 }
|
|
259
|
236
|
260 define void @neg_not_argmemonly(ptr %loc) {
|
150
|
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
|
|
267
|
|
268 loop:
|
|
269 %iv = phi i32 [0, %entry], [%iv.next, %loop]
|
236
|
270 call void @not_argmemonly(i32 0, ptr %loc)
|
150
|
271 %iv.next = add i32 %iv, 1
|
|
272 %cmp = icmp slt i32 %iv, 200
|
|
273 br i1 %cmp, label %loop, label %exit
|
|
274
|
|
275 exit:
|
|
276 ret void
|
|
277 }
|
|
278
|
236
|
279 define void @neg_not_writeonly(ptr %loc) {
|
150
|
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
|
|
286
|
|
287 loop:
|
|
288 %iv = phi i32 [0, %entry], [%iv.next, %loop]
|
236
|
289 call void @not_writeonly(i32 0, ptr %loc)
|
150
|
290 %iv.next = add i32 %iv, 1
|
|
291 %cmp = icmp slt i32 %iv, 200
|
|
292 br i1 %cmp, label %loop, label %exit
|
|
293
|
|
294 exit:
|
|
295 ret void
|
|
296 }
|
|
297
|