[ARM] Better OR's for MVE compares
[llvm-core.git] / test / Analysis / MemorySSA / invariant-groups.ll
blob14f83cbd17aad71f219204eb9188b3bbe330060f
1 ; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %s 2>&1 | FileCheck %s
3 ; Currently, MemorySSA doesn't support invariant groups. So, we should ignore
4 ; launder.invariant.group intrinsics entirely. We'll need to pay attention to
5 ; them when/if we decide to support invariant groups.
7 @g = external global i32
9 define i32 @foo(i32* %a) {
10 ; CHECK: 1 = MemoryDef(liveOnEntry)
11 ; CHECK-NEXT: store i32 0
12   store i32 0, i32* %a, align 4, !invariant.group !0
14 ; CHECK: 2 = MemoryDef(1)
15 ; CHECK-NEXT: store i32 1
16   store i32 1, i32* @g, align 4
18   %1 = bitcast i32* %a to i8*
19 ; CHECK:  3 = MemoryDef(2)
20 ; CHECK-NEXT: %a8 = call i8* @llvm.launder.invariant.group.p0i8(i8* %1)
21   %a8 = call i8* @llvm.launder.invariant.group.p0i8(i8* %1)
22   %a32 = bitcast i8* %a8 to i32*
24 ; This have to be MemoryUse(2), because we can't skip the barrier based on
25 ; invariant.group.
26 ; CHECK: MemoryUse(2)
27 ; CHECK-NEXT: %2 = load i32
28   %2 = load i32, i32* %a32, align 4, !invariant.group !0
29   ret i32 %2
32 define i32 @skipBarrier(i32* %a) {
33 ; CHECK: 1 = MemoryDef(liveOnEntry)
34 ; CHECK-NEXT: store i32 0
35   store i32 0, i32* %a, align 4, !invariant.group !0
37   %1 = bitcast i32* %a to i8*
38 ; CHECK: 2 = MemoryDef(1)
39 ; CHECK-NEXT: %a8 = call i8* @llvm.launder.invariant.group.p0i8(i8* %1)
40   %a8 = call i8* @llvm.launder.invariant.group.p0i8(i8* %1)  
41   %a32 = bitcast i8* %a8 to i32*
43 ; We can skip the barrier only if the "skip" is not based on !invariant.group.
44 ; CHECK: MemoryUse(1)
45 ; CHECK-NEXT: %2 = load i32
46   %2 = load i32, i32* %a32, align 4, !invariant.group !0
47   ret i32 %2
50 define i32 @skipBarrier2(i32* %a) {
52 ; CHECK: MemoryUse(liveOnEntry)
53 ; CHECK-NEXT: %v = load i32
54   %v = load i32, i32* %a, align 4, !invariant.group !0
56   %1 = bitcast i32* %a to i8*
57 ; CHECK: 1 = MemoryDef(liveOnEntry)
58 ; CHECK-NEXT: %a8 = call i8* @llvm.launder.invariant.group.p0i8(i8* %1)
59   %a8 = call i8* @llvm.launder.invariant.group.p0i8(i8* %1)
60   %a32 = bitcast i8* %a8 to i32*
62 ; We can skip the barrier only if the "skip" is not based on !invariant.group.
63 ; CHECK: MemoryUse(liveOnEntry)
64 ; CHECK-NEXT: %v2 = load i32
65   %v2 = load i32, i32* %a32, align 4, !invariant.group !0
66 ; CHECK: 2 = MemoryDef(1)
67 ; CHECK-NEXT: store i32 1
68   store i32 1, i32* @g, align 4
70 ; FIXME: based on invariant.group it should be MemoryUse(liveOnEntry)
71 ; CHECK: MemoryUse(2)
72 ; CHECK-NEXT: %v3 = load i32
73   %v3 = load i32, i32* %a32, align 4, !invariant.group !0
74   %add = add nsw i32 %v2, %v3
75   %add2 = add nsw i32 %add, %v
76   ret i32 %add2
79 define i32 @handleInvariantGroups(i32* %a) {
80 ; CHECK: 1 = MemoryDef(liveOnEntry)
81 ; CHECK-NEXT: store i32 0
82   store i32 0, i32* %a, align 4, !invariant.group !0
84 ; CHECK: 2 = MemoryDef(1)
85 ; CHECK-NEXT: store i32 1
86   store i32 1, i32* @g, align 4
87   %1 = bitcast i32* %a to i8*
88 ; CHECK: 3 = MemoryDef(2)
89 ; CHECK-NEXT: %a8 = call i8* @llvm.launder.invariant.group.p0i8(i8* %1)
90   %a8 = call i8* @llvm.launder.invariant.group.p0i8(i8* %1)
91   %a32 = bitcast i8* %a8 to i32*
93 ; CHECK: MemoryUse(2)
94 ; CHECK-NEXT: %2 = load i32
95   %2 = load i32, i32* %a32, align 4, !invariant.group !0
97 ; CHECK: 4 = MemoryDef(3)
98 ; CHECK-NEXT: store i32 2
99   store i32 2, i32* @g, align 4
101 ; FIXME: This can be changed to MemoryUse(2)
102 ; CHECK: MemoryUse(4)
103 ; CHECK-NEXT: %3 = load i32
104   %3 = load i32, i32* %a32, align 4, !invariant.group !0
105   %add = add nsw i32 %2, %3
106   ret i32 %add
109 define i32 @loop(i1 %a) {
110 entry:
111   %0 = alloca i32, align 4
112 ; CHECK: 1 = MemoryDef(liveOnEntry)
113 ; CHECK-NEXT: store i32 4
114   store i32 4, i32* %0, !invariant.group !0
115 ; CHECK: 2 = MemoryDef(1)
116 ; CHECK-NEXT: call void @clobber
117   call void @clobber(i32* %0)
118   br i1 %a, label %Loop.Body, label %Loop.End
120 Loop.Body:
121 ; FIXME: MemoryUse(1)
122 ; CHECK: MemoryUse(2)
123 ; CHECK-NEXT: %1 = load i32
124   %1 = load i32, i32* %0, !invariant.group !0
125   br i1 %a, label %Loop.End, label %Loop.Body
127 Loop.End:
128 ; FIXME: MemoryUse(1)
129 ; CHECK: MemoryUse(2)
130 ; CHECK-NEXT: %2 = load
131   %2 = load i32, i32* %0, align 4, !invariant.group !0
132   br i1 %a, label %Ret, label %Loop.Body
134 Ret:
135   ret i32 %2
138 define i8 @loop2(i8* %p) {
139 entry:
140 ; CHECK: 1 = MemoryDef(liveOnEntry)
141 ; CHECK-NEXT: store i8
142   store i8 4, i8* %p, !invariant.group !0
143 ; CHECK: 2 = MemoryDef(1)
144 ; CHECK-NEXT: call void @clobber
145   call void @clobber8(i8* %p)
147 ; CHECK: 3 = MemoryDef(2)
148 ; CHECK-NEXT: %after = call i8* @llvm.launder.invariant.group.p0i8(i8* %p)
149   %after = call i8* @llvm.launder.invariant.group.p0i8(i8* %p)
150   br i1 undef, label %Loop.Body, label %Loop.End
152 Loop.Body:
153 ; 5 = MemoryPhi({entry,3},{Loop.Body,4},{Loop.End,6})
154 ; CHECK: MemoryUse(6)
155 ; CHECK-NEXT: %0 = load i8
156   %0 = load i8, i8* %after, !invariant.group !0
158 ; FIXME: MemoryUse(1)
159 ; CHECK: MemoryUse(6)
160 ; CHECK-NEXT: %1 = load i8
161   %1 = load i8, i8* %p, !invariant.group !0
163 ; CHECK: 4 = MemoryDef(6)
164   store i8 4, i8* %after, !invariant.group !0
166   br i1 undef, label %Loop.End, label %Loop.Body
168 Loop.End:
169 ; 6 = MemoryPhi({entry,3},{Loop.Body,4})
170 ; CHECK: MemoryUse(5)
171 ; CHECK-NEXT: %2 = load
172   %2 = load i8, i8* %after, align 4, !invariant.group !0
174 ; FIXME: MemoryUse(1)
175 ; CHECK: MemoryUse(5)
176 ; CHECK-NEXT: %3 = load
177   %3 = load i8, i8* %p, align 4, !invariant.group !0
178   br i1 undef, label %Ret, label %Loop.Body
180 Ret:
181   ret i8 %3
185 define i8 @loop3(i8* %p) {
186 entry:
187 ; CHECK: 1 = MemoryDef(liveOnEntry)
188 ; CHECK-NEXT: store i8
189   store i8 4, i8* %p, !invariant.group !0
190 ; CHECK: 2 = MemoryDef(1)
191 ; CHECK-NEXT: call void @clobber
192   call void @clobber8(i8* %p)
194 ; CHECK: 3 = MemoryDef(2)
195 ; CHECK-NEXT: %after = call i8* @llvm.launder.invariant.group.p0i8(i8* %p)
196   %after = call i8* @llvm.launder.invariant.group.p0i8(i8* %p)
197   br i1 undef, label %Loop.Body, label %Loop.End
199 Loop.Body:
200 ; CHECK: 8 = MemoryPhi({entry,3},{Loop.Body,4},{Loop.next,5},{Loop.End,6})
201 ; CHECK: MemoryUse(8)
202 ; CHECK-NEXT: %0 = load i8
203   %0 = load i8, i8* %after, !invariant.group !0
205 ; CHECK: 4 = MemoryDef(8)
206 ; CHECK-NEXT: call void @clobber8
207   call void @clobber8(i8* %after)
209 ; FIXME: MemoryUse(8)
210 ; CHECK: MemoryUse(4)
211 ; CHECK-NEXT: %1 = load i8
212   %1 = load i8, i8* %after, !invariant.group !0
214   br i1 undef, label %Loop.next, label %Loop.Body
215 Loop.next:
216 ; CHECK: 5 = MemoryDef(4)
217 ; CHECK-NEXT: call void @clobber8
218   call void @clobber8(i8* %after)
220 ; FIXME: MemoryUse(8)
221 ; CHECK: MemoryUse(5)
222 ; CHECK-NEXT: %2 = load i8
223   %2 = load i8, i8* %after, !invariant.group !0
225   br i1 undef, label %Loop.End, label %Loop.Body
227 Loop.End:
228 ; CHECK: 7 = MemoryPhi({entry,3},{Loop.next,5})
229 ; CHECK: MemoryUse(7)
230 ; CHECK-NEXT: %3 = load
231   %3 = load i8, i8* %after, align 4, !invariant.group !0
233 ; CHECK: 6 = MemoryDef(7)
234 ; CHECK-NEXT: call void @clobber8
235   call void @clobber8(i8* %after)
237 ; FIXME: MemoryUse(7)
238 ; CHECK: MemoryUse(6)
239 ; CHECK-NEXT: %4 = load
240   %4 = load i8, i8* %after, align 4, !invariant.group !0
241   br i1 undef, label %Ret, label %Loop.Body
243 Ret:
244   ret i8 %3
247 define i8 @loop4(i8* %p) {
248 entry:
249 ; CHECK: 1 = MemoryDef(liveOnEntry)
250 ; CHECK-NEXT: store i8
251   store i8 4, i8* %p, !invariant.group !0
252 ; CHECK: 2 = MemoryDef(1)
253 ; CHECK-NEXT: call void @clobber
254   call void @clobber8(i8* %p)
255 ; CHECK: 3 = MemoryDef(2)
256 ; CHECK-NEXT: %after = call i8* @llvm.launder.invariant.group.p0i8(i8* %p)
257   %after = call i8* @llvm.launder.invariant.group.p0i8(i8* %p)
258   br i1 undef, label %Loop.Pre, label %Loop.End
260 Loop.Pre:
261 ; CHECK: MemoryUse(2)
262 ; CHECK-NEXT: %0 = load i8
263   %0 = load i8, i8* %after, !invariant.group !0
264   br label %Loop.Body
265 Loop.Body:
266 ; CHECK: 6 = MemoryPhi({Loop.Pre,3},{Loop.Body,4},{Loop.End,5})
267 ; CHECK-NEXT: MemoryUse(6)
268 ; CHECK-NEXT: %1 = load i8
269   %1 = load i8, i8* %after, !invariant.group !0
271 ; FIXME: MemoryUse(2)
272 ; CHECK: MemoryUse(6)
273 ; CHECK-NEXT: %2 = load i8
274   %2 = load i8, i8* %p, !invariant.group !0
276 ; CHECK: 4 = MemoryDef(6)
277   store i8 4, i8* %after, !invariant.group !0
278   br i1 undef, label %Loop.End, label %Loop.Body
280 Loop.End:
281 ; CHECK: 5 = MemoryPhi({entry,3},{Loop.Body,4})
282 ; CHECK-NEXT: MemoryUse(5)
283 ; CHECK-NEXT: %3 = load
284   %3 = load i8, i8* %after, align 4, !invariant.group !0
286 ; FIXME: MemoryUse(2)
287 ; CHECK: MemoryUse(5)
288 ; CHECK-NEXT: %4 = load
289   %4 = load i8, i8* %p, align 4, !invariant.group !0
290   br i1 undef, label %Ret, label %Loop.Body
292 Ret:
293   ret i8 %3
296 ; In the future we would like to CSE barriers if there is no clobber between.
297 ; CHECK-LABEL: define i8 @optimizable()
298 define i8 @optimizable() {
299 entry:
300   %ptr = alloca i8
301 ; CHECK: 1 = MemoryDef(liveOnEntry)
302 ; CHECK-NEXT: store i8 42, i8* %ptr, !invariant.group !0
303   store i8 42, i8* %ptr, !invariant.group !0
304 ; CHECK: 2 = MemoryDef(1)
305 ; CHECK-NEXT: call i8* @llvm.launder.invariant.group
306   %ptr2 = call i8* @llvm.launder.invariant.group.p0i8(i8* %ptr)
307 ; FIXME: This one could be CSEd.
308 ; CHECK: 3 = MemoryDef(2)
309 ; CHECK: call i8* @llvm.launder.invariant.group
310   %ptr3 = call i8* @llvm.launder.invariant.group.p0i8(i8* %ptr)
311 ; CHECK: 4 = MemoryDef(3)
312 ; CHECK-NEXT: call void @clobber8(i8* %ptr)
313   call void @clobber8(i8* %ptr)
314 ; CHECK: 5 = MemoryDef(4)
315 ; CHECK-NEXT: call void @use(i8* %ptr2)
316   call void @use(i8* %ptr2)
317 ; CHECK: 6 = MemoryDef(5)
318 ; CHECK-NEXT: call void @use(i8* %ptr3)
319   call void @use(i8* %ptr3)
320 ; CHECK: MemoryUse(6)
321 ; CHECK-NEXT: load i8, i8* %ptr3, {{.*}}!invariant.group
322   %v = load i8, i8* %ptr3, !invariant.group !0
324   ret i8 %v
327 ; CHECK-LABEL: define i8 @unoptimizable2()
328 define i8 @unoptimizable2() {
329   %ptr = alloca i8
330 ; CHECK: 1 = MemoryDef(liveOnEntry)
331 ; CHECK-NEXT: store i8 42, i8* %ptr, !invariant.group !0
332   store i8 42, i8* %ptr, !invariant.group !0
333 ; CHECK: 2 = MemoryDef(1)
334 ; CHECK-NEXT: call i8* @llvm.launder.invariant.group
335   %ptr2 = call i8* @llvm.launder.invariant.group.p0i8(i8* %ptr)
336 ; CHECK: 3 = MemoryDef(2)
337   store i8 43, i8* %ptr
338 ; CHECK: 4 = MemoryDef(3)
339 ; CHECK-NEXT: call i8* @llvm.launder.invariant.group
340   %ptr3 = call i8* @llvm.launder.invariant.group.p0i8(i8* %ptr)
341 ; CHECK: 5 = MemoryDef(4)
342 ; CHECK-NEXT: call void @clobber8(i8* %ptr)
343   call void @clobber8(i8* %ptr)
344 ; 6 = MemoryDef(5)
345 ; CHECK-NEXT  call void @use(i8* %ptr2)
346   call void @use(i8* %ptr2)
347 ; CHECK: 7 = MemoryDef(6)
348 ; CHECK-NEXT: call void @use(i8* %ptr3)
349   call void @use(i8* %ptr3)
350 ; CHECK: MemoryUse(7)
351 ; CHECK-NEXT: %v = load i8, i8* %ptr3, !invariant.group !0
352   %v = load i8, i8* %ptr3, !invariant.group !0
353   ret i8 %v
357 declare i8* @llvm.launder.invariant.group.p0i8(i8*)
358 declare void @clobber(i32*)
359 declare void @clobber8(i8*)
360 declare void @use(i8* readonly)
362 !0 = !{!"group1"}