Revert "[InstCombine] Support gep nuw in icmp folds" (#118698)
[llvm-project.git] / llvm / test / Transforms / EarlyCSE / invariant-loads.ll
blob88454660711ed070b6044ba4863de1be475cb904
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -S -passes='early-cse' -earlycse-debug-hash < %s | FileCheck %s --check-prefixes=CHECK,NO_ASSUME
3 ; RUN: opt -S -passes='early-cse<memssa>' < %s | FileCheck %s --check-prefixes=CHECK,NO_ASSUME
4 ; RUN: opt -S -passes='early-cse<memssa>' --enable-knowledge-retention < %s | FileCheck %s --check-prefixes=CHECK,USE_ASSUME
6 declare void @clobber_and_use(i32)
8 define void @f_0(ptr %ptr) {
9 ; NO_ASSUME-LABEL: @f_0(
10 ; NO_ASSUME-NEXT:    [[VAL0:%.*]] = load i32, ptr [[PTR:%.*]], align 4, !invariant.load !0
11 ; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
12 ; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
13 ; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
14 ; NO_ASSUME-NEXT:    ret void
16 ; USE_ASSUME-LABEL: @f_0(
17 ; USE_ASSUME-NEXT:    [[VAL0:%.*]] = load i32, ptr [[PTR:%.*]], align 4, !invariant.load !0
18 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
19 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[PTR]], i64 4), "nonnull"(ptr [[PTR]]), "align"(ptr [[PTR]], i64 4) ]
20 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
21 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
22 ; USE_ASSUME-NEXT:    ret void
25   %val0 = load i32, ptr %ptr, !invariant.load !{}
26   call void @clobber_and_use(i32 %val0)
27   %val1 = load i32, ptr %ptr, !invariant.load !{}
28   call void @clobber_and_use(i32 %val1)
29   %val2 = load i32, ptr %ptr, !invariant.load !{}
30   call void @clobber_and_use(i32 %val2)
31   ret void
34 define void @f_1(ptr %ptr) {
35 ; We can forward invariant loads to non-invariant loads.
36 ; NO_ASSUME-LABEL: @f_1(
37 ; NO_ASSUME-NEXT:    [[VAL0:%.*]] = load i32, ptr [[PTR:%.*]], align 4, !invariant.load !0
38 ; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
39 ; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
40 ; NO_ASSUME-NEXT:    ret void
42 ; USE_ASSUME-LABEL: @f_1(
43 ; USE_ASSUME-NEXT:    [[VAL0:%.*]] = load i32, ptr [[PTR:%.*]], align 4, !invariant.load !0
44 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
45 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[PTR]], i64 4), "nonnull"(ptr [[PTR]]), "align"(ptr [[PTR]], i64 4) ]
46 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
47 ; USE_ASSUME-NEXT:    ret void
50   %val0 = load i32, ptr %ptr, !invariant.load !{}
51   call void @clobber_and_use(i32 %val0)
52   %val1 = load i32, ptr %ptr
53   call void @clobber_and_use(i32 %val1)
54   ret void
57 define void @f_2(ptr %ptr) {
58 ; We can forward a non-invariant load into an invariant load.
59 ; NO_ASSUME-LABEL: @f_2(
60 ; NO_ASSUME-NEXT:    [[VAL0:%.*]] = load i32, ptr [[PTR:%.*]], align 4
61 ; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
62 ; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
63 ; NO_ASSUME-NEXT:    ret void
65 ; USE_ASSUME-LABEL: @f_2(
66 ; USE_ASSUME-NEXT:    [[VAL0:%.*]] = load i32, ptr [[PTR:%.*]], align 4
67 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
68 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[PTR]], i64 4), "nonnull"(ptr [[PTR]]), "align"(ptr [[PTR]], i64 4) ]
69 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
70 ; USE_ASSUME-NEXT:    ret void
73   %val0 = load i32, ptr %ptr
74   call void @clobber_and_use(i32 %val0)
75   %val1 = load i32, ptr %ptr, !invariant.load !{}
76   call void @clobber_and_use(i32 %val1)
77   ret void
80 define void @f_3(i1 %cond, ptr %ptr) {
81 ; NO_ASSUME-LABEL: @f_3(
82 ; NO_ASSUME-NEXT:    [[VAL0:%.*]] = load i32, ptr [[PTR:%.*]], align 4, !invariant.load !0
83 ; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
84 ; NO_ASSUME-NEXT:    br i1 [[COND:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
85 ; NO_ASSUME:       left:
86 ; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
87 ; NO_ASSUME-NEXT:    ret void
88 ; NO_ASSUME:       right:
89 ; NO_ASSUME-NEXT:    ret void
91 ; USE_ASSUME-LABEL: @f_3(
92 ; USE_ASSUME-NEXT:    [[VAL0:%.*]] = load i32, ptr [[PTR:%.*]], align 4, !invariant.load !0
93 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
94 ; USE_ASSUME-NEXT:    br i1 [[COND:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
95 ; USE_ASSUME:       left:
96 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[PTR]], i64 4), "nonnull"(ptr [[PTR]]), "align"(ptr [[PTR]], i64 4) ]
97 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
98 ; USE_ASSUME-NEXT:    ret void
99 ; USE_ASSUME:       right:
100 ; USE_ASSUME-NEXT:    ret void
102   %val0 = load i32, ptr %ptr, !invariant.load !{}
103   call void @clobber_and_use(i32 %val0)
104   br i1 %cond, label %left, label %right
107 left:
108   %val1 = load i32, ptr %ptr
109   call void @clobber_and_use(i32 %val1)
110   ret void
112 right:
113   ret void
116 define void @f_4(i1 %cond, ptr %ptr) {
117 ; Negative test -- can't forward %val0 to %va1 because that'll break
118 ; def-dominates-use.
119 ; CHECK-LABEL: @f_4(
120 ; CHECK-NEXT:    br i1 [[COND:%.*]], label [[LEFT:%.*]], label [[MERGE:%.*]]
121 ; CHECK:       left:
122 ; CHECK-NEXT:    [[VAL0:%.*]] = load i32, ptr [[PTR:%.*]], align 4, !invariant.load !0
123 ; CHECK-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
124 ; CHECK-NEXT:    br label [[MERGE]]
125 ; CHECK:       merge:
126 ; CHECK-NEXT:    [[VAL1:%.*]] = load i32, ptr [[PTR]], align 4
127 ; CHECK-NEXT:    call void @clobber_and_use(i32 [[VAL1]])
128 ; CHECK-NEXT:    ret void
130   br i1 %cond, label %left, label %merge
132 left:
134   %val0 = load i32, ptr %ptr, !invariant.load !{}
135   call void @clobber_and_use(i32 %val0)
136   br label %merge
138 merge:
140   %val1 = load i32, ptr %ptr
141   call void @clobber_and_use(i32 %val1)
142   ret void
145 ; By assumption, the call can't change contents of p
146 ; LangRef is a bit unclear about whether the store is reachable, so
147 ; for the moment we chose to be conservative and just assume it's valid
148 ; to restore the same unchanging value.
149 define void @test_dse1(ptr %p) {
150 ; NO_ASSUME-LABEL: @test_dse1(
151 ; NO_ASSUME-NEXT:    [[V1:%.*]] = load i32, ptr [[P:%.*]], align 4, !invariant.load !0
152 ; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[V1]])
153 ; NO_ASSUME-NEXT:    ret void
155 ; USE_ASSUME-LABEL: @test_dse1(
156 ; USE_ASSUME-NEXT:    [[V1:%.*]] = load i32, ptr [[P:%.*]], align 4, !invariant.load !0
157 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[V1]])
158 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
159 ; USE_ASSUME-NEXT:    ret void
161   %v1 = load i32, ptr %p, !invariant.load !{}
162   call void @clobber_and_use(i32 %v1)
163   store i32 %v1, ptr %p
164   ret void
167 ; By assumption, v1 must equal v2 (TODO)
168 define void @test_false_negative_dse2(ptr %p, i32 %v2) {
169 ; CHECK-LABEL: @test_false_negative_dse2(
170 ; CHECK-NEXT:    [[V1:%.*]] = load i32, ptr [[P:%.*]], align 4, !invariant.load !0
171 ; CHECK-NEXT:    call void @clobber_and_use(i32 [[V1]])
172 ; CHECK-NEXT:    store i32 [[V2:%.*]], ptr [[P]], align 4
173 ; CHECK-NEXT:    ret void
175   %v1 = load i32, ptr %p, !invariant.load !{}
176   call void @clobber_and_use(i32 %v1)
177   store i32 %v2, ptr %p
178   ret void
181 ; If we remove the load, we still start an invariant scope since
182 ; it lets us remove later loads not explicitly marked invariant
183 define void @test_scope_start_without_load(ptr %p) {
184 ; NO_ASSUME-LABEL: @test_scope_start_without_load(
185 ; NO_ASSUME-NEXT:    [[V1:%.*]] = load i32, ptr [[P:%.*]], align 4
186 ; NO_ASSUME-NEXT:    [[ADD:%.*]] = add i32 [[V1]], [[V1]]
187 ; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[ADD]])
188 ; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[V1]])
189 ; NO_ASSUME-NEXT:    ret void
191 ; USE_ASSUME-LABEL: @test_scope_start_without_load(
192 ; USE_ASSUME-NEXT:    [[V1:%.*]] = load i32, ptr [[P:%.*]], align 4
193 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
194 ; USE_ASSUME-NEXT:    [[ADD:%.*]] = add i32 [[V1]], [[V1]]
195 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[ADD]])
196 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[V1]])
197 ; USE_ASSUME-NEXT:    ret void
199   %v1 = load i32, ptr %p
200   %v2 = load i32, ptr %p, !invariant.load !{}
201   %add = add i32 %v1, %v2
202   call void @clobber_and_use(i32 %add)
203   %v3 = load i32, ptr %p
204   call void @clobber_and_use(i32 %v3)
205   ret void
208 ; If we already have an invariant scope, don't want to start a new one
209 ; with a potentially greater generation.  This hides the earlier invariant
210 ; load
211 define void @test_scope_restart(ptr %p) {
212 ; NO_ASSUME-LABEL: @test_scope_restart(
213 ; NO_ASSUME-NEXT:    [[V1:%.*]] = load i32, ptr [[P:%.*]], align 4, !invariant.load !0
214 ; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[V1]])
215 ; NO_ASSUME-NEXT:    [[ADD:%.*]] = add i32 [[V1]], [[V1]]
216 ; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[ADD]])
217 ; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[V1]])
218 ; NO_ASSUME-NEXT:    ret void
220 ; USE_ASSUME-LABEL: @test_scope_restart(
221 ; USE_ASSUME-NEXT:    [[V1:%.*]] = load i32, ptr [[P:%.*]], align 4, !invariant.load !0
222 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[V1]])
223 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
224 ; USE_ASSUME-NEXT:    [[ADD:%.*]] = add i32 [[V1]], [[V1]]
225 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[ADD]])
226 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[V1]])
227 ; USE_ASSUME-NEXT:    ret void
229   %v1 = load i32, ptr %p, !invariant.load !{}
230   call void @clobber_and_use(i32 %v1)
231   %v2 = load i32, ptr %p, !invariant.load !{}
232   %add = add i32 %v1, %v2
233   call void @clobber_and_use(i32 %add)
234   %v3 = load i32, ptr %p
235   call void @clobber_and_use(i32 %v3)
236   ret void