• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
5
6declare {}* @llvm.invariant.start.p0i8(i64, i8* nocapture) nounwind readonly
7declare void @llvm.invariant.end.p0i8({}*, i64, i8* 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(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
17;
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
24;
25
26  %V1 = load i8, i8* %P
27  %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
28  %V2 = load i8, i8* %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(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
41;
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
48;
49
50  store i8 42, i8* %P
51  %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
52  %V1 = load i8, i8* %P
53  ret i8 %V1
54}
55
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
58; of invariant.start.
59define 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
65;
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
72;
73
74  store i8 50, i8* %P
75  %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
76  store i8 60, i8* %P
77  ret void
78}
79
80
81; FIXME: Now the first store can actually be eliminated, since there is no read within
82; the invariant region, between start and end.
83define 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
91;
92
93
94  store i8 50, i8* %P
95  %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
96  call void @llvm.invariant.end.p0i8({}* %i, i64 1, i8* %P)
97  store i8 60, i8* %P
98  ret void
99}
100
101
102declare void @clobber()
103declare {}* @llvm.invariant.start.p0i32(i64 %size, i32* nocapture %ptr)
104declare void @llvm.invariant.end.p0i32({}*, i64, i32* nocapture) nounwind
105
106define 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
113;
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
121;
122  call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
123  %v1 = load i32, i32* %p
124  call void @clobber()
125  %v2 = load i32, i32* %p
126  %sub = sub i32 %v1, %v2
127  ret i32 %sub
128}
129
130define 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
137;
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
145;
146  %v1 = load i32, i32* %p
147  call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
148  call void @clobber()
149  %v2 = load i32, i32* %p
150  %sub = sub i32 %v1, %v2
151  ret i32 %sub
152}
153
154define 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
162;
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
171;
172  %v1 = load i32, i32* %p
173  call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
174  call void @clobber()
175  call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
176  %v2 = load i32, i32* %p
177  %sub = sub i32 %v1, %v2
178  ret i32 %sub
179}
180
181define 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
189;
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
198;
199  call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
200  call void @clobber()
201  %v1 = load i32, i32* %p
202  call void @clobber()
203  %v2 = load i32, i32* %p
204  %sub = sub i32 %v1, %v2
205  ret i32 %sub
206}
207
208define 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]]
217;
218  %v1 = load i32, i32* %p
219  call void @clobber()
220  call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
221  %v2 = load i32, i32* %p
222  %sub = sub i32 %v1, %v2
223  ret i32 %sub
224}
225
226define 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:%.*]]
232; NO_ASSUME:       taken:
233; NO_ASSUME-NEXT:    call void @clobber()
234; NO_ASSUME-NEXT:    br label [[MERGE]]
235; NO_ASSUME:       merge:
236; NO_ASSUME-NEXT:    ret i32 0
237;
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:%.*]]
243; USE_ASSUME:       taken:
244; USE_ASSUME-NEXT:    call void @clobber()
245; USE_ASSUME-NEXT:    br label [[MERGE]]
246; USE_ASSUME:       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
249;
250  %v1 = load i32, i32* %p
251  call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
252  br i1 %cnd, label %merge, label %taken
253
254taken:
255  call void @clobber()
256  br label %merge
257merge:
258  %v2 = load i32, i32* %p
259  %sub = sub i32 %v1, %v2
260  ret i32 %sub
261}
262
263define 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:%.*]]
268; CHECK:       taken:
269; CHECK-NEXT:    call void @clobber()
270; CHECK-NEXT:    br label [[MERGE]]
271; CHECK:       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]]
276;
277  %v1 = load i32, i32* %p
278  br i1 %cnd, label %merge, label %taken
279
280taken:
281  call void @clobber()
282  br label %merge
283merge:
284  call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
285  %v2 = load i32, i32* %p
286  %sub = sub i32 %v1, %v2
287  ret i32 %sub
288}
289
290; In theory, this version could work, but earlycse is incapable of
291; merging facts along distinct paths.
292define 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:%.*]]
297; CHECK:       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]]
301; CHECK:       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]]
305;
306  %v1 = load i32, i32* %p
307  br i1 %cnd, label %merge, label %taken
308
309taken:
310  call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
311  call void @clobber()
312  br label %merge
313merge:
314  %v2 = load i32, i32* %p
315  %sub = sub i32 %v1, %v2
316  ret i32 %sub
317}
318
319define 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:%.*]]
326; NO_ASSUME:       taken:
327; NO_ASSUME-NEXT:    call void @clobber()
328; NO_ASSUME-NEXT:    br label [[MERGE]]
329; NO_ASSUME:       merge:
330; NO_ASSUME-NEXT:    ret i32 0
331;
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:%.*]]
338; USE_ASSUME:       taken:
339; USE_ASSUME-NEXT:    call void @clobber()
340; USE_ASSUME-NEXT:    br label [[MERGE]]
341; USE_ASSUME:       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
344;
345  call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
346  call void @clobber()
347  %v1 = load i32, i32* %p
348  br i1 %cnd, label %merge, label %taken
349
350taken:
351  call void @clobber()
352  br label %merge
353merge:
354  %v2 = load i32, i32* %p
355  %sub = sub i32 %v1, %v2
356  ret i32 %sub
357}
358
359define 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
366;
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
374;
375  call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
376  %v1 = load i32, i32* %p
377  call void @clobber()
378  store i32 %v1, i32* %p
379  ret void
380}
381
382define 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
389;
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
397;
398  %v1 = load i32, i32* %p
399  call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
400  call void @clobber()
401  store i32 %v1, i32* %p
402  ret void
403}
404
405
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.
409define 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]]
420;
421  call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
422  %v1 = load i32, i32* %p
423  call void @clobber()
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
428  ret i32 %sub
429}
430
431define 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]]
440;
441  call {}* @llvm.invariant.start.p0i32(i64 3, i32* %p)
442  %v1 = load i32, i32* %p
443  call void @clobber()
444  %v2 = load i32, i32* %p
445  %sub = sub i32 %v1, %v2
446  ret i32 %sub
447}
448
449define 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]]
458;
459  call {}* @llvm.invariant.start.p0i32(i64 0, i32* %p)
460  %v1 = load i32, i32* %p
461  call void @clobber()
462  %v2 = load i32, i32* %p
463  %sub = sub i32 %v1, %v2
464  ret i32 %sub
465}
466
467define 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]]
477;
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
481  call void @clobber()
482  %v2 = load i32, i32* %p
483  %sub = sub i32 %v1, %v2
484  ret i32 %sub
485}
486
487define 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]]
497;
498  %scope = call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
499  %v1 = load i32, i32* %p
500  call void @clobber()
501  %v2 = load i32, i32* %p
502  call void @llvm.invariant.end.p0i32({}* %scope, i64 4, i32* %p)
503  %sub = sub i32 %v1, %v2
504  ret i32 %sub
505}
506
507; Invariant load defact starts an invariant.start scope of the appropriate size
508define 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
514;
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
521;
522  %v1 = load i32, i32* %p, !invariant.load !{}
523  call void @clobber()
524  %v2 = load i32, i32* %p
525  %sub = sub i32 %v1, %v2
526  ret i32 %sub
527}
528
529; USE_ASSUME: declare void @llvm.assume(i1 noundef)
530