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) {
6 ; CHECK: store i32 0, ptr %loc
12 %iv = phi i32 [0, %entry], [%iv.next, %loop]
14 %iv.next = add i32 %iv, 1
15 %cmp = icmp slt i32 %iv, 200
16 br i1 %cmp, label %loop, label %exit
22 define void @test_multiexit(ptr %loc, i1 %earlycnd) {
23 ; CHECK-LABEL: @test_multiexit
25 ; CHECK: store i32 0, ptr %loc
31 %iv = phi i32 [0, %entry], [%iv.next, %backedge]
33 %iv.next = add i32 %iv, 1
34 br i1 %earlycnd, label %exit1, label %backedge
37 %cmp = icmp slt i32 %iv, 200
38 br i1 %cmp, label %loop, label %exit2
46 define ptr @false_negative_2use(ptr %loc) {
47 ; CHECK-LABEL: @false_negative_2use
49 ; CHECK: store i32 0, ptr %loc
55 %iv = phi i32 [0, %entry], [%iv.next, %loop]
57 %iv.next = add i32 %iv, 1
58 %cmp = icmp slt i32 %iv, 200
59 br i1 %cmp, label %loop, label %exit
65 define void @neg_lv_value(ptr %loc) {
66 ; CHECK-LABEL: @neg_lv_value
68 ; CHECK: store i32 %iv.lcssa, ptr %loc
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
83 define void @neg_lv_addr(ptr %loc) {
84 ; CHECK-LABEL: @neg_lv_addr
86 ; CHECK: store i32 0, ptr %p
92 %iv = phi i32 [0, %entry], [%iv.next, %loop]
93 %p = getelementptr i32, ptr %loc, i32 %iv
95 %iv.next = add i32 %iv, 1
96 %cmp = icmp slt i32 %iv, 200
97 br i1 %cmp, label %loop, label %exit
103 define void @neg_mod(ptr %loc) {
104 ; CHECK-LABEL: @neg_mod
106 ; CHECK: store i32 %iv.lcssa, ptr %loc
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
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
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
140 %iv.next = add i32 %iv, 1
141 %cmp = icmp slt i32 %iv, 200
142 br i1 %cmp, label %loop, label %exit2
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
158 store i32 198, ptr %loc
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
169 %iv.next = add i32 %iv, 1
170 %cmp = icmp slt i32 %iv, 200
171 br i1 %cmp, label %loop, label %exit2
179 declare void @modref()
181 define void @neg_modref(ptr %loc) {
182 ; CHECK-LABEL: @neg_modref
184 ; CHECK: store i32 0, ptr %loc
190 %iv = phi i32 [0, %entry], [%iv.next, %loop]
191 store i32 0, ptr %loc
193 %iv.next = add i32 %iv, 1
194 %cmp = icmp slt i32 %iv, 200
195 br i1 %cmp, label %loop, label %exit
201 define void @neg_fence(ptr %loc) {
202 ; CHECK-LABEL: @neg_fence
204 ; CHECK: store i32 0, ptr %loc
210 %iv = phi i32 [0, %entry], [%iv.next, %loop]
211 store i32 0, ptr %loc
213 %iv.next = add i32 %iv, 1
214 %cmp = icmp slt i32 %iv, 200
215 br i1 %cmp, label %loop, label %exit
221 define void @neg_volatile(ptr %loc) {
222 ; CHECK-LABEL: @neg_volatile
224 ; CHECK: store volatile i32 0, ptr %loc
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
240 define void @neg_release(ptr %loc) {
241 ; CHECK-LABEL: @neg_release
243 ; CHECK: store atomic i32 0, ptr %loc release, align 4
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
259 define void @neg_seq_cst(ptr %loc) {
260 ; CHECK-LABEL: @neg_seq_cst
262 ; CHECK: store atomic i32 0, ptr %loc seq_cst, align 4
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
278 declare void @maythrow() inaccessiblememonly
280 define void @neg_early_exit(ptr %loc) {
281 ; CHECK-LABEL: @neg_early_exit
283 ; CHECK: store i32 0, ptr %loc
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
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
303 define void @neg_early_throw(ptr %loc) {
304 ; CHECK-LABEL: @neg_early_throw
306 ; CHECK: store i32 0, ptr %loc
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
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
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
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
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
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
370 ; CHECK: store i32 0, ptr %loc
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
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
392 ; CHECK: store i32 0, ptr %loc
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
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
415 ; CHECK: store i32 0, ptr %loc
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
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
439 ; CHECK: store i32 0, ptr %loc
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
449 call void @readonly()
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