1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -S -licm < %s | FileCheck %s
4 ; Note: the !invariant.load is there just solely to let us call @use()
5 ; to add a fake use, and still have the aliasing work out. The call
6 ; to @use(0) is just to provide a may-unwind exit out of the loop, so
7 ; that LICM cannot hoist out the load simply because it is guaranteed
10 declare void @use(i32)
12 define void @f_0(i8* align 4 dereferenceable(1024) %ptr) nofree nosync {
15 ; CHECK-NEXT: [[PTR_GEP:%.*]] = getelementptr i8, i8* [[PTR:%.*]], i32 32
16 ; CHECK-NEXT: [[PTR_I32:%.*]] = bitcast i8* [[PTR_GEP]] to i32*
17 ; CHECK-NEXT: [[VAL:%.*]] = load i32, i32* [[PTR_I32]], align 4
18 ; CHECK-NEXT: br label [[LOOP:%.*]]
20 ; CHECK-NEXT: call void @use(i32 0)
21 ; CHECK-NEXT: call void @use(i32 [[VAL]])
22 ; CHECK-NEXT: br label [[LOOP]]
27 %ptr.gep = getelementptr i8, i8* %ptr, i32 32
28 %ptr.i32 = bitcast i8* %ptr.gep to i32*
33 %val = load i32, i32* %ptr.i32, !invariant.load !{}
34 call void @use(i32 %val)
38 define void @f_1(i8* align 4 dereferenceable_or_null(1024) %ptr) nofree nosync {
41 ; CHECK-NEXT: [[PTR_GEP:%.*]] = getelementptr i8, i8* [[PTR:%.*]], i32 32
42 ; CHECK-NEXT: [[PTR_I32:%.*]] = bitcast i8* [[PTR_GEP]] to i32*
43 ; CHECK-NEXT: [[PTR_IS_NULL:%.*]] = icmp eq i8* [[PTR]], null
44 ; CHECK-NEXT: br i1 [[PTR_IS_NULL]], label [[LEAVE:%.*]], label [[LOOP_PREHEADER:%.*]]
45 ; CHECK: loop.preheader:
46 ; CHECK-NEXT: [[VAL:%.*]] = load i32, i32* [[PTR_I32]], align 4
47 ; CHECK-NEXT: br label [[LOOP:%.*]]
49 ; CHECK-NEXT: call void @use(i32 0)
50 ; CHECK-NEXT: call void @use(i32 [[VAL]])
51 ; CHECK-NEXT: br label [[LOOP]]
53 ; CHECK-NEXT: ret void
56 %ptr.gep = getelementptr i8, i8* %ptr, i32 32
57 %ptr.i32 = bitcast i8* %ptr.gep to i32*
58 %ptr_is_null = icmp eq i8* %ptr, null
59 br i1 %ptr_is_null, label %leave, label %loop
64 %val = load i32, i32* %ptr.i32, !invariant.load !{}
65 call void @use(i32 %val)
72 define void @f_2(i8* align 4 dereferenceable_or_null(1024) %ptr) {
75 ; CHECK-NEXT: [[PTR_GEP:%.*]] = getelementptr i8, i8* [[PTR:%.*]], i32 30
76 ; CHECK-NEXT: [[PTR_I32:%.*]] = bitcast i8* [[PTR_GEP]] to i32*
77 ; CHECK-NEXT: [[PTR_IS_NULL:%.*]] = icmp eq i8* [[PTR]], null
78 ; CHECK-NEXT: br i1 [[PTR_IS_NULL]], label [[LEAVE:%.*]], label [[LOOP_PREHEADER:%.*]]
79 ; CHECK: loop.preheader:
80 ; CHECK-NEXT: br label [[LOOP:%.*]]
82 ; CHECK-NEXT: call void @use(i32 0)
83 ; CHECK-NEXT: [[VAL:%.*]] = load i32, i32* [[PTR_I32]], align 4, !invariant.load !0
84 ; CHECK-NEXT: call void @use(i32 [[VAL]])
85 ; CHECK-NEXT: br label [[LOOP]]
87 ; CHECK-NEXT: ret void
91 ;; Can't hoist, since the alignment does not work out -- (<4 byte
92 ;; aligned> + 30) is not necessarily 4 byte aligned.
94 %ptr.gep = getelementptr i8, i8* %ptr, i32 30
95 %ptr.i32 = bitcast i8* %ptr.gep to i32*
96 %ptr_is_null = icmp eq i8* %ptr, null
97 br i1 %ptr_is_null, label %leave, label %loop
100 call void @use(i32 0)
101 %val = load i32, i32* %ptr.i32, !invariant.load !{}
102 call void @use(i32 %val)
109 define void @checkLaunder(i8* align 4 dereferenceable(1024) %p) nofree nosync {
110 ; CHECK-LABEL: @checkLaunder(
112 ; CHECK-NEXT: [[L:%.*]] = call i8* @llvm.launder.invariant.group.p0i8(i8* [[P:%.*]])
113 ; CHECK-NEXT: [[VAL:%.*]] = load i8, i8* [[L]], align 1
114 ; CHECK-NEXT: br label [[LOOP:%.*]]
116 ; CHECK-NEXT: call void @use(i32 0)
117 ; CHECK-NEXT: call void @use8(i8 [[VAL]])
118 ; CHECK-NEXT: br label [[LOOP]]
122 %l = call i8* @llvm.launder.invariant.group.p0i8(i8* %p)
126 call void @use(i32 0)
127 %val = load i8, i8* %l, !invariant.load !{}
128 call void @use8(i8 %val)
132 declare i8* @llvm.launder.invariant.group.p0i8(i8*)
134 declare void @use8(i8)