blob: 5fabd0cee0d7c04d96ade7fa4eb99be7aa58af76 [file] [log] [blame]
Anna Thomasb2d12b82016-08-09 20:00:47 +00001; RUN: opt < %s -S -early-cse | FileCheck %s
2; RUN: opt < %s -S -passes=early-cse | FileCheck %s
3
4declare {}* @llvm.invariant.start.p0i8(i64, i8* nocapture) nounwind readonly
5declare void @llvm.invariant.end.p0i8({}*, i64, i8* nocapture) nounwind
6
7; Check that we do load-load forwarding over invariant.start, since it does not
8; clobber memory
Philip Reames0adbb192018-03-14 21:35:06 +00009define i8 @test_bypass1(i8 *%P) {
10 ; CHECK-LABEL: @test_bypass1(
Anna Thomasb2d12b82016-08-09 20:00:47 +000011 ; CHECK-NEXT: %V1 = load i8, i8* %P
12 ; CHECK-NEXT: %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
13 ; CHECK-NEXT: ret i8 0
14
Anna Thomasb2d12b82016-08-09 20:00:47 +000015 %V1 = load i8, i8* %P
16 %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
17 %V2 = load i8, i8* %P
18 %Diff = sub i8 %V1, %V2
19 ret i8 %Diff
20}
21
22
23; Trivial Store->load forwarding over invariant.start
Philip Reames0adbb192018-03-14 21:35:06 +000024define i8 @test_bypass2(i8 *%P) {
25 ; CHECK-LABEL: @test_bypass2(
Anna Thomasb2d12b82016-08-09 20:00:47 +000026 ; CHECK-NEXT: store i8 42, i8* %P
27 ; CHECK-NEXT: %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
28 ; CHECK-NEXT: ret i8 42
29
Anna Thomasb2d12b82016-08-09 20:00:47 +000030 store i8 42, i8* %P
31 %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
32 %V1 = load i8, i8* %P
33 ret i8 %V1
34}
35
36; We can DSE over invariant.start calls, since the first store to
37; %P is valid, and the second store is actually unreachable based on semantics
38; of invariant.start.
Philip Reames0adbb192018-03-14 21:35:06 +000039define void @test_bypass3(i8* %P) {
40; CHECK-LABEL: @test_bypass3(
Anna Thomasb2d12b82016-08-09 20:00:47 +000041; CHECK-NEXT: %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
42; CHECK-NEXT: store i8 60, i8* %P
43
Anna Thomasb2d12b82016-08-09 20:00:47 +000044 store i8 50, i8* %P
45 %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
46 store i8 60, i8* %P
47 ret void
48}
49
50
51; FIXME: Now the first store can actually be eliminated, since there is no read within
52; the invariant region, between start and end.
Philip Reames0adbb192018-03-14 21:35:06 +000053define void @test_bypass4(i8* %P) {
Anna Thomasb2d12b82016-08-09 20:00:47 +000054
Philip Reames0adbb192018-03-14 21:35:06 +000055; CHECK-LABEL: @test_bypass4(
Anna Thomasb2d12b82016-08-09 20:00:47 +000056; CHECK-NEXT: store i8 50, i8* %P
57; CHECK-NEXT: %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
58; CHECK-NEXT: call void @llvm.invariant.end.p0i8({}* %i, i64 1, i8* %P)
59; CHECK-NEXT: store i8 60, i8* %P
60
61
62 store i8 50, i8* %P
63 %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
64 call void @llvm.invariant.end.p0i8({}* %i, i64 1, i8* %P)
65 store i8 60, i8* %P
66 ret void
67}
Philip Reames0adbb192018-03-14 21:35:06 +000068
69
70declare void @clobber()
71declare {}* @llvm.invariant.start.p0i32(i64 %size, i32* nocapture %ptr)
72declare void @llvm.invariant.end.p0i32({}*, i64, i32* nocapture) nounwind
73
74define i32 @test_before_load(i32* %p) {
75; CHECK-LABEL: @test_before_load
76; CHECK: ret i32 0
77 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
78 %v1 = load i32, i32* %p
79 call void @clobber()
80 %v2 = load i32, i32* %p
81 %sub = sub i32 %v1, %v2
82 ret i32 %sub
83}
84
85define i32 @test_before_clobber(i32* %p) {
86; CHECK-LABEL: @test_before_clobber
87; CHECK: ret i32 0
88 %v1 = load i32, i32* %p
89 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
90 call void @clobber()
91 %v2 = load i32, i32* %p
92 %sub = sub i32 %v1, %v2
93 ret i32 %sub
94}
95
96define i32 @test_unanalzyable_load(i32* %p) {
97; CHECK-LABEL: @test_unanalzyable_load
98; CHECK: ret i32 0
99 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
100 call void @clobber()
101 %v1 = load i32, i32* %p
102 call void @clobber()
103 %v2 = load i32, i32* %p
104 %sub = sub i32 %v1, %v2
105 ret i32 %sub
106}
107
108define i32 @test_negative_after_clobber(i32* %p) {
109; CHECK-LABEL: @test_negative_after_clobber
110; CHECK: ret i32 %sub
111 %v1 = load i32, i32* %p
112 call void @clobber()
113 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
114 %v2 = load i32, i32* %p
115 %sub = sub i32 %v1, %v2
116 ret i32 %sub
117}
118
119define i32 @test_merge(i32* %p, i1 %cnd) {
120; CHECK-LABEL: @test_merge
121; CHECK: ret i32 0
122 %v1 = load i32, i32* %p
123 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
124 br i1 %cnd, label %merge, label %taken
125
126taken:
127 call void @clobber()
128 br label %merge
129merge:
130 %v2 = load i32, i32* %p
131 %sub = sub i32 %v1, %v2
132 ret i32 %sub
133}
134
135define i32 @test_negative_after_mergeclobber(i32* %p, i1 %cnd) {
136; CHECK-LABEL: @test_negative_after_mergeclobber
137; CHECK: ret i32 %sub
138 %v1 = load i32, i32* %p
139 br i1 %cnd, label %merge, label %taken
140
141taken:
142 call void @clobber()
143 br label %merge
144merge:
145 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
146 %v2 = load i32, i32* %p
147 %sub = sub i32 %v1, %v2
148 ret i32 %sub
149}
150
151; In theory, this version could work, but earlycse is incapable of
152; merging facts along distinct paths.
153define i32 @test_false_negative_merge(i32* %p, i1 %cnd) {
154; CHECK-LABEL: @test_false_negative_merge
155; CHECK: ret i32 %sub
156 %v1 = load i32, i32* %p
157 br i1 %cnd, label %merge, label %taken
158
159taken:
160 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
161 call void @clobber()
162 br label %merge
163merge:
164 %v2 = load i32, i32* %p
165 %sub = sub i32 %v1, %v2
166 ret i32 %sub
167}
168
169define i32 @test_merge_unanalyzable_load(i32* %p, i1 %cnd) {
170; CHECK-LABEL: @test_merge_unanalyzable_load
171; CHECK: ret i32 0
172 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
173 call void @clobber()
174 %v1 = load i32, i32* %p
175 br i1 %cnd, label %merge, label %taken
176
177taken:
178 call void @clobber()
179 br label %merge
180merge:
181 %v2 = load i32, i32* %p
182 %sub = sub i32 %v1, %v2
183 ret i32 %sub
184}
185
186define void @test_dse_before_load(i32* %p, i1 %cnd) {
187; CHECK-LABEL: @test_dse_before_load
188; CHECK-NOT: store
189 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
190 %v1 = load i32, i32* %p
191 call void @clobber()
192 store i32 %v1, i32* %p
193 ret void
194}
195
196define void @test_dse_after_load(i32* %p, i1 %cnd) {
197; CHECK-LABEL: @test_dse_after_load
198; CHECK-NOT: store
199 %v1 = load i32, i32* %p
200 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
201 call void @clobber()
202 store i32 %v1, i32* %p
203 ret void
204}
205
206
207; In this case, we have a false negative since MemoryLocation is implicitly
208; typed due to the user of a Value to represent the address. Note that other
209; passes will canonicalize away the bitcasts in this example.
210define i32 @test_false_negative_types(i32* %p) {
211; CHECK-LABEL: @test_false_negative_types
212; CHECK: ret i32 %sub
213 call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
214 %v1 = load i32, i32* %p
215 call void @clobber()
216 %pf = bitcast i32* %p to float*
217 %v2f = load float, float* %pf
218 %v2 = bitcast float %v2f to i32
219 %sub = sub i32 %v1, %v2
220 ret i32 %sub
221}
222
223define i32 @test_negative_size1(i32* %p) {
224; CHECK-LABEL: @test_negative_size1
225; CHECK: ret i32 %sub
226 call {}* @llvm.invariant.start.p0i32(i64 3, i32* %p)
227 %v1 = load i32, i32* %p
228 call void @clobber()
229 %v2 = load i32, i32* %p
230 %sub = sub i32 %v1, %v2
231 ret i32 %sub
232}
233
234define i32 @test_negative_size2(i32* %p) {
235; CHECK-LABEL: @test_negative_size2
236; CHECK: ret i32 %sub
237 call {}* @llvm.invariant.start.p0i32(i64 0, i32* %p)
238 %v1 = load i32, i32* %p
239 call void @clobber()
240 %v2 = load i32, i32* %p
241 %sub = sub i32 %v1, %v2
242 ret i32 %sub
243}
244
245define i32 @test_negative_scope(i32* %p) {
246; CHECK-LABEL: @test_negative_scope
247; CHECK: ret i32 %sub
248 %scope = call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
249 call void @llvm.invariant.end.p0i32({}* %scope, i64 4, i32* %p)
250 %v1 = load i32, i32* %p
251 call void @clobber()
252 %v2 = load i32, i32* %p
253 %sub = sub i32 %v1, %v2
254 ret i32 %sub
255}
256
257define i32 @test_false_negative_scope(i32* %p) {
258; CHECK-LABEL: @test_false_negative_scope
259; CHECK: ret i32 %sub
260 %scope = call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p)
261 %v1 = load i32, i32* %p
262 call void @clobber()
263 %v2 = load i32, i32* %p
264 call void @llvm.invariant.end.p0i32({}* %scope, i64 4, i32* %p)
265 %sub = sub i32 %v1, %v2
266 ret i32 %sub
267}
268
269; Invariant load defact starts an invariant.start scope of the appropriate size
270define i32 @test_invariant_load_scope(i32* %p) {
271; CHECK-LABEL: @test_invariant_load_scope
272; CHECK: ret i32 0
273 %v1 = load i32, i32* %p, !invariant.load !{}
274 call void @clobber()
275 %v2 = load i32, i32* %p
276 %sub = sub i32 %v1, %v2
277 ret i32 %sub
278}