[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / llvm / test / Transforms / EarlyCSE / invariant.start.ll
blob554d3ce519b5eedf2f8d9754e0b012f7bcf930f5
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
10 ; clobber memory
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
26   %V1 = load i8, ptr %P
27   %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P)
28   %V2 = load i8, ptr %P
29   %Diff = sub i8 %V1, %V2
30   ret i8 %Diff
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
50   store i8 42, ptr %P
51   %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P)
52   %V1 = load i8, ptr %P
53   ret i8 %V1
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
73   store i8 42, ptr %P
74   %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P)
75   store i8 0, ptr %P2
76   %V1 = load i8, ptr %P
77   ret i8 %V1
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)
99   store i8 0, ptr %P2
100   %V1 = load i8, ptr %P
101   ret i8 %V1
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]]
116   store i8 42, ptr %P
117   %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P)
118   store i8 0, ptr %P2
119   %V1 = load i8, ptr %P, !tbaa !0
120   ret i8 %V1
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
141   store i8 50, ptr %P
142   %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P)
143   store i8 60, ptr %P
144   ret void
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
161   store i8 50, ptr %P
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)
164   store i8 60, ptr %P
165   ret void
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
189   call void @clobber()
190   %v2 = load i32, ptr %p
191   %sub = sub i32 %v1, %v2
192   ret i32 %sub
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)
213   call void @clobber()
214   %v2 = load i32, ptr %p
215   %sub = sub i32 %v1, %v2
216   ret i32 %sub
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)
239   call void @clobber()
240   call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
241   %v2 = load i32, ptr %p
242   %sub = sub i32 %v1, %v2
243   ret i32 %sub
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)
265   call void @clobber()
266   %v1 = load i32, ptr %p
267   call void @clobber()
268   %v2 = load i32, ptr %p
269   %sub = sub i32 %v1, %v2
270   ret i32 %sub
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
284   call void @clobber()
285   call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
286   %v2 = load i32, ptr %p
287   %sub = sub i32 %v1, %v2
288   ret i32 %sub
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:%.*]]
297 ; NO_ASSUME:       taken:
298 ; NO_ASSUME-NEXT:    call void @clobber()
299 ; NO_ASSUME-NEXT:    br label [[MERGE]]
300 ; NO_ASSUME:       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:%.*]]
308 ; USE_ASSUME:       taken:
309 ; USE_ASSUME-NEXT:    call void @clobber()
310 ; USE_ASSUME-NEXT:    br label [[MERGE]]
311 ; USE_ASSUME:       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
319 taken:
320   call void @clobber()
321   br label %merge
322 merge:
323   %v2 = load i32, ptr %p
324   %sub = sub i32 %v1, %v2
325   ret i32 %sub
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:%.*]]
333 ; CHECK:       taken:
334 ; CHECK-NEXT:    call void @clobber()
335 ; CHECK-NEXT:    br label [[MERGE]]
336 ; CHECK:       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
345 taken:
346   call void @clobber()
347   br label %merge
348 merge:
349   call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
350   %v2 = load i32, ptr %p
351   %sub = sub i32 %v1, %v2
352   ret i32 %sub
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:%.*]]
362 ; CHECK:       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]]
366 ; CHECK:       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
374 taken:
375   call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
376   call void @clobber()
377   br label %merge
378 merge:
379   %v2 = load i32, ptr %p
380   %sub = sub i32 %v1, %v2
381   ret i32 %sub
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:%.*]]
391 ; NO_ASSUME:       taken:
392 ; NO_ASSUME-NEXT:    call void @clobber()
393 ; NO_ASSUME-NEXT:    br label [[MERGE]]
394 ; NO_ASSUME:       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:%.*]]
403 ; USE_ASSUME:       taken:
404 ; USE_ASSUME-NEXT:    call void @clobber()
405 ; USE_ASSUME-NEXT:    br label [[MERGE]]
406 ; USE_ASSUME:       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)
411   call void @clobber()
412   %v1 = load i32, ptr %p
413   br i1 %cnd, label %merge, label %taken
415 taken:
416   call void @clobber()
417   br label %merge
418 merge:
419   %v2 = load i32, ptr %p
420   %sub = sub i32 %v1, %v2
421   ret i32 %sub
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
442   call void @clobber()
443   store i32 %v1, ptr %p
444   ret void
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)
465   call void @clobber()
466   store i32 %v1, ptr %p
467   ret void
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
487   call void @clobber()
488   %v2f = load float, ptr %p
489   %v2 = bitcast float %v2f to i32
490   %sub = sub i32 %v1, %v2
491   ret i32 %sub
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
506   call void @clobber()
507   %v2 = load i32, ptr %p
508   %sub = sub i32 %v1, %v2
509   ret i32 %sub
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
524   call void @clobber()
525   %v2 = load i32, ptr %p
526   %sub = sub i32 %v1, %v2
527   ret i32 %sub
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
544   call void @clobber()
545   %v2 = load i32, ptr %p
546   %sub = sub i32 %v1, %v2
547   ret i32 %sub
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
563   call void @clobber()
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
567   ret i32 %sub
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 !{}
586   call void @clobber()
587   %v2 = load i32, ptr %p
588   %sub = sub i32 %v1, %v2
589   ret i32 %sub
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"}