1 ; RUN: opt < %s -passes=gvn -S | FileCheck %s
3 %struct.A = type { ptr }
4 @_ZTV1A = available_externally unnamed_addr constant [3 x ptr] [ptr null, ptr @_ZTI1A, ptr @_ZN1A3fooEv], align 8
5 @_ZTI1A = external constant ptr
7 @unknownPtr = external global i8
9 ; CHECK-LABEL: define i8 @simple() {
13 store i8 42, ptr %ptr, !invariant.group !0
14 call void @foo(ptr %ptr)
16 %a = load i8, ptr %ptr, !invariant.group !0
17 %b = load i8, ptr %ptr, !invariant.group !0
18 %c = load i8, ptr %ptr, !invariant.group !0
23 ; CHECK-LABEL: define i8 @optimizable1() {
24 define i8 @optimizable1() {
27 store i8 42, ptr %ptr, !invariant.group !0
28 %ptr2 = call ptr @llvm.launder.invariant.group.p0(ptr %ptr)
29 %a = load i8, ptr %ptr, !invariant.group !0
31 call void @foo(ptr %ptr2); call to use %ptr2
36 ; CHECK-LABEL: define i8 @optimizable2() {
37 define i8 @optimizable2() {
40 store i8 42, ptr %ptr, !invariant.group !0
41 call void @foo(ptr %ptr)
43 store i8 13, ptr %ptr ; can't use this store with invariant.group
44 %a = load i8, ptr %ptr
45 call void @bar(i8 %a) ; call to use %a
47 call void @foo(ptr %ptr)
48 %b = load i8, ptr %ptr, !invariant.group !0
54 ; CHECK-LABEL: define i1 @proveEqualityForStrip(
55 define i1 @proveEqualityForStrip(ptr %a) {
56 ; FIXME: The first call could be also removed by GVN. Right now
57 ; DCE removes it. The second call is CSE'd with the first one.
58 ; CHECK: %b1 = call ptr @llvm.strip.invariant.group.p0(ptr %a)
59 %b1 = call ptr @llvm.strip.invariant.group.p0(ptr %a)
60 ; CHECK-NOT: llvm.strip.invariant.group
61 %b2 = call ptr @llvm.strip.invariant.group.p0(ptr %a)
62 %r = icmp eq ptr %b1, %b2
66 ; CHECK-LABEL: define i8 @unoptimizable1() {
67 define i8 @unoptimizable1() {
71 call void @foo(ptr %ptr)
72 %a = load i8, ptr %ptr, !invariant.group !0
77 ; CHECK-LABEL: define void @indirectLoads() {
78 define void @indirectLoads() {
80 %a = alloca ptr, align 8
82 %call = call ptr @getPointer(ptr null)
83 call void @_ZN1AC1Ev(ptr %call)
85 ; CHECK: %vtable = load {{.*}} !invariant.group
86 %vtable = load ptr, ptr %call, align 8, !invariant.group !0
87 %cmp.vtables = icmp eq ptr %vtable, getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2)
88 call void @llvm.assume(i1 %cmp.vtables)
90 store ptr %call, ptr %a, align 8
91 %0 = load ptr, ptr %a, align 8
93 ; CHECK: call void @_ZN1A3fooEv(
94 %vtable1 = load ptr, ptr %0, align 8, !invariant.group !0
95 %1 = load ptr, ptr %vtable1, align 8
97 %2 = load ptr, ptr %a, align 8
99 ; CHECK: call void @_ZN1A3fooEv(
100 %vtable2 = load ptr, ptr %2, align 8, !invariant.group !0
101 %3 = load ptr, ptr %vtable2, align 8
104 %4 = load ptr, ptr %a, align 8
106 %vtable4 = load ptr, ptr %4, align 8, !invariant.group !0
107 %5 = load ptr, ptr %vtable4, align 8
108 ; CHECK: call void @_ZN1A3fooEv(
111 %vtable5 = load ptr, ptr %call, align 8, !invariant.group !0
112 %6 = load ptr, ptr %vtable5, align 8
113 ; CHECK: call void @_ZN1A3fooEv(
119 ; CHECK-LABEL: define void @combiningBitCastWithLoad() {
120 define void @combiningBitCastWithLoad() {
122 %a = alloca ptr, align 8
124 %call = call ptr @getPointer(ptr null)
125 call void @_ZN1AC1Ev(ptr %call)
127 ; CHECK: %vtable = load {{.*}} !invariant.group
128 %vtable = load ptr, ptr %call, align 8, !invariant.group !0
129 %cmp.vtables = icmp eq ptr %vtable, getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2)
131 store ptr %call, ptr %a, align 8
132 ; CHECK-NOT: !invariant.group
133 %0 = load ptr, ptr %a, align 8
135 %vtable1 = load ptr, ptr %0, align 8, !invariant.group !0
136 %1 = load ptr, ptr %vtable1, align 8
142 ; CHECK-LABEL:define void @loadCombine() {
143 define void @loadCombine() {
146 store i8 42, ptr %ptr
147 call void @foo(ptr %ptr)
148 ; CHECK: %[[A:.*]] = load i8, ptr %ptr, align 1, !invariant.group
149 %a = load i8, ptr %ptr, !invariant.group !0
151 %b = load i8, ptr %ptr, !invariant.group !0
152 ; CHECK: call void @bar(i8 %[[A]])
153 call void @bar(i8 %a)
154 ; CHECK: call void @bar(i8 %[[A]])
155 call void @bar(i8 %b)
159 ; CHECK-LABEL: define void @loadCombine1() {
160 define void @loadCombine1() {
163 store i8 42, ptr %ptr
164 call void @foo(ptr %ptr)
165 ; CHECK: %[[D:.*]] = load i8, ptr %ptr, align 1, !invariant.group
166 %c = load i8, ptr %ptr
168 %d = load i8, ptr %ptr, !invariant.group !0
169 ; CHECK: call void @bar(i8 %[[D]])
170 call void @bar(i8 %c)
171 ; CHECK: call void @bar(i8 %[[D]])
172 call void @bar(i8 %d)
176 ; CHECK-LABEL: define void @loadCombine2() {
177 define void @loadCombine2() {
180 store i8 42, ptr %ptr
181 call void @foo(ptr %ptr)
182 ; CHECK: %[[E:.*]] = load i8, ptr %ptr, align 1, !invariant.group
183 %e = load i8, ptr %ptr, !invariant.group !0
185 %f = load i8, ptr %ptr
186 ; CHECK: call void @bar(i8 %[[E]])
187 call void @bar(i8 %e)
188 ; CHECK: call void @bar(i8 %[[E]])
189 call void @bar(i8 %f)
193 ; CHECK-LABEL: define void @loadCombine3() {
194 define void @loadCombine3() {
197 store i8 42, ptr %ptr
198 call void @foo(ptr %ptr)
199 ; CHECK: %[[E:.*]] = load i8, ptr %ptr, align 1, !invariant.group
200 %e = load i8, ptr %ptr, !invariant.group !0
202 %f = load i8, ptr %ptr, !invariant.group !0
203 ; CHECK: call void @bar(i8 %[[E]])
204 call void @bar(i8 %e)
205 ; CHECK: call void @bar(i8 %[[E]])
206 call void @bar(i8 %f)
210 ; CHECK-LABEL: define i8 @unoptimizable2() {
211 define i8 @unoptimizable2() {
214 store i8 42, ptr %ptr
215 call void @foo(ptr %ptr)
216 %a = load i8, ptr %ptr
217 call void @foo(ptr %ptr)
218 %b = load i8, ptr %ptr, !invariant.group !0
224 ; CHECK-LABEL: define i8 @unoptimizable3() {
225 define i8 @unoptimizable3() {
228 store i8 42, ptr %ptr, !invariant.group !0
229 %ptr2 = call ptr @getPointer(ptr %ptr)
230 %a = load i8, ptr %ptr2, !invariant.group !0
236 ; CHECK-LABEL: define i8 @optimizable4() {
237 define i8 @optimizable4() {
240 store i8 42, ptr %ptr, !invariant.group !0
241 %ptr2 = call ptr @llvm.launder.invariant.group.p0(ptr %ptr)
243 %a = load i8, ptr %ptr2, !invariant.group !0
249 ; CHECK-LABEL: define i8 @volatile1() {
250 define i8 @volatile1() {
253 store i8 42, ptr %ptr, !invariant.group !0
254 call void @foo(ptr %ptr)
255 %a = load i8, ptr %ptr, !invariant.group !0
256 %b = load volatile i8, ptr %ptr
257 ; CHECK: call void @bar(i8 %b)
258 call void @bar(i8 %b)
260 %c = load volatile i8, ptr %ptr, !invariant.group !0
261 ; FIXME: we could change %c to 42, preserving volatile load
262 ; CHECK: call void @bar(i8 %c)
263 call void @bar(i8 %c)
268 ; CHECK-LABEL: define i8 @volatile2() {
269 define i8 @volatile2() {
272 store i8 42, ptr %ptr, !invariant.group !0
273 call void @foo(ptr %ptr)
274 %a = load i8, ptr %ptr, !invariant.group !0
275 %b = load volatile i8, ptr %ptr
276 ; CHECK: call void @bar(i8 %b)
277 call void @bar(i8 %b)
279 %c = load volatile i8, ptr %ptr, !invariant.group !0
280 ; FIXME: we could change %c to 42, preserving volatile load
281 ; CHECK: call void @bar(i8 %c)
282 call void @bar(i8 %c)
287 ; CHECK-LABEL: define i8 @fun() {
291 store i8 42, ptr %ptr, !invariant.group !0
292 call void @foo(ptr %ptr)
294 %a = load i8, ptr %ptr, !invariant.group !0 ; Can assume that value under %ptr didn't change
295 ; CHECK: call void @bar(i8 42)
296 call void @bar(i8 %a)
298 %newPtr = call ptr @getPointer(ptr %ptr)
299 %c = load i8, ptr %newPtr, !invariant.group !0 ; Can't assume anything, because we only have information about %ptr
300 ; CHECK: call void @bar(i8 %c)
301 call void @bar(i8 %c)
303 %unknownValue = load i8, ptr @unknownPtr
304 ; FIXME: Can assume that %unknownValue == 42
305 ; CHECK: store i8 %unknownValue, ptr %ptr, align 1, !invariant.group !0
306 store i8 %unknownValue, ptr %ptr, !invariant.group !0
308 %newPtr2 = call ptr @llvm.launder.invariant.group.p0(ptr %ptr)
310 %d = load i8, ptr %newPtr2, !invariant.group !0
311 ; CHECK: ret i8 %unknownValue
315 ; This test checks if invariant.group understands gep with zeros
316 ; CHECK-LABEL: define void @testGEP0() {
317 define void @testGEP0() {
318 %a = alloca %struct.A, align 8
319 store ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2), ptr %a, align 8, !invariant.group !0
320 ; CHECK: call void @_ZN1A3fooEv(ptr nonnull dereferenceable(8) %a)
321 call void @_ZN1A3fooEv(ptr nonnull dereferenceable(8) %a) ; This call may change vptr
322 %1 = load i8, ptr @unknownPtr, align 4
323 %2 = icmp eq i8 %1, 0
324 br i1 %2, label %_Z1gR1A.exit, label %3
326 ; This should be devirtualized by invariant.group
327 %4 = load ptr, ptr %a, align 8, !invariant.group !0
328 %5 = load ptr, ptr %4, align 8
329 ; CHECK: call void @_ZN1A3fooEv(ptr nonnull %a)
330 call void %5(ptr nonnull %a)
331 br label %_Z1gR1A.exit
333 _Z1gR1A.exit: ; preds = %0, %3
337 ; Check if no optimizations are performed with global pointers.
338 ; FIXME: we could do the optimizations if we would check if dependency comes
339 ; from the same function.
340 ; CHECK-LABEL: define void @testGlobal() {
341 define void @testGlobal() {
342 ; CHECK: %a = load i8, ptr @unknownPtr, align 1, !invariant.group !0
343 %a = load i8, ptr @unknownPtr, !invariant.group !0
344 call void @foo2(ptr @unknownPtr, i8 %a)
345 ; CHECK: %1 = load i8, ptr @unknownPtr, align 1, !invariant.group !0
346 %1 = load i8, ptr @unknownPtr, !invariant.group !0
347 call void @bar(i8 %1)
349 call void @fooBit(ptr @unknownPtr, i1 1)
350 ; Adding regex because of canonicalization of bitcasts
351 ; CHECK: %2 = load i1, ptr {{.*}}, !invariant.group !0
352 %2 = load i1, ptr @unknownPtr, !invariant.group !0
353 call void @fooBit(ptr @unknownPtr, i1 %2)
354 ; CHECK: %3 = load i1, ptr {{.*}}, !invariant.group !0
355 %3 = load i1, ptr @unknownPtr, !invariant.group !0
356 call void @fooBit(ptr @unknownPtr, i1 %3)
359 ; And in the case it is not global
360 ; CHECK-LABEL: define void @testNotGlobal() {
361 define void @testNotGlobal() {
363 call void @foo(ptr %a)
364 ; CHECK: %b = load i8, ptr %a, align 1, !invariant.group !0
365 %b = load i8, ptr %a, !invariant.group !0
366 call void @foo2(ptr %a, i8 %b)
368 %1 = load i8, ptr %a, !invariant.group !0
369 ; CHECK: call void @bar(i8 %b)
370 call void @bar(i8 %1)
372 call void @fooBit(ptr %a, i1 1)
373 ; CHECK: %1 = trunc i8 %b to i1
374 %2 = load i1, ptr %a, !invariant.group !0
375 ; CHECK-NEXT: call void @fooBit(ptr %a, i1 %1)
376 call void @fooBit(ptr %a, i1 %2)
377 %3 = load i1, ptr %a, !invariant.group !0
378 ; CHECK-NEXT: call void @fooBit(ptr %a, i1 %1)
379 call void @fooBit(ptr %a, i1 %3)
383 ; CHECK-LABEL: define void @handling_loops()
384 define void @handling_loops() {
385 %a = alloca %struct.A, align 8
386 store ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2), ptr %a, align 8, !invariant.group !0
387 %1 = load i8, ptr @unknownPtr, align 4
388 %2 = icmp sgt i8 %1, 0
389 br i1 %2, label %.lr.ph.i, label %_Z2g2R1A.exit
391 .lr.ph.i: ; preds = %0
392 %3 = load i8, ptr @unknownPtr, align 4
393 %4 = icmp sgt i8 %3, 1
394 br i1 %4, label %._crit_edge.preheader, label %_Z2g2R1A.exit
396 ._crit_edge.preheader: ; preds = %.lr.ph.i
397 br label %._crit_edge
399 ._crit_edge: ; preds = %._crit_edge.preheader, %._crit_edge
400 %5 = phi i8 [ %7, %._crit_edge ], [ 1, %._crit_edge.preheader ]
401 %.pre = load ptr, ptr %a, align 8, !invariant.group !0
402 %6 = load ptr, ptr %.pre, align 8
403 ; CHECK: call void @_ZN1A3fooEv(ptr nonnull %a)
404 call void %6(ptr nonnull %a) #3
405 ; CHECK-NOT: call void %
406 %7 = add nuw nsw i8 %5, 1
407 %8 = load i8, ptr @unknownPtr, align 4
408 %9 = icmp slt i8 %7, %8
409 br i1 %9, label %._crit_edge, label %_Z2g2R1A.exit.loopexit
411 _Z2g2R1A.exit.loopexit: ; preds = %._crit_edge
412 br label %_Z2g2R1A.exit
414 _Z2g2R1A.exit: ; preds = %_Z2g2R1A.exit.loopexit, %.lr.ph.i, %0
419 declare void @foo(ptr)
420 declare void @foo2(ptr, i8)
421 declare void @bar(i8)
422 declare ptr @getPointer(ptr)
423 declare void @_ZN1A3fooEv(ptr)
424 declare void @_ZN1AC1Ev(ptr)
425 declare void @fooBit(ptr, i1)
427 declare ptr @llvm.launder.invariant.group.p0(ptr)
428 declare ptr @llvm.strip.invariant.group.p0(ptr)
431 declare void @llvm.assume(i1 %cmp.vtables)