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 {}* @llvm.invariant.start.p0i8(i64, i8* nocapture) nounwind readonly
7 declare void @llvm.invariant.end.p0i8({}*, i64, i8* nocapture) nounwind
9 ; Check that we do load-load forwarding over invariant.start, since it does not
11 define i8 @test_bypass1(i8 *%P) {
12 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_bypass1
13 ; NO_ASSUME-SAME: (i8* [[P:%.*]])
14 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i8, i8* [[P]], align 1
15 ; NO_ASSUME-NEXT: [[I:%.*]] = call {}* @llvm.invariant.start.p0i8(i64 1, i8* [[P]])
16 ; NO_ASSUME-NEXT: ret i8 0
18 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_bypass1
19 ; USE_ASSUME-SAME: (i8* [[P:%.*]])
20 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i8, i8* [[P]], align 1
21 ; USE_ASSUME-NEXT: [[I:%.*]] = call {}* @llvm.invariant.start.p0i8(i64 1, i8* [[P]])
22 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i8* [[P]], i64 1), "nonnull"(i8* [[P]]) ]
23 ; USE_ASSUME-NEXT: ret i8 0
27 %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
29 %Diff = sub i8 %V1, %V2
34 ; Trivial Store->load forwarding over invariant.start
35 define i8 @test_bypass2(i8 *%P) {
36 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_bypass2
37 ; NO_ASSUME-SAME: (i8* [[P:%.*]])
38 ; NO_ASSUME-NEXT: store i8 42, i8* [[P]], align 1
39 ; NO_ASSUME-NEXT: [[I:%.*]] = call {}* @llvm.invariant.start.p0i8(i64 1, i8* [[P]])
40 ; NO_ASSUME-NEXT: ret i8 42
42 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_bypass2
43 ; USE_ASSUME-SAME: (i8* [[P:%.*]])
44 ; USE_ASSUME-NEXT: store i8 42, i8* [[P]], align 1
45 ; USE_ASSUME-NEXT: [[I:%.*]] = call {}* @llvm.invariant.start.p0i8(i64 1, i8* [[P]])
46 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i8* [[P]], i64 1), "nonnull"(i8* [[P]]) ]
47 ; USE_ASSUME-NEXT: ret i8 42
51 %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
56 ; We can DSE over invariant.start calls, since the first store to
57 ; %P is valid, and the second store is actually unreachable based on semantics
59 define void @test_bypass3(i8* %P) {
60 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_bypass3
61 ; NO_ASSUME-SAME: (i8* [[P:%.*]])
62 ; NO_ASSUME-NEXT: [[I:%.*]] = call {}* @llvm.invariant.start.p0i8(i64 1, i8* [[P]])
63 ; NO_ASSUME-NEXT: store i8 60, i8* [[P]], align 1
64 ; NO_ASSUME-NEXT: ret void
66 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_bypass3
67 ; USE_ASSUME-SAME: (i8* [[P:%.*]])
68 ; USE_ASSUME-NEXT: [[I:%.*]] = call {}* @llvm.invariant.start.p0i8(i64 1, i8* [[P]])
69 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i8* [[P]], i64 1), "nonnull"(i8* [[P]]) ]
70 ; USE_ASSUME-NEXT: store i8 60, i8* [[P]], align 1
71 ; USE_ASSUME-NEXT: ret void
75 %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
81 ; FIXME: Now the first store can actually be eliminated, since there is no read within
82 ; the invariant region, between start and end.
83 define void @test_bypass4(i8* %P) {
84 ; CHECK-LABEL: define {{[^@]+}}@test_bypass4
85 ; CHECK-SAME: (i8* [[P:%.*]])
86 ; CHECK-NEXT: store i8 50, i8* [[P]], align 1
87 ; CHECK-NEXT: [[I:%.*]] = call {}* @llvm.invariant.start.p0i8(i64 1, i8* [[P]])
88 ; CHECK-NEXT: call void @llvm.invariant.end.p0i8({}* [[I]], i64 1, i8* [[P]])
89 ; CHECK-NEXT: store i8 60, i8* [[P]], align 1
90 ; CHECK-NEXT: ret void
95 %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
96 call void @llvm.invariant.end.p0i8({}* %i, i64 1, i8* %P)
102 declare void @clobber()
103 declare {}* @llvm.invariant.start.p0i32(i64 %size, i32* nocapture %ptr)
104 declare void @llvm.invariant.end.p0i32({}*, i64, i32* nocapture) nounwind
106 define i32 @test_before_load(i32* %p) {
107 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_before_load
108 ; NO_ASSUME-SAME: (i32* [[P:%.*]])
109 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
110 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
111 ; NO_ASSUME-NEXT: call void @clobber()
112 ; NO_ASSUME-NEXT: ret i32 0
114 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_before_load
115 ; USE_ASSUME-SAME: (i32* [[P:%.*]])
116 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
117 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
118 ; USE_ASSUME-NEXT: call void @clobber()
119 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]), "align"(i32* [[P]], i64 4) ]
120 ; USE_ASSUME-NEXT: ret i32 0
122 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
123 %v1 = load i32, i32* %p
125 %v2 = load i32, i32* %p
126 %sub = sub i32 %v1, %v2
130 define i32 @test_before_clobber(i32* %p) {
131 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_before_clobber
132 ; NO_ASSUME-SAME: (i32* [[P:%.*]])
133 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
134 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
135 ; NO_ASSUME-NEXT: call void @clobber()
136 ; NO_ASSUME-NEXT: ret i32 0
138 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_before_clobber
139 ; USE_ASSUME-SAME: (i32* [[P:%.*]])
140 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
141 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
142 ; USE_ASSUME-NEXT: call void @clobber()
143 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]), "align"(i32* [[P]], i64 4) ]
144 ; USE_ASSUME-NEXT: ret i32 0
146 %v1 = load i32, i32* %p
147 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
149 %v2 = load i32, i32* %p
150 %sub = sub i32 %v1, %v2
154 define i32 @test_duplicate_scope(i32* %p) {
155 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_duplicate_scope
156 ; NO_ASSUME-SAME: (i32* [[P:%.*]])
157 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
158 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
159 ; NO_ASSUME-NEXT: call void @clobber()
160 ; NO_ASSUME-NEXT: [[TMP2:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
161 ; NO_ASSUME-NEXT: ret i32 0
163 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_duplicate_scope
164 ; USE_ASSUME-SAME: (i32* [[P:%.*]])
165 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
166 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
167 ; USE_ASSUME-NEXT: call void @clobber()
168 ; USE_ASSUME-NEXT: [[TMP2:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
169 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]), "align"(i32* [[P]], i64 4) ]
170 ; USE_ASSUME-NEXT: ret i32 0
172 %v1 = load i32, i32* %p
173 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
175 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
176 %v2 = load i32, i32* %p
177 %sub = sub i32 %v1, %v2
181 define i32 @test_unanalzyable_load(i32* %p) {
182 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_unanalzyable_load
183 ; NO_ASSUME-SAME: (i32* [[P:%.*]])
184 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
185 ; NO_ASSUME-NEXT: call void @clobber()
186 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
187 ; NO_ASSUME-NEXT: call void @clobber()
188 ; NO_ASSUME-NEXT: ret i32 0
190 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_unanalzyable_load
191 ; USE_ASSUME-SAME: (i32* [[P:%.*]])
192 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
193 ; USE_ASSUME-NEXT: call void @clobber()
194 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
195 ; USE_ASSUME-NEXT: call void @clobber()
196 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]), "align"(i32* [[P]], i64 4) ]
197 ; USE_ASSUME-NEXT: ret i32 0
199 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
201 %v1 = load i32, i32* %p
203 %v2 = load i32, i32* %p
204 %sub = sub i32 %v1, %v2
208 define i32 @test_negative_after_clobber(i32* %p) {
209 ; CHECK-LABEL: define {{[^@]+}}@test_negative_after_clobber
210 ; CHECK-SAME: (i32* [[P:%.*]])
211 ; CHECK-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
212 ; CHECK-NEXT: call void @clobber()
213 ; CHECK-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
214 ; CHECK-NEXT: [[V2:%.*]] = load i32, i32* [[P]], align 4
215 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
216 ; CHECK-NEXT: ret i32 [[SUB]]
218 %v1 = load i32, i32* %p
220 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
221 %v2 = load i32, i32* %p
222 %sub = sub i32 %v1, %v2
226 define i32 @test_merge(i32* %p, i1 %cnd) {
227 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_merge
228 ; NO_ASSUME-SAME: (i32* [[P:%.*]], i1 [[CND:%.*]])
229 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
230 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
231 ; NO_ASSUME-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]]
233 ; NO_ASSUME-NEXT: call void @clobber()
234 ; NO_ASSUME-NEXT: br label [[MERGE]]
236 ; NO_ASSUME-NEXT: ret i32 0
238 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_merge
239 ; USE_ASSUME-SAME: (i32* [[P:%.*]], i1 [[CND:%.*]])
240 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
241 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
242 ; USE_ASSUME-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]]
244 ; USE_ASSUME-NEXT: call void @clobber()
245 ; USE_ASSUME-NEXT: br label [[MERGE]]
247 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]), "align"(i32* [[P]], i64 4) ]
248 ; USE_ASSUME-NEXT: ret i32 0
250 %v1 = load i32, i32* %p
251 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
252 br i1 %cnd, label %merge, label %taken
258 %v2 = load i32, i32* %p
259 %sub = sub i32 %v1, %v2
263 define i32 @test_negative_after_mergeclobber(i32* %p, i1 %cnd) {
264 ; CHECK-LABEL: define {{[^@]+}}@test_negative_after_mergeclobber
265 ; CHECK-SAME: (i32* [[P:%.*]], i1 [[CND:%.*]])
266 ; CHECK-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
267 ; CHECK-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]]
269 ; CHECK-NEXT: call void @clobber()
270 ; CHECK-NEXT: br label [[MERGE]]
272 ; CHECK-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
273 ; CHECK-NEXT: [[V2:%.*]] = load i32, i32* [[P]], align 4
274 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
275 ; CHECK-NEXT: ret i32 [[SUB]]
277 %v1 = load i32, i32* %p
278 br i1 %cnd, label %merge, label %taken
284 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
285 %v2 = load i32, i32* %p
286 %sub = sub i32 %v1, %v2
290 ; In theory, this version could work, but earlycse is incapable of
291 ; merging facts along distinct paths.
292 define i32 @test_false_negative_merge(i32* %p, i1 %cnd) {
293 ; CHECK-LABEL: define {{[^@]+}}@test_false_negative_merge
294 ; CHECK-SAME: (i32* [[P:%.*]], i1 [[CND:%.*]])
295 ; CHECK-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
296 ; CHECK-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]]
298 ; CHECK-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
299 ; CHECK-NEXT: call void @clobber()
300 ; CHECK-NEXT: br label [[MERGE]]
302 ; CHECK-NEXT: [[V2:%.*]] = load i32, i32* [[P]], align 4
303 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
304 ; CHECK-NEXT: ret i32 [[SUB]]
306 %v1 = load i32, i32* %p
307 br i1 %cnd, label %merge, label %taken
310 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
314 %v2 = load i32, i32* %p
315 %sub = sub i32 %v1, %v2
319 define i32 @test_merge_unanalyzable_load(i32* %p, i1 %cnd) {
320 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_merge_unanalyzable_load
321 ; NO_ASSUME-SAME: (i32* [[P:%.*]], i1 [[CND:%.*]])
322 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
323 ; NO_ASSUME-NEXT: call void @clobber()
324 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
325 ; NO_ASSUME-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]]
327 ; NO_ASSUME-NEXT: call void @clobber()
328 ; NO_ASSUME-NEXT: br label [[MERGE]]
330 ; NO_ASSUME-NEXT: ret i32 0
332 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_merge_unanalyzable_load
333 ; USE_ASSUME-SAME: (i32* [[P:%.*]], i1 [[CND:%.*]])
334 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
335 ; USE_ASSUME-NEXT: call void @clobber()
336 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
337 ; USE_ASSUME-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]]
339 ; USE_ASSUME-NEXT: call void @clobber()
340 ; USE_ASSUME-NEXT: br label [[MERGE]]
342 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]), "align"(i32* [[P]], i64 4) ]
343 ; USE_ASSUME-NEXT: ret i32 0
345 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
347 %v1 = load i32, i32* %p
348 br i1 %cnd, label %merge, label %taken
354 %v2 = load i32, i32* %p
355 %sub = sub i32 %v1, %v2
359 define void @test_dse_before_load(i32* %p, i1 %cnd) {
360 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_dse_before_load
361 ; NO_ASSUME-SAME: (i32* [[P:%.*]], i1 [[CND:%.*]])
362 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
363 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
364 ; NO_ASSUME-NEXT: call void @clobber()
365 ; NO_ASSUME-NEXT: ret void
367 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_dse_before_load
368 ; USE_ASSUME-SAME: (i32* [[P:%.*]], i1 [[CND:%.*]])
369 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
370 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
371 ; USE_ASSUME-NEXT: call void @clobber()
372 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]), "align"(i32* [[P]], i64 4) ]
373 ; USE_ASSUME-NEXT: ret void
375 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
376 %v1 = load i32, i32* %p
378 store i32 %v1, i32* %p
382 define void @test_dse_after_load(i32* %p, i1 %cnd) {
383 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_dse_after_load
384 ; NO_ASSUME-SAME: (i32* [[P:%.*]], i1 [[CND:%.*]])
385 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
386 ; NO_ASSUME-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
387 ; NO_ASSUME-NEXT: call void @clobber()
388 ; NO_ASSUME-NEXT: ret void
390 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_dse_after_load
391 ; USE_ASSUME-SAME: (i32* [[P:%.*]], i1 [[CND:%.*]])
392 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
393 ; USE_ASSUME-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
394 ; USE_ASSUME-NEXT: call void @clobber()
395 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]), "align"(i32* [[P]], i64 4) ]
396 ; USE_ASSUME-NEXT: ret void
398 %v1 = load i32, i32* %p
399 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
401 store i32 %v1, i32* %p
406 ; In this case, we have a false negative since MemoryLocation is implicitly
407 ; typed due to the user of a Value to represent the address. Note that other
408 ; passes will canonicalize away the bitcasts in this example.
409 define i32 @test_false_negative_types(i32* %p) {
410 ; CHECK-LABEL: define {{[^@]+}}@test_false_negative_types
411 ; CHECK-SAME: (i32* [[P:%.*]])
412 ; CHECK-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
413 ; CHECK-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
414 ; CHECK-NEXT: call void @clobber()
415 ; CHECK-NEXT: [[PF:%.*]] = bitcast i32* [[P]] to float*
416 ; CHECK-NEXT: [[V2F:%.*]] = load float, float* [[PF]], align 4
417 ; CHECK-NEXT: [[V2:%.*]] = bitcast float [[V2F]] to i32
418 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
419 ; CHECK-NEXT: ret i32 [[SUB]]
421 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
422 %v1 = load i32, i32* %p
424 %pf = bitcast i32* %p to float*
425 %v2f = load float, float* %pf
426 %v2 = bitcast float %v2f to i32
427 %sub = sub i32 %v1, %v2
431 define i32 @test_negative_size1(i32* %p) {
432 ; CHECK-LABEL: define {{[^@]+}}@test_negative_size1
433 ; CHECK-SAME: (i32* [[P:%.*]])
434 ; CHECK-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 3, i32* [[P]])
435 ; CHECK-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
436 ; CHECK-NEXT: call void @clobber()
437 ; CHECK-NEXT: [[V2:%.*]] = load i32, i32* [[P]], align 4
438 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
439 ; CHECK-NEXT: ret i32 [[SUB]]
441 call {}* @llvm.invariant.start.p0i32(i64 3, i32* %p)
442 %v1 = load i32, i32* %p
444 %v2 = load i32, i32* %p
445 %sub = sub i32 %v1, %v2
449 define i32 @test_negative_size2(i32* %p) {
450 ; CHECK-LABEL: define {{[^@]+}}@test_negative_size2
451 ; CHECK-SAME: (i32* [[P:%.*]])
452 ; CHECK-NEXT: [[TMP1:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 0, i32* [[P]])
453 ; CHECK-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
454 ; CHECK-NEXT: call void @clobber()
455 ; CHECK-NEXT: [[V2:%.*]] = load i32, i32* [[P]], align 4
456 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
457 ; CHECK-NEXT: ret i32 [[SUB]]
459 call {}* @llvm.invariant.start.p0i32(i64 0, i32* %p)
460 %v1 = load i32, i32* %p
462 %v2 = load i32, i32* %p
463 %sub = sub i32 %v1, %v2
467 define i32 @test_negative_scope(i32* %p) {
468 ; CHECK-LABEL: define {{[^@]+}}@test_negative_scope
469 ; CHECK-SAME: (i32* [[P:%.*]])
470 ; CHECK-NEXT: [[SCOPE:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
471 ; CHECK-NEXT: call void @llvm.invariant.end.p0i32({}* [[SCOPE]], i64 4, i32* [[P]])
472 ; CHECK-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
473 ; CHECK-NEXT: call void @clobber()
474 ; CHECK-NEXT: [[V2:%.*]] = load i32, i32* [[P]], align 4
475 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
476 ; CHECK-NEXT: ret i32 [[SUB]]
478 %scope = call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
479 call void @llvm.invariant.end.p0i32({}* %scope, i64 4, i32* %p)
480 %v1 = load i32, i32* %p
482 %v2 = load i32, i32* %p
483 %sub = sub i32 %v1, %v2
487 define i32 @test_false_negative_scope(i32* %p) {
488 ; CHECK-LABEL: define {{[^@]+}}@test_false_negative_scope
489 ; CHECK-SAME: (i32* [[P:%.*]])
490 ; CHECK-NEXT: [[SCOPE:%.*]] = call {}* @llvm.invariant.start.p0i32(i64 4, i32* [[P]])
491 ; CHECK-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4
492 ; CHECK-NEXT: call void @clobber()
493 ; CHECK-NEXT: [[V2:%.*]] = load i32, i32* [[P]], align 4
494 ; CHECK-NEXT: call void @llvm.invariant.end.p0i32({}* [[SCOPE]], i64 4, i32* [[P]])
495 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]]
496 ; CHECK-NEXT: ret i32 [[SUB]]
498 %scope = call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
499 %v1 = load i32, i32* %p
501 %v2 = load i32, i32* %p
502 call void @llvm.invariant.end.p0i32({}* %scope, i64 4, i32* %p)
503 %sub = sub i32 %v1, %v2
507 ; Invariant load defact starts an invariant.start scope of the appropriate size
508 define i32 @test_invariant_load_scope(i32* %p) {
509 ; NO_ASSUME-LABEL: define {{[^@]+}}@test_invariant_load_scope
510 ; NO_ASSUME-SAME: (i32* [[P:%.*]])
511 ; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4, !invariant.load !0
512 ; NO_ASSUME-NEXT: call void @clobber()
513 ; NO_ASSUME-NEXT: ret i32 0
515 ; USE_ASSUME-LABEL: define {{[^@]+}}@test_invariant_load_scope
516 ; USE_ASSUME-SAME: (i32* [[P:%.*]])
517 ; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, i32* [[P]], align 4, !invariant.load !0
518 ; USE_ASSUME-NEXT: call void @clobber()
519 ; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]), "align"(i32* [[P]], i64 4) ]
520 ; USE_ASSUME-NEXT: ret i32 0
522 %v1 = load i32, i32* %p, !invariant.load !{}
524 %v2 = load i32, i32* %p
525 %sub = sub i32 %v1, %v2
529 ; USE_ASSUME: declare void @llvm.assume(i1 noundef)