1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
2 ; RUN: opt < %s -S -passes=early-cse -earlycse-debug-hash | FileCheck %s --check-prefixes=CHECK,NO_ASSUME
3 ; RUN: opt < %s -S -passes=early-cse --enable-knowledge-retention | FileCheck %s --check-prefixes=CHECK,USE_ASSUME
4 ; RUN: opt < %s -S -passes=early-cse | FileCheck %s --check-prefixes=CHECK,NO_ASSUME
6 declare ptr @llvm.invariant.start.p0(i64, ptr nocapture) nounwind readonly
7 declare void @llvm.invariant.end.p0(ptr, i64, ptr nocapture) nounwind
9 ; Check that we do load-load forwarding over invariant.start, since it does not
11 define i8 @test_bypass1(ptr%P) {
12 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_bypass1
13 ; NO_ASSUME-SAME: (ptr [[P:%.*]]) {
14 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i8, ptr [[P]], align 1
15 ; NO_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]])
16 ; NO_ASSUME-NEXT: ret i8 0
18 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_bypass1
19 ; USE_ASSUME-SAME: (ptr [[P:%.*]]) {
20 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i8, ptr [[P]], align 1
21 ; USE_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]])
22 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 1), "nonnull"(ptr [[P]]) ]
23 ; USE_ASSUME-NEXT: ret i8 0
27 %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P)
29 %Diff = sub i8 %V1, %V2
34 ; Trivial Store->load forwarding over invariant.start
35 define i8 @test_bypass2(ptr%P) {
36 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_bypass2
37 ; NO_ASSUME-SAME: (ptr [[P:%.*]]) {
38 ; NO_ASSUME-NEXT: store i8 42, ptr [[P]], align 1
39 ; NO_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]])
40 ; NO_ASSUME-NEXT: ret i8 42
42 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_bypass2
43 ; USE_ASSUME-SAME: (ptr [[P:%.*]]) {
44 ; USE_ASSUME-NEXT: store i8 42, ptr [[P]], align 1
45 ; USE_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]])
46 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 1), "nonnull"(ptr [[P]]) ]
47 ; USE_ASSUME-NEXT: ret i8 42
51 %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P)
56 define i8 @test_bypass_store_load(ptr%P, ptr%P2) {
57 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_bypass_store_load
58 ; NO_ASSUME-SAME: (ptr [[P:%.*]], ptr [[P2:%.*]]) {
59 ; NO_ASSUME-NEXT: store i8 42, ptr [[P]], align 1
60 ; NO_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]])
61 ; NO_ASSUME-NEXT: store i8 0, ptr [[P2]], align 1
62 ; NO_ASSUME-NEXT: ret i8 42
64 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_bypass_store_load
65 ; USE_ASSUME-SAME: (ptr [[P:%.*]], ptr [[P2:%.*]]) {
66 ; USE_ASSUME-NEXT: store i8 42, ptr [[P]], align 1
67 ; USE_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]])
68 ; USE_ASSUME-NEXT: store i8 0, ptr [[P2]], align 1
69 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 1), "nonnull"(ptr [[P]]) ]
70 ; USE_ASSUME-NEXT: ret i8 42
74 %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P)
80 define i8 @test_bypass_store_load_aatags_1(ptr%P, ptr%P2) {
81 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_bypass_store_load_aatags_1
82 ; NO_ASSUME-SAME: (ptr [[P:%.*]], ptr [[P2:%.*]]) {
83 ; NO_ASSUME-NEXT: store i8 42, ptr [[P]], align 1, !tbaa [[TBAA0:![0-9]+]]
84 ; NO_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]])
85 ; NO_ASSUME-NEXT: store i8 0, ptr [[P2]], align 1
86 ; NO_ASSUME-NEXT: ret i8 42
88 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_bypass_store_load_aatags_1
89 ; USE_ASSUME-SAME: (ptr [[P:%.*]], ptr [[P2:%.*]]) {
90 ; USE_ASSUME-NEXT: store i8 42, ptr [[P]], align 1, !tbaa [[TBAA0:![0-9]+]]
91 ; USE_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]])
92 ; USE_ASSUME-NEXT: store i8 0, ptr [[P2]], align 1
93 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 1), "nonnull"(ptr [[P]]) ]
94 ; USE_ASSUME-NEXT: ret i8 42
97 store i8 42, ptr %P, !tbaa !0
98 %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P)
100 %V1 = load i8, ptr %P
104 ; The test demonstrates a missed optimization opportunity in case when the load
105 ; has AA tags that are different from the store tags.
106 define i8 @test_bypass_store_load_aatags_2(ptr%P, ptr%P2) {
107 ; CHECK-LABEL: define {{[^@]+}}@test_bypass_store_load_aatags_2
108 ; CHECK-SAME: (ptr [[P:%.*]], ptr [[P2:%.*]]) {
109 ; CHECK-NEXT: store i8 42, ptr [[P]], align 1
110 ; CHECK-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]])
111 ; CHECK-NEXT: store i8 0, ptr [[P2]], align 1
112 ; CHECK-NEXT: [[V1:%.*]] = load i8, ptr [[P]], align 1, !tbaa [[TBAA0:![0-9]+]]
113 ; CHECK-NEXT: ret i8 [[V1]]
117 %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P)
119 %V1 = load i8, ptr %P, !tbaa !0
123 ; We can DSE over invariant.start calls, since the first store to
124 ; %P is valid, and the second store is actually unreachable based on semantics
125 ; of invariant.start.
126 define void @test_bypass3(ptr %P) {
127 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_bypass3
128 ; NO_ASSUME-SAME: (ptr [[P:%.*]]) {
129 ; NO_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]])
130 ; NO_ASSUME-NEXT: store i8 60, ptr [[P]], align 1
131 ; NO_ASSUME-NEXT: ret void
133 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_bypass3
134 ; USE_ASSUME-SAME: (ptr [[P:%.*]]) {
135 ; USE_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]])
136 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 1), "nonnull"(ptr [[P]]) ]
137 ; USE_ASSUME-NEXT: store i8 60, ptr [[P]], align 1
138 ; USE_ASSUME-NEXT: ret void
142 %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P)
148 ; FIXME: Now the first store can actually be eliminated, since there is no read within
149 ; the invariant region, between start and end.
150 define void @test_bypass4(ptr %P) {
151 ; CHECK-LABEL: define {{[^@]+}}@test_bypass4
152 ; CHECK-SAME: (ptr [[P:%.*]]) {
153 ; CHECK-NEXT: store i8 50, ptr [[P]], align 1
154 ; CHECK-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]])
155 ; CHECK-NEXT: call void @llvm.invariant.end.p0(ptr [[I]], i64 1, ptr [[P]])
156 ; CHECK-NEXT: store i8 60, ptr [[P]], align 1
157 ; CHECK-NEXT: ret void
162 %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P)
163 call void @llvm.invariant.end.p0(ptr %i, i64 1, ptr %P)
169 declare void @clobber()
171 define i32 @test_before_load(ptr %p) {
172 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_before_load
173 ; NO_ASSUME-SAME: (ptr [[P:%.*]]) {
174 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
175 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
176 ; NO_ASSUME-NEXT: call void @clobber()
177 ; NO_ASSUME-NEXT: ret i32 0
179 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_before_load
180 ; USE_ASSUME-SAME: (ptr [[P:%.*]]) {
181 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
182 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
183 ; USE_ASSUME-NEXT: call void @clobber()
184 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
185 ; USE_ASSUME-NEXT: ret i32 0
187 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
188 %v1 = load i32, ptr %p
190 %v2 = load i32, ptr %p
191 %sub = sub i32 %v1, %v2
195 define i32 @test_before_clobber(ptr %p) {
196 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_before_clobber
197 ; NO_ASSUME-SAME: (ptr [[P:%.*]]) {
198 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
199 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
200 ; NO_ASSUME-NEXT: call void @clobber()
201 ; NO_ASSUME-NEXT: ret i32 0
203 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_before_clobber
204 ; USE_ASSUME-SAME: (ptr [[P:%.*]]) {
205 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
206 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
207 ; USE_ASSUME-NEXT: call void @clobber()
208 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
209 ; USE_ASSUME-NEXT: ret i32 0
211 %v1 = load i32, ptr %p
212 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
214 %v2 = load i32, ptr %p
215 %sub = sub i32 %v1, %v2
219 define i32 @test_duplicate_scope(ptr %p) {
220 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_duplicate_scope
221 ; NO_ASSUME-SAME: (ptr [[P:%.*]]) {
222 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
223 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
224 ; NO_ASSUME-NEXT: call void @clobber()
225 ; NO_ASSUME-NEXT: [[TMP2:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
226 ; NO_ASSUME-NEXT: ret i32 0
228 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_duplicate_scope
229 ; USE_ASSUME-SAME: (ptr [[P:%.*]]) {
230 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
231 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
232 ; USE_ASSUME-NEXT: call void @clobber()
233 ; USE_ASSUME-NEXT: [[TMP2:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
234 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
235 ; USE_ASSUME-NEXT: ret i32 0
237 %v1 = load i32, ptr %p
238 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
240 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
241 %v2 = load i32, ptr %p
242 %sub = sub i32 %v1, %v2
246 define i32 @test_unanalzyable_load(ptr %p) {
247 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_unanalzyable_load
248 ; NO_ASSUME-SAME: (ptr [[P:%.*]]) {
249 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
250 ; NO_ASSUME-NEXT: call void @clobber()
251 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
252 ; NO_ASSUME-NEXT: call void @clobber()
253 ; NO_ASSUME-NEXT: ret i32 0
255 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_unanalzyable_load
256 ; USE_ASSUME-SAME: (ptr [[P:%.*]]) {
257 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
258 ; USE_ASSUME-NEXT: call void @clobber()
259 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
260 ; USE_ASSUME-NEXT: call void @clobber()
261 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
262 ; USE_ASSUME-NEXT: ret i32 0
264 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
266 %v1 = load i32, ptr %p
268 %v2 = load i32, ptr %p
269 %sub = sub i32 %v1, %v2
273 define i32 @test_negative_after_clobber(ptr %p) {
274 ; CHECK-LABEL: define {{[^@]+}}@test_negative_after_clobber
275 ; CHECK-SAME: (ptr [[P:%.*]]) {
276 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
277 ; CHECK-NEXT: call void @clobber()
278 ; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
279 ; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4
280 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
281 ; CHECK-NEXT: ret i32 [[SUB]]
283 %v1 = load i32, ptr %p
285 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
286 %v2 = load i32, ptr %p
287 %sub = sub i32 %v1, %v2
291 define i32 @test_merge(ptr %p, i1 %cnd) {
292 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_merge
293 ; NO_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]]) {
294 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
295 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
296 ; NO_ASSUME-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]]
298 ; NO_ASSUME-NEXT: call void @clobber()
299 ; NO_ASSUME-NEXT: br label [[MERGE]]
301 ; NO_ASSUME-NEXT: ret i32 0
303 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_merge
304 ; USE_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]]) {
305 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
306 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
307 ; USE_ASSUME-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]]
309 ; USE_ASSUME-NEXT: call void @clobber()
310 ; USE_ASSUME-NEXT: br label [[MERGE]]
312 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
313 ; USE_ASSUME-NEXT: ret i32 0
315 %v1 = load i32, ptr %p
316 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
317 br i1 %cnd, label %merge, label %taken
323 %v2 = load i32, ptr %p
324 %sub = sub i32 %v1, %v2
328 define i32 @test_negative_after_mergeclobber(ptr %p, i1 %cnd) {
329 ; CHECK-LABEL: define {{[^@]+}}@test_negative_after_mergeclobber
330 ; CHECK-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]]) {
331 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
332 ; CHECK-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]]
334 ; CHECK-NEXT: call void @clobber()
335 ; CHECK-NEXT: br label [[MERGE]]
337 ; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
338 ; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4
339 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
340 ; CHECK-NEXT: ret i32 [[SUB]]
342 %v1 = load i32, ptr %p
343 br i1 %cnd, label %merge, label %taken
349 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
350 %v2 = load i32, ptr %p
351 %sub = sub i32 %v1, %v2
355 ; In theory, this version could work, but earlycse is incapable of
356 ; merging facts along distinct paths.
357 define i32 @test_false_negative_merge(ptr %p, i1 %cnd) {
358 ; CHECK-LABEL: define {{[^@]+}}@test_false_negative_merge
359 ; CHECK-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]]) {
360 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
361 ; CHECK-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]]
363 ; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
364 ; CHECK-NEXT: call void @clobber()
365 ; CHECK-NEXT: br label [[MERGE]]
367 ; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4
368 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
369 ; CHECK-NEXT: ret i32 [[SUB]]
371 %v1 = load i32, ptr %p
372 br i1 %cnd, label %merge, label %taken
375 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
379 %v2 = load i32, ptr %p
380 %sub = sub i32 %v1, %v2
384 define i32 @test_merge_unanalyzable_load(ptr %p, i1 %cnd) {
385 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_merge_unanalyzable_load
386 ; NO_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]]) {
387 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
388 ; NO_ASSUME-NEXT: call void @clobber()
389 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
390 ; NO_ASSUME-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]]
392 ; NO_ASSUME-NEXT: call void @clobber()
393 ; NO_ASSUME-NEXT: br label [[MERGE]]
395 ; NO_ASSUME-NEXT: ret i32 0
397 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_merge_unanalyzable_load
398 ; USE_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]]) {
399 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
400 ; USE_ASSUME-NEXT: call void @clobber()
401 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
402 ; USE_ASSUME-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]]
404 ; USE_ASSUME-NEXT: call void @clobber()
405 ; USE_ASSUME-NEXT: br label [[MERGE]]
407 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
408 ; USE_ASSUME-NEXT: ret i32 0
410 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
412 %v1 = load i32, ptr %p
413 br i1 %cnd, label %merge, label %taken
419 %v2 = load i32, ptr %p
420 %sub = sub i32 %v1, %v2
424 define void @test_dse_before_load(ptr %p, i1 %cnd) {
425 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_dse_before_load
426 ; NO_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]]) {
427 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
428 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
429 ; NO_ASSUME-NEXT: call void @clobber()
430 ; NO_ASSUME-NEXT: ret void
432 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_dse_before_load
433 ; USE_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]]) {
434 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
435 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
436 ; USE_ASSUME-NEXT: call void @clobber()
437 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
438 ; USE_ASSUME-NEXT: ret void
440 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
441 %v1 = load i32, ptr %p
443 store i32 %v1, ptr %p
447 define void @test_dse_after_load(ptr %p, i1 %cnd) {
448 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_dse_after_load
449 ; NO_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]]) {
450 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
451 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
452 ; NO_ASSUME-NEXT: call void @clobber()
453 ; NO_ASSUME-NEXT: ret void
455 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_dse_after_load
456 ; USE_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]]) {
457 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
458 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
459 ; USE_ASSUME-NEXT: call void @clobber()
460 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
461 ; USE_ASSUME-NEXT: ret void
463 %v1 = load i32, ptr %p
464 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
466 store i32 %v1, ptr %p
471 ; In this case, we have a false negative since MemoryLocation is implicitly
472 ; typed due to the user of a Value to represent the address. Note that other
473 ; passes will canonicalize away the bitcasts in this example.
474 define i32 @test_false_negative_types(ptr %p) {
475 ; CHECK-LABEL: define {{[^@]+}}@test_false_negative_types
476 ; CHECK-SAME: (ptr [[P:%.*]]) {
477 ; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
478 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
479 ; CHECK-NEXT: call void @clobber()
480 ; CHECK-NEXT: [[V2F:%.*]] = load float, ptr [[P]], align 4
481 ; CHECK-NEXT: [[V2:%.*]] = bitcast float [[V2F]] to i32
482 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
483 ; CHECK-NEXT: ret i32 [[SUB]]
485 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
486 %v1 = load i32, ptr %p
488 %v2f = load float, ptr %p
489 %v2 = bitcast float %v2f to i32
490 %sub = sub i32 %v1, %v2
494 define i32 @test_negative_size1(ptr %p) {
495 ; CHECK-LABEL: define {{[^@]+}}@test_negative_size1
496 ; CHECK-SAME: (ptr [[P:%.*]]) {
497 ; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 3, ptr [[P]])
498 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
499 ; CHECK-NEXT: call void @clobber()
500 ; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4
501 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
502 ; CHECK-NEXT: ret i32 [[SUB]]
504 call ptr @llvm.invariant.start.p0(i64 3, ptr %p)
505 %v1 = load i32, ptr %p
507 %v2 = load i32, ptr %p
508 %sub = sub i32 %v1, %v2
512 define i32 @test_negative_size2(ptr %p) {
513 ; CHECK-LABEL: define {{[^@]+}}@test_negative_size2
514 ; CHECK-SAME: (ptr [[P:%.*]]) {
515 ; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 0, ptr [[P]])
516 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
517 ; CHECK-NEXT: call void @clobber()
518 ; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4
519 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
520 ; CHECK-NEXT: ret i32 [[SUB]]
522 call ptr @llvm.invariant.start.p0(i64 0, ptr %p)
523 %v1 = load i32, ptr %p
525 %v2 = load i32, ptr %p
526 %sub = sub i32 %v1, %v2
530 define i32 @test_negative_scope(ptr %p) {
531 ; CHECK-LABEL: define {{[^@]+}}@test_negative_scope
532 ; CHECK-SAME: (ptr [[P:%.*]]) {
533 ; CHECK-NEXT: [[SCOPE:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
534 ; CHECK-NEXT: call void @llvm.invariant.end.p0(ptr [[SCOPE]], i64 4, ptr [[P]])
535 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
536 ; CHECK-NEXT: call void @clobber()
537 ; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4
538 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
539 ; CHECK-NEXT: ret i32 [[SUB]]
541 %scope = call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
542 call void @llvm.invariant.end.p0(ptr %scope, i64 4, ptr %p)
543 %v1 = load i32, ptr %p
545 %v2 = load i32, ptr %p
546 %sub = sub i32 %v1, %v2
550 define i32 @test_false_negative_scope(ptr %p) {
551 ; CHECK-LABEL: define {{[^@]+}}@test_false_negative_scope
552 ; CHECK-SAME: (ptr [[P:%.*]]) {
553 ; CHECK-NEXT: [[SCOPE:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
554 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
555 ; CHECK-NEXT: call void @clobber()
556 ; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4
557 ; CHECK-NEXT: call void @llvm.invariant.end.p0(ptr [[SCOPE]], i64 4, ptr [[P]])
558 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
559 ; CHECK-NEXT: ret i32 [[SUB]]
561 %scope = call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
562 %v1 = load i32, ptr %p
564 %v2 = load i32, ptr %p
565 call void @llvm.invariant.end.p0(ptr %scope, i64 4, ptr %p)
566 %sub = sub i32 %v1, %v2
570 ; Invariant load defact starts an invariant.start scope of the appropriate size
571 define i32 @test_invariant_load_scope(ptr %p) {
572 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_invariant_load_scope
573 ; NO_ASSUME-SAME: (ptr [[P:%.*]]) {
574 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4, !invariant.load !4
575 ; NO_ASSUME-NEXT: call void @clobber()
576 ; NO_ASSUME-NEXT: ret i32 0
578 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_invariant_load_scope
579 ; USE_ASSUME-SAME: (ptr [[P:%.*]]) {
580 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4, !invariant.load !4
581 ; USE_ASSUME-NEXT: call void @clobber()
582 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
583 ; USE_ASSUME-NEXT: ret i32 0
585 %v1 = load i32, ptr %p, !invariant.load !{}
587 %v2 = load i32, ptr %p
588 %sub = sub i32 %v1, %v2
592 ; USE_ASSUME: declare void @llvm.assume(i1 noundef)
594 !0 = !{!1, !1, i64 0}
595 !1 = !{!"float", !2, i64 0}
596 !2 = !{!"omnipotent char", !3, i64 0}
597 !3 = !{!"Simple C/C++ TBAA"}