[TTI] getTypeBasedIntrinsicInstrCost - add basic handling for strided load/store...
[llvm-project.git] / llvm / test / Transforms / GVN / invariant.group.ll
blob9c673ba1ced42d217eeff7654d3feedbfa809e48
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() {
10 define i8 @simple() {
11 entry:
12     %ptr = alloca i8
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
19 ; CHECK: ret i8 42
20     ret i8 %a
23 ; CHECK-LABEL: define i8 @optimizable1() {
24 define i8 @optimizable1() {
25 entry:
26     %ptr = alloca i8
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
30     
31     call void @foo(ptr %ptr2); call to use %ptr2
32 ; CHECK: ret i8 42
33     ret i8 %a
36 ; CHECK-LABEL: define i8 @optimizable2() {
37 define i8 @optimizable2() {
38 entry:
39     %ptr = alloca i8
40     store i8 42, ptr %ptr, !invariant.group !0
41     call void @foo(ptr %ptr)
42     
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
46     
47     call void @foo(ptr %ptr)
48     %b = load i8, ptr %ptr, !invariant.group !0
49     
50 ; CHECK: ret i8 42
51     ret i8 %b
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
63 ; CHECK: ret i1 true
64   ret i1 %r
66 ; CHECK-LABEL: define i8 @unoptimizable1() {
67 define i8 @unoptimizable1() {
68 entry:
69     %ptr = alloca i8
70     store i8 42, ptr %ptr
71     call void @foo(ptr %ptr)
72     %a = load i8, ptr %ptr, !invariant.group !0
73 ; CHECK: ret i8 %a
74     ret i8 %a
77 ; CHECK-LABEL: define void @indirectLoads() {
78 define void @indirectLoads() {
79 entry:
80   %a = alloca ptr, align 8
81   
82   %call = call ptr @getPointer(ptr null) 
83   call void @_ZN1AC1Ev(ptr %call)
84   
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)
89   
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
96   call void %1(ptr %0)
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
102   
103   call void %3(ptr %2)
104   %4 = load ptr, ptr %a, align 8
105   
106   %vtable4 = load ptr, ptr %4, align 8, !invariant.group !0
107   %5 = load ptr, ptr %vtable4, align 8
108 ; CHECK: call void @_ZN1A3fooEv(
109   call void %5(ptr %4)
111   %vtable5 = load ptr, ptr %call, align 8, !invariant.group !0
112   %6 = load ptr, ptr %vtable5, align 8
113 ; CHECK: call void @_ZN1A3fooEv(
114   call void %6(ptr %4)
115   
116   ret void
119 ; CHECK-LABEL: define void @combiningBitCastWithLoad() {
120 define void @combiningBitCastWithLoad() {
121 entry:
122   %a = alloca ptr, align 8
123   
124   %call = call ptr @getPointer(ptr null) 
125   call void @_ZN1AC1Ev(ptr %call)
126   
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)
130   
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
137   call void %1(ptr %0)
139   ret void
142 ; CHECK-LABEL:define void @loadCombine() {
143 define void @loadCombine() {
144 enter:
145   %ptr = alloca i8
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
150 ; CHECK-NOT: load
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)
156   ret void
159 ; CHECK-LABEL: define void @loadCombine1() {
160 define void @loadCombine1() {
161 enter:
162   %ptr = alloca i8
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
167 ; CHECK-NOT: load
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)
173   ret void
176 ; CHECK-LABEL: define void @loadCombine2() {    
177 define void @loadCombine2() {
178 enter:
179   %ptr = alloca i8
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
184 ; CHECK-NOT: load
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)
190   ret void
193 ; CHECK-LABEL: define void @loadCombine3() {
194 define void @loadCombine3() {
195 enter:
196   %ptr = alloca i8
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
201 ; CHECK-NOT: load
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)
207   ret void
210 ; CHECK-LABEL: define i8 @unoptimizable2() {
211 define i8 @unoptimizable2() {
212 entry:
213     %ptr = alloca i8
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
219     
220 ; CHECK: ret i8 %a
221     ret i8 %a
224 ; CHECK-LABEL: define i8 @unoptimizable3() {
225 define i8 @unoptimizable3() {
226 entry:
227     %ptr = alloca i8
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
231     
232 ; CHECK: ret i8 %a
233     ret i8 %a
236 ; CHECK-LABEL: define i8 @optimizable4() {
237 define i8 @optimizable4() {
238 entry:
239     %ptr = alloca i8
240     store i8 42, ptr %ptr, !invariant.group !0
241     %ptr2 = call ptr @llvm.launder.invariant.group.p0(ptr %ptr)
242 ; CHECK-NOT: load
243     %a = load i8, ptr %ptr2, !invariant.group !0
244     
245 ; CHECK: ret i8 42
246     ret i8 %a
249 ; CHECK-LABEL: define i8 @volatile1() {
250 define i8 @volatile1() {
251 entry:
252     %ptr = alloca i8
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)
264 ; CHECK: ret i8 42
265     ret i8 %a
268 ; CHECK-LABEL: define i8 @volatile2() {
269 define i8 @volatile2() {
270 entry:
271     %ptr = alloca i8
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)
283 ; CHECK: ret i8 42
284     ret i8 %a
287 ; CHECK-LABEL: define i8 @fun() {
288 define i8 @fun() {
289 entry:
290     %ptr = alloca i8
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)
302     
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)
309 ; CHECK-NOT: load
310     %d = load i8, ptr %newPtr2, !invariant.group !0
311 ; CHECK: ret i8 %unknownValue
312     ret i8 %d
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
334   ret void
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)
357    ret void
359 ; And in the case it is not global
360 ; CHECK-LABEL: define void @testNotGlobal() {
361 define void @testNotGlobal() {
362    %a = alloca i8
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)
380    ret void
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
415   ret void
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)
434 !0 = !{}