[AArch64][NFC] NFC for const vector as Instruction operand (#116790)
[llvm-project.git] / llvm / test / Transforms / LICM / store-hoisting.ll
blobd4f62d1c16f0689e6fcf69d93c3627f593a25430
1 ; 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
3 define void @test(ptr %loc) {
4 ; CHECK-LABEL: @test
5 ; CHECK-LABEL: entry:
6 ; CHECK: store i32 0, ptr %loc
7 ; CHECK-LABEL: loop:
8 entry:
9   br label %loop
11 loop:
12   %iv = phi i32 [0, %entry], [%iv.next, %loop]
13   store i32 0, ptr %loc
14   %iv.next = add i32 %iv, 1
15   %cmp = icmp slt i32 %iv, 200
16   br i1 %cmp, label %loop, label %exit
18 exit:
19   ret void
22 define void @test_multiexit(ptr %loc, i1 %earlycnd) {
23 ; CHECK-LABEL: @test_multiexit
24 ; CHECK-LABEL: entry:
25 ; CHECK: store i32 0, ptr %loc
26 ; CHECK-LABEL: loop:
27 entry:
28   br label %loop
30 loop:
31   %iv = phi i32 [0, %entry], [%iv.next, %backedge]
32   store i32 0, ptr %loc
33   %iv.next = add i32 %iv, 1
34   br i1 %earlycnd, label %exit1, label %backedge
35   
36 backedge:
37   %cmp = icmp slt i32 %iv, 200
38   br i1 %cmp, label %loop, label %exit2
40 exit1:
41   ret void
42 exit2:
43   ret void
46 define ptr @false_negative_2use(ptr %loc) {
47 ; CHECK-LABEL: @false_negative_2use
48 ; CHECK-LABEL: entry:
49 ; CHECK: store i32 0, ptr %loc
50 ; CHECK-LABEL: loop:
51 entry:
52   br label %loop
54 loop:
55   %iv = phi i32 [0, %entry], [%iv.next, %loop]
56   store i32 0, ptr %loc
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 ptr %loc
65 define void @neg_lv_value(ptr %loc) {
66 ; CHECK-LABEL: @neg_lv_value
67 ; CHECK-LABEL: exit:
68 ; CHECK: store i32 %iv.lcssa, ptr %loc
69 entry:
70   br label %loop
72 loop:
73   %iv = phi i32 [0, %entry], [%iv.next, %loop]
74   store i32 %iv, ptr %loc
75   %iv.next = add i32 %iv, 1
76   %cmp = icmp slt i32 %iv, 200
77   br i1 %cmp, label %loop, label %exit
79 exit:
80   ret void
83 define void @neg_lv_addr(ptr %loc) {
84 ; CHECK-LABEL: @neg_lv_addr
85 ; CHECK-LABEL: loop:
86 ; CHECK: store i32 0, ptr %p
87 ; CHECK-LABEL: exit:
88 entry:
89   br label %loop
91 loop:
92   %iv = phi i32 [0, %entry], [%iv.next, %loop]
93   %p = getelementptr i32, ptr %loc, i32 %iv
94   store i32 0, ptr %p
95   %iv.next = add i32 %iv, 1
96   %cmp = icmp slt i32 %iv, 200
97   br i1 %cmp, label %loop, label %exit
99 exit:
100   ret void
103 define void @neg_mod(ptr %loc) {
104 ; CHECK-LABEL: @neg_mod
105 ; CHECK-LABEL: exit:
106 ; CHECK: store i32 %iv.lcssa, ptr %loc
107 entry:
108   br label %loop
110 loop:
111   %iv = phi i32 [0, %entry], [%iv.next, %loop]
112   store i32 0, ptr %loc
113   store i32 %iv, ptr %loc
114   %iv.next = add i32 %iv, 1
115   %cmp = icmp slt i32 %iv, 200
116   br i1 %cmp, label %loop, label %exit
118 exit:
119   ret void
122 ; Hoisting the store is actually valid here, as it dominates the load.
123 define void @neg_ref(ptr %loc) {
124 ; CHECK-LABEL: @neg_ref
125 ; CHECK-LABEL: exit1:
126 ; CHECK: store i32 0, ptr %loc
127 ; CHECK-LABEL: exit2:
128 ; CHECK: store i32 0, ptr %loc
129 entry:
130   br label %loop
132 loop:
133   %iv = phi i32 [0, %entry], [%iv.next, %backedge]
134   store i32 0, ptr %loc
135   %v = load i32, ptr %loc
136   %earlycnd = icmp eq i32 %v, 198
137   br i1 %earlycnd, label %exit1, label %backedge
138   
139 backedge:
140   %iv.next = add i32 %iv, 1
141   %cmp = icmp slt i32 %iv, 200
142   br i1 %cmp, label %loop, label %exit2
144 exit1:
145   ret void
146 exit2:
147   ret void
150 ; Hoisting the store here leads to a miscompile.
151 define void @neg_ref2(ptr %loc) {
152 ; CHECK-LABEL: @neg_ref2
153 ; CHECK-LABEL: exit1:
154 ; CHECK: store i32 0, ptr %loc
155 ; CHECK-LABEL: exit2:
156 ; CHECK: store i32 0, ptr %loc
157 entry:
158   store i32 198, ptr %loc
159   br label %loop
161 loop:
162   %iv = phi i32 [0, %entry], [%iv.next, %backedge]
163   %v = load i32, ptr %loc
164   store i32 0, ptr %loc
165   %earlycnd = icmp eq i32 %v, 198
166   br i1 %earlycnd, label %exit1, label %backedge
167   
168 backedge:
169   %iv.next = add i32 %iv, 1
170   %cmp = icmp slt i32 %iv, 200
171   br i1 %cmp, label %loop, label %exit2
173 exit1:
174   ret void
175 exit2:
176   ret void
179 declare void @modref()
181 define void @neg_modref(ptr %loc) {
182 ; CHECK-LABEL: @neg_modref
183 ; CHECK-LABEL: loop:
184 ; CHECK: store i32 0, ptr %loc
185 ; CHECK-LABEL: exit:
186 entry:
187   br label %loop
189 loop:
190   %iv = phi i32 [0, %entry], [%iv.next, %loop]
191   store i32 0, ptr %loc
192   call void @modref()
193   %iv.next = add i32 %iv, 1
194   %cmp = icmp slt i32 %iv, 200
195   br i1 %cmp, label %loop, label %exit
197 exit:
198   ret void
201 define void @neg_fence(ptr %loc) {
202 ; CHECK-LABEL: @neg_fence
203 ; CHECK-LABEL: loop:
204 ; CHECK: store i32 0, ptr %loc
205 ; CHECK-LABEL: exit:
206 entry:
207   br label %loop
209 loop:
210   %iv = phi i32 [0, %entry], [%iv.next, %loop]
211   store i32 0, ptr %loc
212   fence seq_cst
213   %iv.next = add i32 %iv, 1
214   %cmp = icmp slt i32 %iv, 200
215   br i1 %cmp, label %loop, label %exit
217 exit:
218   ret void
221 define void @neg_volatile(ptr %loc) {
222 ; CHECK-LABEL: @neg_volatile
223 ; CHECK-LABEL: loop:
224 ; CHECK: store volatile i32 0, ptr %loc
225 ; CHECK-LABEL: exit:
226 entry:
227   br label %loop
229 loop:
230   %iv = phi i32 [0, %entry], [%iv.next, %loop]
231   store volatile i32 0, ptr %loc
232   %iv.next = add i32 %iv, 1
233   %cmp = icmp slt i32 %iv, 200
234   br i1 %cmp, label %loop, label %exit
236 exit:
237   ret void
240 define void @neg_release(ptr %loc) {
241 ; CHECK-LABEL: @neg_release
242 ; CHECK-LABEL: loop:
243 ; CHECK: store atomic i32 0, ptr %loc release, align 4
244 ; CHECK-LABEL: exit:
245 entry:
246   br label %loop
248 loop:
249   %iv = phi i32 [0, %entry], [%iv.next, %loop]
250   store atomic i32 0, ptr %loc release, align 4
251   %iv.next = add i32 %iv, 1
252   %cmp = icmp slt i32 %iv, 200
253   br i1 %cmp, label %loop, label %exit
255 exit:
256   ret void
259 define void @neg_seq_cst(ptr %loc) {
260 ; CHECK-LABEL: @neg_seq_cst
261 ; CHECK-LABEL: loop:
262 ; CHECK: store atomic i32 0, ptr %loc seq_cst, align 4
263 ; CHECK-LABEL: exit:
264 entry:
265   br label %loop
267 loop:
268   %iv = phi i32 [0, %entry], [%iv.next, %loop]
269   store atomic i32 0, ptr %loc seq_cst, align 4
270   %iv.next = add i32 %iv, 1
271   %cmp = icmp slt i32 %iv, 200
272   br i1 %cmp, label %loop, label %exit
274 exit:
275   ret void
278 declare void @maythrow() inaccessiblememonly
280 define void @neg_early_exit(ptr %loc) {
281 ; CHECK-LABEL: @neg_early_exit
282 ; CHECK-LABEL: body:
283 ; CHECK: store i32 0, ptr %loc
284 ; CHECK-LABEL: exit:
285 entry:
286   br label %loop
288 loop:
289   %iv = phi i32 [0, %entry], [%iv.next, %body]
290   %is_null = icmp eq ptr %loc, null
291   br i1 %is_null, label %exit, label %body
292 body:
293   call void @maythrow()
294   store i32 0, ptr %loc
295   %iv.next = add i32 %iv, 1
296   %cmp = icmp slt i32 %iv, 200
297   br i1 %cmp, label %loop, label %exit
299 exit:
300   ret void
303 define void @neg_early_throw(ptr %loc) {
304 ; CHECK-LABEL: @neg_early_throw
305 ; CHECK-LABEL: loop:
306 ; CHECK: store i32 0, ptr %loc
307 ; CHECK-LABEL: exit:
308 entry:
309   br label %loop
311 loop:
312   %iv = phi i32 [0, %entry], [%iv.next, %loop]
313   call void @maythrow()
314   store i32 0, ptr %loc
315   %iv.next = add i32 %iv, 1
316   %cmp = icmp slt i32 %iv, 200
317   br i1 %cmp, label %loop, label %exit
319 exit:
320   ret void
323 define void @test_late_throw(ptr %loc) {
324 ; CHECK-LABEL: @test_late_throw
325 ; CHECK-LABEL: entry:
326 ; CHECK: store i32 0, ptr %loc
327 ; CHECK-LABEL: loop:
328 entry:
329   br label %loop
331 loop:
332   %iv = phi i32 [0, %entry], [%iv.next, %loop]
333   store i32 0, ptr %loc
334   call void @maythrow()
335   %iv.next = add i32 %iv, 1
336   %cmp = icmp slt i32 %iv, 200
337   br i1 %cmp, label %loop, label %exit
339 exit:
340   ret void
343 ; TODO: could validly hoist the store here since we know what value
344 ; the load must observe.
345 define i32 @test_dominated_read(ptr %loc) {
346 ; CHECK-LABEL: @test_dominated_read
347 ; CHECK-LABEL: entry:
348 ; CHECK: store i32 0, ptr %loc
349 ; CHECK-LABEL: loop:
350 entry:
351   br label %loop
353 loop:
354   %iv = phi i32 [0, %entry], [%iv.next, %loop]
355   store i32 0, ptr %loc
356   %reload = load i32, ptr %loc
357   %iv.next = add i32 %iv, 1
358   %cmp = icmp slt i32 %iv, 200
359   br i1 %cmp, label %loop, label %exit
361 exit:
362   ret i32 %reload
365 ; TODO: could validly hoist the store since we already hoisted the load and
366 ; it's no longer in the loop.
367 define i32 @test_dominating_read(ptr %loc) {
368 ; CHECK-LABEL: @test_dominating_read
369 ; CHECK-LABEL: exit:
370 ; CHECK: store i32 0, ptr %loc
371 entry:
372   br label %loop
374 loop:
375   %iv = phi i32 [0, %entry], [%iv.next, %loop]
376   %reload = load i32, ptr %loc
377   store i32 0, ptr %loc
378   %iv.next = add i32 %iv, 1
379   %cmp = icmp slt i32 %iv, 200
380   br i1 %cmp, label %loop, label %exit
382 exit:
383   ret i32 %reload
386 declare void @readonly() readonly
388 ; TODO: can legally hoist since value read by call is known
389 define void @test_dominated_readonly(ptr %loc) {
390 ; CHECK-LABEL: @test_dominated_readonly
391 ; CHECK-LABEL: loop:
392 ; CHECK: store i32 0, ptr %loc
393 ; CHECK-LABEL: exit:
394 entry:
395   br label %loop
397 loop:
398   %iv = phi i32 [0, %entry], [%iv.next, %loop]
399   store i32 0, ptr %loc
400   call void @readonly()
401   %iv.next = add i32 %iv, 1
402   %cmp = icmp slt i32 %iv, 200
403   br i1 %cmp, label %loop, label %exit
405 exit:
406   ret void
409 ; While technically possible to hoist the store to %loc, this runs across
410 ; a funemental limitation of alias sets since both stores and the call are
411 ; within the same alias set and we can't distinguish them cheaply.
412 define void @test_aliasset_fn(ptr %loc, ptr %loc2) {
413 ; CHECK-LABEL: @test_aliasset_fn
414 ; CHECK-LABEL: loop:
415 ; CHECK: store i32 0, ptr %loc
416 ; CHECK-LABEL: exit:
417 entry:
418   br label %loop
420 loop:
421   %iv = phi i32 [0, %entry], [%iv.next, %loop]
422   store i32 0, ptr %loc
423   call void @readonly()
424   store i32 %iv, ptr %loc2
425   %iv.next = add i32 %iv, 1
426   %cmp = icmp slt i32 %iv, 200
427   br i1 %cmp, label %loop, label %exit
429 exit:
430   ret void
434 ; If we can't tell if the value is read before the write, we can't hoist the
435 ; write over the potential read (since we don't know the value read)
436 define void @neg_may_read(ptr %loc, i1 %maybe) {
437 ; CHECK-LABEL: @neg_may_read
438 ; CHECK-LABEL: loop:
439 ; CHECK: store i32 0, ptr %loc
440 ; CHECK-LABEL: exit:
441 entry:
442   br label %loop
444 loop:
445   %iv = phi i32 [0, %entry], [%iv.next, %merge]
446   ;; maybe is a placeholder for an unanalyzable condition
447   br i1 %maybe, label %taken, label %merge
448 taken:
449   call void @readonly()
450   br label %merge
451 merge:
452   store i32 0, ptr %loc
453   %iv.next = add i32 %iv, 1
454   %cmp = icmp slt i32 %iv, 200
455   br i1 %cmp, label %loop, label %exit
457 exit:
458   ret void