1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
2 ; RUN: opt < %s -S -early-cse -earlycse-debug-hash | FileCheck %s --check-prefixes=CHECK,NO_ASSUME
3 ; RUN: opt < %s -S -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 !0
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 !0
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 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_bypass_store_load_aatags_2
108 ; NO_ASSUME-SAME: (ptr [[P:%.*]], ptr [[P2:%.*]])
109 ; NO_ASSUME-NEXT: store i8 42, ptr [[P]], align 1
110 ; NO_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]])
111 ; NO_ASSUME-NEXT: store i8 0, ptr [[P2]], align 1
112 ; NO_ASSUME-NEXT: %V1 = load i8, ptr %P, align 1, !tbaa !0
113 ; NO_ASSUME-NEXT: ret i8 %V1
115 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_bypass_store_load_aatags_2
116 ; USE_ASSUME-SAME: (ptr [[P:%.*]], ptr [[P2:%.*]])
117 ; USE_ASSUME-NEXT: store i8 42, ptr [[P]], align 1
118 ; USE_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]])
119 ; USE_ASSUME-NEXT: store i8 0, ptr [[P2]], align 1
120 ; USE_ASSUME-NEXT: %V1 = load i8, ptr %P, align 1, !tbaa !0
121 ; USE_ASSUME-NEXT: ret i8 %V1
125 %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P)
127 %V1 = load i8, ptr %P, !tbaa !0
131 ; We can DSE over invariant.start calls, since the first store to
132 ; %P is valid, and the second store is actually unreachable based on semantics
133 ; of invariant.start.
134 define void @test_bypass3(ptr %P) {
135 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_bypass3
136 ; NO_ASSUME-SAME: (ptr [[P:%.*]])
137 ; NO_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]])
138 ; NO_ASSUME-NEXT: store i8 60, ptr [[P]], align 1
139 ; NO_ASSUME-NEXT: ret void
141 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_bypass3
142 ; USE_ASSUME-SAME: (ptr [[P:%.*]])
143 ; USE_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]])
144 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 1), "nonnull"(ptr [[P]]) ]
145 ; USE_ASSUME-NEXT: store i8 60, ptr [[P]], align 1
146 ; USE_ASSUME-NEXT: ret void
150 %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P)
156 ; FIXME: Now the first store can actually be eliminated, since there is no read within
157 ; the invariant region, between start and end.
158 define void @test_bypass4(ptr %P) {
159 ; CHECK-LABEL: define {{[^@]+}}@test_bypass4
160 ; CHECK-SAME: (ptr [[P:%.*]])
161 ; CHECK-NEXT: store i8 50, ptr [[P]], align 1
162 ; CHECK-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]])
163 ; CHECK-NEXT: call void @llvm.invariant.end.p0(ptr [[I]], i64 1, ptr [[P]])
164 ; CHECK-NEXT: store i8 60, ptr [[P]], align 1
165 ; CHECK-NEXT: ret void
170 %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P)
171 call void @llvm.invariant.end.p0(ptr %i, i64 1, ptr %P)
177 declare void @clobber()
179 define i32 @test_before_load(ptr %p) {
180 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_before_load
181 ; NO_ASSUME-SAME: (ptr [[P:%.*]])
182 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
183 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
184 ; NO_ASSUME-NEXT: call void @clobber()
185 ; NO_ASSUME-NEXT: ret i32 0
187 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_before_load
188 ; USE_ASSUME-SAME: (ptr [[P:%.*]])
189 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
190 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
191 ; USE_ASSUME-NEXT: call void @clobber()
192 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
193 ; USE_ASSUME-NEXT: ret i32 0
195 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
196 %v1 = load i32, ptr %p
198 %v2 = load i32, ptr %p
199 %sub = sub i32 %v1, %v2
203 define i32 @test_before_clobber(ptr %p) {
204 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_before_clobber
205 ; NO_ASSUME-SAME: (ptr [[P:%.*]])
206 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
207 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
208 ; NO_ASSUME-NEXT: call void @clobber()
209 ; NO_ASSUME-NEXT: ret i32 0
211 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_before_clobber
212 ; USE_ASSUME-SAME: (ptr [[P:%.*]])
213 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
214 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
215 ; USE_ASSUME-NEXT: call void @clobber()
216 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
217 ; USE_ASSUME-NEXT: ret i32 0
219 %v1 = load i32, ptr %p
220 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
222 %v2 = load i32, ptr %p
223 %sub = sub i32 %v1, %v2
227 define i32 @test_duplicate_scope(ptr %p) {
228 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_duplicate_scope
229 ; NO_ASSUME-SAME: (ptr [[P:%.*]])
230 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
231 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
232 ; NO_ASSUME-NEXT: call void @clobber()
233 ; NO_ASSUME-NEXT: [[TMP2:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
234 ; NO_ASSUME-NEXT: ret i32 0
236 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_duplicate_scope
237 ; USE_ASSUME-SAME: (ptr [[P:%.*]])
238 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
239 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
240 ; USE_ASSUME-NEXT: call void @clobber()
241 ; USE_ASSUME-NEXT: [[TMP2:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
242 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
243 ; USE_ASSUME-NEXT: ret i32 0
245 %v1 = load i32, ptr %p
246 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
248 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
249 %v2 = load i32, ptr %p
250 %sub = sub i32 %v1, %v2
254 define i32 @test_unanalzyable_load(ptr %p) {
255 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_unanalzyable_load
256 ; NO_ASSUME-SAME: (ptr [[P:%.*]])
257 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
258 ; NO_ASSUME-NEXT: call void @clobber()
259 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
260 ; NO_ASSUME-NEXT: call void @clobber()
261 ; NO_ASSUME-NEXT: ret i32 0
263 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_unanalzyable_load
264 ; USE_ASSUME-SAME: (ptr [[P:%.*]])
265 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
266 ; USE_ASSUME-NEXT: call void @clobber()
267 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
268 ; USE_ASSUME-NEXT: call void @clobber()
269 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
270 ; USE_ASSUME-NEXT: ret i32 0
272 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
274 %v1 = load i32, ptr %p
276 %v2 = load i32, ptr %p
277 %sub = sub i32 %v1, %v2
281 define i32 @test_negative_after_clobber(ptr %p) {
282 ; CHECK-LABEL: define {{[^@]+}}@test_negative_after_clobber
283 ; CHECK-SAME: (ptr [[P:%.*]])
284 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
285 ; CHECK-NEXT: call void @clobber()
286 ; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
287 ; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4
288 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
289 ; CHECK-NEXT: ret i32 [[SUB]]
291 %v1 = load i32, ptr %p
293 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
294 %v2 = load i32, ptr %p
295 %sub = sub i32 %v1, %v2
299 define i32 @test_merge(ptr %p, i1 %cnd) {
300 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_merge
301 ; NO_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]])
302 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
303 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
304 ; NO_ASSUME-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]]
306 ; NO_ASSUME-NEXT: call void @clobber()
307 ; NO_ASSUME-NEXT: br label [[MERGE]]
309 ; NO_ASSUME-NEXT: ret i32 0
311 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_merge
312 ; USE_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]])
313 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
314 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
315 ; USE_ASSUME-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]]
317 ; USE_ASSUME-NEXT: call void @clobber()
318 ; USE_ASSUME-NEXT: br label [[MERGE]]
320 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
321 ; USE_ASSUME-NEXT: ret i32 0
323 %v1 = load i32, ptr %p
324 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
325 br i1 %cnd, label %merge, label %taken
331 %v2 = load i32, ptr %p
332 %sub = sub i32 %v1, %v2
336 define i32 @test_negative_after_mergeclobber(ptr %p, i1 %cnd) {
337 ; CHECK-LABEL: define {{[^@]+}}@test_negative_after_mergeclobber
338 ; CHECK-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]])
339 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
340 ; CHECK-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]]
342 ; CHECK-NEXT: call void @clobber()
343 ; CHECK-NEXT: br label [[MERGE]]
345 ; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
346 ; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4
347 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
348 ; CHECK-NEXT: ret i32 [[SUB]]
350 %v1 = load i32, ptr %p
351 br i1 %cnd, label %merge, label %taken
357 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
358 %v2 = load i32, ptr %p
359 %sub = sub i32 %v1, %v2
363 ; In theory, this version could work, but earlycse is incapable of
364 ; merging facts along distinct paths.
365 define i32 @test_false_negative_merge(ptr %p, i1 %cnd) {
366 ; CHECK-LABEL: define {{[^@]+}}@test_false_negative_merge
367 ; CHECK-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]])
368 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
369 ; CHECK-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]]
371 ; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
372 ; CHECK-NEXT: call void @clobber()
373 ; CHECK-NEXT: br label [[MERGE]]
375 ; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4
376 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
377 ; CHECK-NEXT: ret i32 [[SUB]]
379 %v1 = load i32, ptr %p
380 br i1 %cnd, label %merge, label %taken
383 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
387 %v2 = load i32, ptr %p
388 %sub = sub i32 %v1, %v2
392 define i32 @test_merge_unanalyzable_load(ptr %p, i1 %cnd) {
393 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_merge_unanalyzable_load
394 ; NO_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]])
395 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
396 ; NO_ASSUME-NEXT: call void @clobber()
397 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
398 ; NO_ASSUME-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]]
400 ; NO_ASSUME-NEXT: call void @clobber()
401 ; NO_ASSUME-NEXT: br label [[MERGE]]
403 ; NO_ASSUME-NEXT: ret i32 0
405 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_merge_unanalyzable_load
406 ; USE_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]])
407 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
408 ; USE_ASSUME-NEXT: call void @clobber()
409 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
410 ; USE_ASSUME-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]]
412 ; USE_ASSUME-NEXT: call void @clobber()
413 ; USE_ASSUME-NEXT: br label [[MERGE]]
415 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
416 ; USE_ASSUME-NEXT: ret i32 0
418 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
420 %v1 = load i32, ptr %p
421 br i1 %cnd, label %merge, label %taken
427 %v2 = load i32, ptr %p
428 %sub = sub i32 %v1, %v2
432 define void @test_dse_before_load(ptr %p, i1 %cnd) {
433 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_dse_before_load
434 ; NO_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]])
435 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
436 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
437 ; NO_ASSUME-NEXT: call void @clobber()
438 ; NO_ASSUME-NEXT: ret void
440 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_dse_before_load
441 ; USE_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]])
442 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
443 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
444 ; USE_ASSUME-NEXT: call void @clobber()
445 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
446 ; USE_ASSUME-NEXT: ret void
448 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
449 %v1 = load i32, ptr %p
451 store i32 %v1, ptr %p
455 define void @test_dse_after_load(ptr %p, i1 %cnd) {
456 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_dse_after_load
457 ; NO_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]])
458 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
459 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
460 ; NO_ASSUME-NEXT: call void @clobber()
461 ; NO_ASSUME-NEXT: ret void
463 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_dse_after_load
464 ; USE_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]])
465 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
466 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
467 ; USE_ASSUME-NEXT: call void @clobber()
468 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
469 ; USE_ASSUME-NEXT: ret void
471 %v1 = load i32, ptr %p
472 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
474 store i32 %v1, ptr %p
479 ; In this case, we have a false negative since MemoryLocation is implicitly
480 ; typed due to the user of a Value to represent the address. Note that other
481 ; passes will canonicalize away the bitcasts in this example.
482 define i32 @test_false_negative_types(ptr %p) {
483 ; CHECK-LABEL: define {{[^@]+}}@test_false_negative_types
484 ; CHECK-SAME: (ptr [[P:%.*]])
485 ; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
486 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
487 ; CHECK-NEXT: call void @clobber()
488 ; CHECK-NEXT: [[V2F:%.*]] = load float, ptr [[P]], align 4
489 ; CHECK-NEXT: [[V2:%.*]] = bitcast float [[V2F]] to i32
490 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
491 ; CHECK-NEXT: ret i32 [[SUB]]
493 call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
494 %v1 = load i32, ptr %p
496 %v2f = load float, ptr %p
497 %v2 = bitcast float %v2f to i32
498 %sub = sub i32 %v1, %v2
502 define i32 @test_negative_size1(ptr %p) {
503 ; CHECK-LABEL: define {{[^@]+}}@test_negative_size1
504 ; CHECK-SAME: (ptr [[P:%.*]])
505 ; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 3, ptr [[P]])
506 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
507 ; CHECK-NEXT: call void @clobber()
508 ; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4
509 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
510 ; CHECK-NEXT: ret i32 [[SUB]]
512 call ptr @llvm.invariant.start.p0(i64 3, ptr %p)
513 %v1 = load i32, ptr %p
515 %v2 = load i32, ptr %p
516 %sub = sub i32 %v1, %v2
520 define i32 @test_negative_size2(ptr %p) {
521 ; CHECK-LABEL: define {{[^@]+}}@test_negative_size2
522 ; CHECK-SAME: (ptr [[P:%.*]])
523 ; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 0, ptr [[P]])
524 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
525 ; CHECK-NEXT: call void @clobber()
526 ; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4
527 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
528 ; CHECK-NEXT: ret i32 [[SUB]]
530 call ptr @llvm.invariant.start.p0(i64 0, ptr %p)
531 %v1 = load i32, ptr %p
533 %v2 = load i32, ptr %p
534 %sub = sub i32 %v1, %v2
538 define i32 @test_negative_scope(ptr %p) {
539 ; CHECK-LABEL: define {{[^@]+}}@test_negative_scope
540 ; CHECK-SAME: (ptr [[P:%.*]])
541 ; CHECK-NEXT: [[SCOPE:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
542 ; CHECK-NEXT: call void @llvm.invariant.end.p0(ptr [[SCOPE]], i64 4, ptr [[P]])
543 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
544 ; CHECK-NEXT: call void @clobber()
545 ; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4
546 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
547 ; CHECK-NEXT: ret i32 [[SUB]]
549 %scope = call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
550 call void @llvm.invariant.end.p0(ptr %scope, i64 4, ptr %p)
551 %v1 = load i32, ptr %p
553 %v2 = load i32, ptr %p
554 %sub = sub i32 %v1, %v2
558 define i32 @test_false_negative_scope(ptr %p) {
559 ; CHECK-LABEL: define {{[^@]+}}@test_false_negative_scope
560 ; CHECK-SAME: (ptr [[P:%.*]])
561 ; CHECK-NEXT: [[SCOPE:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]])
562 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
563 ; CHECK-NEXT: call void @clobber()
564 ; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4
565 ; CHECK-NEXT: call void @llvm.invariant.end.p0(ptr [[SCOPE]], i64 4, ptr [[P]])
566 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
567 ; CHECK-NEXT: ret i32 [[SUB]]
569 %scope = call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
570 %v1 = load i32, ptr %p
572 %v2 = load i32, ptr %p
573 call void @llvm.invariant.end.p0(ptr %scope, i64 4, ptr %p)
574 %sub = sub i32 %v1, %v2
578 ; Invariant load defact starts an invariant.start scope of the appropriate size
579 define i32 @test_invariant_load_scope(ptr %p) {
580 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_invariant_load_scope
581 ; NO_ASSUME-SAME: (ptr [[P:%.*]])
582 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4, !invariant.load !4
583 ; NO_ASSUME-NEXT: call void @clobber()
584 ; NO_ASSUME-NEXT: ret i32 0
586 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_invariant_load_scope
587 ; USE_ASSUME-SAME: (ptr [[P:%.*]])
588 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4, !invariant.load !4
589 ; USE_ASSUME-NEXT: call void @clobber()
590 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]
591 ; USE_ASSUME-NEXT: ret i32 0
593 %v1 = load i32, ptr %p, !invariant.load !{}
595 %v2 = load i32, ptr %p
596 %sub = sub i32 %v1, %v2
600 ; USE_ASSUME: declare void @llvm.assume(i1 noundef)
602 !0 = !{!1, !1, i64 0}
603 !1 = !{!"float", !2, i64 0}
604 !2 = !{!"omnipotent char", !3, i64 0}
605 !3 = !{!"Simple C/C++ TBAA"}