[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / llvm / test / Transforms / NewGVN / invariant.group.ll
blob81e733f84ddb11f3ab2930303cf66c623945bd51
1 ; RUN: opt < %s -passes=newgvn -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   %b1 = call ptr @llvm.strip.invariant.group.p0(ptr %a)
57 ; CHECK-NOT: llvm.strip.invariant.group
58   %b2 = call ptr @llvm.strip.invariant.group.p0(ptr %a)
59   %r = icmp eq ptr %b1, %b2
60 ; CHECK: ret i1 true
61   ret i1 %r
64 ; CHECK-LABEL: define i8 @unoptimizable1() {
65 define i8 @unoptimizable1() {
66 entry:
67     %ptr = alloca i8
68     store i8 42, ptr %ptr
69     call void @foo(ptr %ptr)
70     %a = load i8, ptr %ptr, !invariant.group !0
71 ; CHECK: ret i8 %a
72     ret i8 %a
75 ; NewGVN doesn't support assumes.
76 ; CHECK-LABEL: define void @indirectLoads() {
77 define void @indirectLoads() {
78 entry:
79   %a = alloca ptr, align 8
80   
81   %call = call ptr @getPointer(ptr null) 
82   call void @_ZN1AC1Ev(ptr %call)
83   
84 ; CHECK: %vtable = load {{.*}} !invariant.group
85   %vtable = load ptr, ptr %call, align 8, !invariant.group !0
86   %cmp.vtables = icmp eq ptr %vtable, getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2)
87   call void @llvm.assume(i1 %cmp.vtables)
88   
89   store ptr %call, ptr %a, align 8
90   %0 = load ptr, ptr %a, align 8
92 ; FIXME: call void @_ZN1A3fooEv(
93   %vtable1 = load ptr, ptr %0, align 8, !invariant.group !0
94   %1 = load ptr, ptr %vtable1, align 8
95   call void %1(ptr %0)
96   %2 = load ptr, ptr %a, align 8
98 ; FIXME: call void @_ZN1A3fooEv(
99   %vtable2 = load ptr, ptr %2, align 8, !invariant.group !0
100   %3 = load ptr, ptr %vtable2, align 8
101   
102   call void %3(ptr %2)
103   %4 = load ptr, ptr %a, align 8
104   
105   %vtable4 = load ptr, ptr %4, align 8, !invariant.group !0
106   %5 = load ptr, ptr %vtable4, align 8
107 ; FIXME: call void @_ZN1A3fooEv(
108   call void %5(ptr %4)
110   %vtable5 = load ptr, ptr %call, align 8, !invariant.group !0
111   %6 = load ptr, ptr %vtable5, align 8
112 ; FIXME: call void @_ZN1A3fooEv(
113   call void %6(ptr %4)
114   
115   ret void
118 ; NewGVN won't CSE loads with different pointee types.
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 ; FIXME-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 ; NewGVN cares about the launder for some reason.
237 ; CHECK-LABEL: define i8 @optimizable4() {
238 define i8 @optimizable4() {
239 entry:
240     %ptr = alloca i8
241     store i8 42, ptr %ptr
242     %ptr2 = call ptr @llvm.launder.invariant.group.p0(ptr %ptr)
243 ; FIXME-NOT: load
244     %a = load i8, ptr %ptr2
245     
246 ; FIXME: ret i8 42
247     ret i8 %a
250 ; CHECK-LABEL: define i8 @volatile1() {
251 define i8 @volatile1() {
252 entry:
253     %ptr = alloca i8
254     store i8 42, ptr %ptr, !invariant.group !0
255     call void @foo(ptr %ptr)
256     %a = load i8, ptr %ptr, !invariant.group !0
257     %b = load volatile i8, ptr %ptr
258 ; CHECK: call void @bar(i8 %b)
259     call void @bar(i8 %b)
261     %c = load volatile i8, ptr %ptr, !invariant.group !0
262 ; We might be able to optimize this, but nobody cares
263 ; CHECK: call void @bar(i8 %c)
264     call void @bar(i8 %c)
265 ; CHECK: ret i8 42
266     ret i8 %a
269 ; CHECK-LABEL: define i8 @volatile2() {
270 define i8 @volatile2() {
271 entry:
272     %ptr = alloca i8
273     store i8 42, ptr %ptr, !invariant.group !0
274     call void @foo(ptr %ptr)
275     %a = load i8, ptr %ptr, !invariant.group !0
276     %b = load volatile i8, ptr %ptr
277 ; CHECK: call void @bar(i8 %b)
278     call void @bar(i8 %b)
280     %c = load volatile i8, ptr %ptr, !invariant.group !0
281 ; We might be able to optimize this, but nobody cares
282 ; CHECK: call void @bar(i8 %c)
283     call void @bar(i8 %c)
284 ; CHECK: ret i8 42
285     ret i8 %a
288 ; CHECK-LABEL: define void @fun() {
289 define void @fun() {
290 entry:
291     %ptr = alloca i8
292     store i8 42, ptr %ptr, !invariant.group !0
293     call void @foo(ptr %ptr)
295     %a = load i8, ptr %ptr, !invariant.group !0 ; Can assume that value under %ptr didn't change
296 ; CHECK: call void @bar(i8 42)
297     call void @bar(i8 %a)
299     ret void
302 ; FIXME: NewGVN doesn't run instsimplify on a load from a vtable definition?
303 ; This test checks if invariant.group understands gep with zeros
304 ; CHECK-LABEL: define void @testGEP0() {
305 define void @testGEP0() {
306   %a = alloca %struct.A, align 8
307   store ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2), ptr %a, align 8, !invariant.group !0
308 ; CHECK: call void @_ZN1A3fooEv(ptr nonnull dereferenceable(8) %a)
309   call void @_ZN1A3fooEv(ptr nonnull dereferenceable(8) %a) ; This call may change vptr
310   %1 = load i8, ptr @unknownPtr, align 4
311   %2 = icmp eq i8 %1, 0
312   br i1 %2, label %_Z1gR1A.exit, label %3
314 ; This should be devirtualized by invariant.group
315   %4 = load ptr, ptr %a, align 8, !invariant.group !0
316   %5 = load ptr, ptr %4, align 8
317 ; FIXME: call void @_ZN1A3fooEv(ptr nonnull %a)
318   call void %5(ptr nonnull %a)
319   br label %_Z1gR1A.exit
321 _Z1gR1A.exit:                                     ; preds = %0, %3
322   ret void
325 ; Check if no optimizations are performed with global pointers.
326 ; FIXME: we could do the optimizations if we would check if dependency comes
327 ; from the same function.
328 ; CHECK-LABEL: define void @testGlobal() {
329 define void @testGlobal() {
330 ; CHECK:  %a = load i8, ptr @unknownPtr, align 1, !invariant.group !0
331    %a = load i8, ptr @unknownPtr, !invariant.group !0
332    call void @foo2(ptr @unknownPtr, i8 %a)
333 ; CHECK:  %1 = load i8, ptr @unknownPtr, align 1, !invariant.group !0
334    %1 = load i8, ptr @unknownPtr, !invariant.group !0
335    call void @bar(i8 %1)
337    call void @fooBit(ptr @unknownPtr, i1 1)
338 ; Adding regex because of canonicalization of bitcasts
339 ; CHECK: %2 = load i1, ptr {{.*}}, !invariant.group !0
340    %2 = load i1, ptr @unknownPtr, !invariant.group !0
341    call void @fooBit(ptr @unknownPtr, i1 %2)
342 ; CHECK:  %3 = load i1, ptr {{.*}}, !invariant.group !0
343    %3 = load i1, ptr @unknownPtr, !invariant.group !0
344    call void @fooBit(ptr @unknownPtr, i1 %3)
345    ret void
348 ; Might be similar to above where NewGVN doesn't handle loads of different types from the same location.
349 ; Not super important anyway.
350 ; CHECK-LABEL: define void @testTrunc() {
351 define void @testTrunc() {
352    %a = alloca i8
353    call void @foo(ptr %a)
354 ; CHECK:  %b = load i8, ptr %a, align 1, !invariant.group !0
355    %b = load i8, ptr %a, !invariant.group !0
356    call void @foo2(ptr %a, i8 %b)
358    %1 = load i8, ptr %a, !invariant.group !0
359 ; CHECK: call void @bar(i8 %b)
360    call void @bar(i8 %1)
362    call void @fooBit(ptr %a, i1 1)
363 ; FIXME: %1 = trunc i8 %b to i1
364    %2 = load i1, ptr %a, !invariant.group !0
365 ; FIXME-NEXT: call void @fooBit(ptr %a, i1 %1)
366    call void @fooBit(ptr %a, i1 %2)
367    %3 = load i1, ptr %a, !invariant.group !0
368 ; FIXME-NEXT: call void @fooBit(ptr %a, i1 %1)
369    call void @fooBit(ptr %a, i1 %3)
370    ret void
373 ; See comment in @testGEP0 on what NewGVN is lacking.
374 ; CHECK-LABEL: define void @handling_loops()
375 define void @handling_loops() {
376   %a = alloca %struct.A, align 8
377   store ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2), ptr %a, align 8, !invariant.group !0
378   %1 = load i8, ptr @unknownPtr, align 4
379   %2 = icmp sgt i8 %1, 0
380   br i1 %2, label %.lr.ph.i, label %_Z2g2R1A.exit
382 .lr.ph.i:                                         ; preds = %0
383   %3 = load i8, ptr @unknownPtr, align 4
384   %4 = icmp sgt i8 %3, 1
385   br i1 %4, label %._crit_edge.preheader, label %_Z2g2R1A.exit
387 ._crit_edge.preheader:                            ; preds = %.lr.ph.i
388   br label %._crit_edge
390 ._crit_edge:                                      ; preds = %._crit_edge.preheader, %._crit_edge
391   %5 = phi i8 [ %7, %._crit_edge ], [ 1, %._crit_edge.preheader ]
392   %.pre = load ptr, ptr %a, align 8, !invariant.group !0
393   %6 = load ptr, ptr %.pre, align 8
394   ; FIXME: call void @_ZN1A3fooEv(ptr nonnull %a)
395   call void %6(ptr nonnull %a) #3
396   ; FIXME-NOT: call void %
397   %7 = add nuw nsw i8 %5, 1
398   %8 = load i8, ptr @unknownPtr, align 4
399   %9 = icmp slt i8 %7, %8
400   br i1 %9, label %._crit_edge, label %_Z2g2R1A.exit.loopexit
402 _Z2g2R1A.exit.loopexit:                           ; preds = %._crit_edge
403   br label %_Z2g2R1A.exit
405 _Z2g2R1A.exit:                                    ; preds = %_Z2g2R1A.exit.loopexit, %.lr.ph.i, %0
406   ret void
410 declare void @foo(ptr)
411 declare void @foo2(ptr, i8)
412 declare void @bar(i8)
413 declare ptr @getPointer(ptr)
414 declare void @_ZN1A3fooEv(ptr)
415 declare void @_ZN1AC1Ev(ptr)
416 declare void @fooBit(ptr, i1)
418 declare ptr @llvm.launder.invariant.group.p0(ptr)
419 declare ptr @llvm.strip.invariant.group.p0(ptr)
421 ; Function Attrs: nounwind
422 declare void @llvm.assume(i1 %cmp.vtables) #0
425 attributes #0 = { nounwind }
426 !0 = !{}