xref: /llvm-project/llvm/test/Transforms/EarlyCSE/invariant.start.ll (revision 1b326be9e84121b24b6f2648c49bad73e88f708a)
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
5
6declare ptr @llvm.invariant.start.p0(i64, ptr nocapture) nounwind readonly
7declare void @llvm.invariant.end.p0(ptr, i64, ptr nocapture) nounwind
8
9; Check that we do load-load forwarding over invariant.start, since it does not
10; clobber memory
11define 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
17;
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
24;
25
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
31}
32
33
34; Trivial Store->load forwarding over invariant.start
35define 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
41;
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
48;
49
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
54}
55
56define 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
63;
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
71;
72
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
78}
79
80define 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
87;
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
95;
96
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
102}
103
104; The test demonstrates a missed optimization opportunity in case when the load
105; has AA tags that are different from the store tags.
106define 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]]
114;
115
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
121}
122
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.
126define 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
132;
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
139;
140
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
145}
146
147
148; FIXME: Now the first store can actually be eliminated, since there is no read within
149; the invariant region, between start and end.
150define 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
158;
159
160
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
166}
167
168
169declare void @clobber()
170
171define 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
178;
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
186;
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
193}
194
195define 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
202;
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
210;
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
217}
218
219define 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
227;
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
236;
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
244}
245
246define 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
254;
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
263;
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
271}
272
273define 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]]
282;
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
289}
290
291define 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
302;
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
314;
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
318
319taken:
320  call void @clobber()
321  br label %merge
322merge:
323  %v2 = load i32, ptr %p
324  %sub = sub i32 %v1, %v2
325  ret i32 %sub
326}
327
328define 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]]
341;
342  %v1 = load i32, ptr %p
343  br i1 %cnd, label %merge, label %taken
344
345taken:
346  call void @clobber()
347  br label %merge
348merge:
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
353}
354
355; In theory, this version could work, but earlycse is incapable of
356; merging facts along distinct paths.
357define 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]]
370;
371  %v1 = load i32, ptr %p
372  br i1 %cnd, label %merge, label %taken
373
374taken:
375  call ptr @llvm.invariant.start.p0(i64 4, ptr %p)
376  call void @clobber()
377  br label %merge
378merge:
379  %v2 = load i32, ptr %p
380  %sub = sub i32 %v1, %v2
381  ret i32 %sub
382}
383
384define 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
396;
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
409;
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
414
415taken:
416  call void @clobber()
417  br label %merge
418merge:
419  %v2 = load i32, ptr %p
420  %sub = sub i32 %v1, %v2
421  ret i32 %sub
422}
423
424define 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
431;
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
439;
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
445}
446
447define 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
454;
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
462;
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
468}
469
470
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.
474define 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]]
484;
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
492}
493
494define 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]]
503;
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
510}
511
512define 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]]
521;
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
528}
529
530define 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]]
540;
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
548}
549
550define 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]]
560;
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
568}
569
570; Invariant load defact starts an invariant.start scope of the appropriate size
571define 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
577;
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
584;
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
590}
591
592; USE_ASSUME: declare void @llvm.assume(i1 noundef)
593
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"}
598