xref: /llvm-project/llvm/test/Transforms/LICM/store-hoisting.ll (revision e390c229a438ed1eb3396df8fbeeda89c49474e6)
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
2
3define void @test(ptr %loc) {
4; CHECK-LABEL: @test
5; CHECK-LABEL: entry:
6; CHECK: store i32 0, ptr %loc
7; CHECK-LABEL: loop:
8entry:
9  br label %loop
10
11loop:
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
17
18exit:
19  ret void
20}
21
22define 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:
27entry:
28  br label %loop
29
30loop:
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
36backedge:
37  %cmp = icmp slt i32 %iv, 200
38  br i1 %cmp, label %loop, label %exit2
39
40exit1:
41  ret void
42exit2:
43  ret void
44}
45
46define 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:
51entry:
52  br label %loop
53
54loop:
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
60
61exit:
62  ret ptr %loc
63}
64
65define void @neg_lv_value(ptr %loc) {
66; CHECK-LABEL: @neg_lv_value
67; CHECK-LABEL: exit:
68; CHECK: store i32 %iv.lcssa, ptr %loc
69entry:
70  br label %loop
71
72loop:
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
78
79exit:
80  ret void
81}
82
83define 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:
88entry:
89  br label %loop
90
91loop:
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
98
99exit:
100  ret void
101}
102
103define void @neg_mod(ptr %loc) {
104; CHECK-LABEL: @neg_mod
105; CHECK-LABEL: exit:
106; CHECK: store i32 %iv.lcssa, ptr %loc
107entry:
108  br label %loop
109
110loop:
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
117
118exit:
119  ret void
120}
121
122; Hoisting the store is actually valid here, as it dominates the load.
123define 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
129entry:
130  br label %loop
131
132loop:
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
139backedge:
140  %iv.next = add i32 %iv, 1
141  %cmp = icmp slt i32 %iv, 200
142  br i1 %cmp, label %loop, label %exit2
143
144exit1:
145  ret void
146exit2:
147  ret void
148}
149
150; Hoisting the store here leads to a miscompile.
151define 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
157entry:
158  store i32 198, ptr %loc
159  br label %loop
160
161loop:
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
168backedge:
169  %iv.next = add i32 %iv, 1
170  %cmp = icmp slt i32 %iv, 200
171  br i1 %cmp, label %loop, label %exit2
172
173exit1:
174  ret void
175exit2:
176  ret void
177}
178
179declare void @modref()
180
181define 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:
186entry:
187  br label %loop
188
189loop:
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
196
197exit:
198  ret void
199}
200
201define 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:
206entry:
207  br label %loop
208
209loop:
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
216
217exit:
218  ret void
219}
220
221define 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:
226entry:
227  br label %loop
228
229loop:
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
235
236exit:
237  ret void
238}
239
240define 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:
245entry:
246  br label %loop
247
248loop:
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
254
255exit:
256  ret void
257}
258
259define 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:
264entry:
265  br label %loop
266
267loop:
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
273
274exit:
275  ret void
276}
277
278declare void @maythrow() inaccessiblememonly
279
280define 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:
285entry:
286  br label %loop
287
288loop:
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
292body:
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
298
299exit:
300  ret void
301}
302
303define 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:
308entry:
309  br label %loop
310
311loop:
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
318
319exit:
320  ret void
321}
322
323define 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:
328entry:
329  br label %loop
330
331loop:
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
338
339exit:
340  ret void
341}
342
343; TODO: could validly hoist the store here since we know what value
344; the load must observe.
345define 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:
350entry:
351  br label %loop
352
353loop:
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
360
361exit:
362  ret i32 %reload
363}
364
365; TODO: could validly hoist the store since we already hoisted the load and
366; it's no longer in the loop.
367define i32 @test_dominating_read(ptr %loc) {
368; CHECK-LABEL: @test_dominating_read
369; CHECK-LABEL: exit:
370; CHECK: store i32 0, ptr %loc
371entry:
372  br label %loop
373
374loop:
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
381
382exit:
383  ret i32 %reload
384}
385
386declare void @readonly() readonly
387
388; TODO: can legally hoist since value read by call is known
389define 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:
394entry:
395  br label %loop
396
397loop:
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
404
405exit:
406  ret void
407}
408
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.
412define 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:
417entry:
418  br label %loop
419
420loop:
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
428
429exit:
430  ret void
431}
432
433
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)
436define 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:
441entry:
442  br label %loop
443
444loop:
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
448taken:
449  call void @readonly()
450  br label %merge
451merge:
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
456
457exit:
458  ret void
459}
460