1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -S -passes=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(ptr align 4 dereferenceable(1024) %ptr) nofree nosync {
15 ; CHECK-NEXT: [[PTR_GEP:%.*]] = getelementptr i8, ptr [[PTR:%.*]], i32 32
16 ; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[PTR_GEP]], align 4
17 ; CHECK-NEXT: br label [[LOOP:%.*]]
19 ; CHECK-NEXT: call void @use(i32 0)
20 ; CHECK-NEXT: call void @use(i32 [[VAL]])
21 ; CHECK-NEXT: br label [[LOOP]]
26 %ptr.gep = getelementptr i8, ptr %ptr, i32 32
31 %val = load i32, ptr %ptr.gep, !invariant.load !{}
32 call void @use(i32 %val)
36 define void @f_1(ptr align 4 dereferenceable_or_null(1024) %ptr) nofree nosync {
39 ; CHECK-NEXT: [[PTR_GEP:%.*]] = getelementptr i8, ptr [[PTR:%.*]], i32 32
40 ; CHECK-NEXT: [[PTR_IS_NULL:%.*]] = icmp eq ptr [[PTR]], null
41 ; CHECK-NEXT: br i1 [[PTR_IS_NULL]], label [[LEAVE:%.*]], label [[LOOP_PREHEADER:%.*]]
42 ; CHECK: loop.preheader:
43 ; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[PTR_GEP]], align 4
44 ; CHECK-NEXT: br label [[LOOP:%.*]]
46 ; CHECK-NEXT: call void @use(i32 0)
47 ; CHECK-NEXT: call void @use(i32 [[VAL]])
48 ; CHECK-NEXT: br label [[LOOP]]
50 ; CHECK-NEXT: ret void
53 %ptr.gep = getelementptr i8, ptr %ptr, i32 32
54 %ptr_is_null = icmp eq ptr %ptr, null
55 br i1 %ptr_is_null, label %leave, label %loop
60 %val = load i32, ptr %ptr.gep, !invariant.load !{}
61 call void @use(i32 %val)
68 define void @f_2(ptr align 4 dereferenceable_or_null(1024) %ptr) {
71 ; CHECK-NEXT: [[PTR_GEP:%.*]] = getelementptr i8, ptr [[PTR:%.*]], i32 30
72 ; CHECK-NEXT: [[PTR_IS_NULL:%.*]] = icmp eq ptr [[PTR]], null
73 ; CHECK-NEXT: br i1 [[PTR_IS_NULL]], label [[LEAVE:%.*]], label [[LOOP_PREHEADER:%.*]]
74 ; CHECK: loop.preheader:
75 ; CHECK-NEXT: br label [[LOOP:%.*]]
77 ; CHECK-NEXT: call void @use(i32 0)
78 ; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[PTR_GEP]], align 4, !invariant.load !0
79 ; CHECK-NEXT: call void @use(i32 [[VAL]])
80 ; CHECK-NEXT: br label [[LOOP]]
82 ; CHECK-NEXT: ret void
86 ;; Can't hoist, since the alignment does not work out -- (<4 byte
87 ;; aligned> + 30) is not necessarily 4 byte aligned.
89 %ptr.gep = getelementptr i8, ptr %ptr, i32 30
90 %ptr_is_null = icmp eq ptr %ptr, null
91 br i1 %ptr_is_null, label %leave, label %loop
95 %val = load i32, ptr %ptr.gep, !invariant.load !{}
96 call void @use(i32 %val)
103 define void @checkLaunder(ptr align 4 dereferenceable(1024) %p) nofree nosync {
104 ; CHECK-LABEL: @checkLaunder(
106 ; CHECK-NEXT: [[L:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[P:%.*]])
107 ; CHECK-NEXT: [[VAL:%.*]] = load i8, ptr [[L]], align 1
108 ; CHECK-NEXT: br label [[LOOP:%.*]]
110 ; CHECK-NEXT: call void @use(i32 0)
111 ; CHECK-NEXT: call void @use8(i8 [[VAL]])
112 ; CHECK-NEXT: br label [[LOOP]]
116 %l = call ptr @llvm.launder.invariant.group.p0(ptr %p)
120 call void @use(i32 0)
121 %val = load i8, ptr %l, !invariant.load !{}
122 call void @use8(i8 %val)
126 declare ptr @llvm.launder.invariant.group.p0(ptr)
128 declare void @use8(i8)