1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -passes=licm < %s | FileCheck %s 3 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 8; to execute. 9 10declare void @use(i32) 11 12define void @f_0(ptr align 4 dereferenceable(1024) %ptr) nofree nosync { 13; CHECK-LABEL: @f_0( 14; CHECK-NEXT: entry: 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:%.*]] 18; CHECK: loop: 19; CHECK-NEXT: call void @use(i32 0) 20; CHECK-NEXT: call void @use(i32 [[VAL]]) 21; CHECK-NEXT: br label [[LOOP]] 22; 23 24 25entry: 26 %ptr.gep = getelementptr i8, ptr %ptr, i32 32 27 br label %loop 28 29loop: 30 call void @use(i32 0) 31 %val = load i32, ptr %ptr.gep, !invariant.load !{} 32 call void @use(i32 %val) 33 br label %loop 34} 35 36define void @f_1(ptr align 4 dereferenceable_or_null(1024) %ptr) nofree nosync { 37; CHECK-LABEL: @f_1( 38; CHECK-NEXT: entry: 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:%.*]] 45; CHECK: loop: 46; CHECK-NEXT: call void @use(i32 0) 47; CHECK-NEXT: call void @use(i32 [[VAL]]) 48; CHECK-NEXT: br label [[LOOP]] 49; CHECK: leave: 50; CHECK-NEXT: ret void 51; 52entry: 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 56 57 58loop: 59 call void @use(i32 0) 60 %val = load i32, ptr %ptr.gep, !invariant.load !{} 61 call void @use(i32 %val) 62 br label %loop 63 64leave: 65 ret void 66} 67 68define void @f_2(ptr align 4 dereferenceable_or_null(1024) %ptr) { 69; CHECK-LABEL: @f_2( 70; CHECK-NEXT: entry: 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:%.*]] 76; CHECK: 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]] 81; CHECK: leave: 82; CHECK-NEXT: ret void 83; 84 85entry: 86 ;; Can't hoist, since the alignment does not work out -- (<4 byte 87 ;; aligned> + 30) is not necessarily 4 byte aligned. 88 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 92 93loop: 94 call void @use(i32 0) 95 %val = load i32, ptr %ptr.gep, !invariant.load !{} 96 call void @use(i32 %val) 97 br label %loop 98 99leave: 100 ret void 101} 102 103define void @checkLaunder(ptr align 4 dereferenceable(1024) %p) nofree nosync { 104; CHECK-LABEL: @checkLaunder( 105; CHECK-NEXT: entry: 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:%.*]] 109; CHECK: loop: 110; CHECK-NEXT: call void @use(i32 0) 111; CHECK-NEXT: call void @use8(i8 [[VAL]]) 112; CHECK-NEXT: br label [[LOOP]] 113; 114 115entry: 116 %l = call ptr @llvm.launder.invariant.group.p0(ptr %p) 117 br label %loop 118 119loop: 120 call void @use(i32 0) 121 %val = load i8, ptr %l, !invariant.load !{} 122 call void @use8(i8 %val) 123 br label %loop 124} 125 126declare ptr @llvm.launder.invariant.group.p0(ptr) 127 128declare void @use8(i8) 129