1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature 2; RUN: opt < %s -passes='require<globals-aa>,memcpyopt' -S -verify-memoryssa | FileCheck %s 3 4target datalayout = "e" 5 6declare void @foo(ptr) 7declare void @llvm.memcpy.p0.p0.i32(ptr nocapture, ptr nocapture, i32, i1) nounwind 8declare void @llvm.lifetime.start.p0(i64, ptr nocapture) 9declare void @llvm.lifetime.end.p0(i64, ptr nocapture) 10 11; Check that the transformation isn't applied if the called function can 12; capture the pointer argument (i.e. the nocapture attribute isn't present) 13define void @test() { 14; CHECK-LABEL: define {{[^@]+}}@test() { 15; CHECK-NEXT: [[PTR1:%.*]] = alloca i8, align 1 16; CHECK-NEXT: [[PTR2:%.*]] = alloca i8, align 1 17; CHECK-NEXT: call void @foo(ptr [[PTR2]]) 18; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 1, i1 false) 19; CHECK-NEXT: call void @foo(ptr [[PTR1]]) 20; CHECK-NEXT: ret void 21; 22 %ptr1 = alloca i8 23 %ptr2 = alloca i8 24 call void @foo(ptr %ptr2) 25 call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false) 26 call void @foo(ptr %ptr1) 27 ret void 28} 29 30; Same as previous test, but with a bitcasted argument. 31define void @test_bitcast() { 32; CHECK-LABEL: define {{[^@]+}}@test_bitcast() { 33; CHECK-NEXT: [[PTR1:%.*]] = alloca [2 x i8], align 1 34; CHECK-NEXT: [[PTR2:%.*]] = alloca [2 x i8], align 1 35; CHECK-NEXT: call void @foo(ptr [[PTR2]]) 36; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 2, i1 false) 37; CHECK-NEXT: call void @foo(ptr [[PTR1]]) 38; CHECK-NEXT: ret void 39; 40 %ptr1 = alloca [2 x i8] 41 %ptr2 = alloca [2 x i8] 42 call void @foo(ptr %ptr2) 43 call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 2, i1 false) 44 call void @foo(ptr %ptr1) 45 ret void 46} 47 48; Lifetime of %ptr2 ends before the potential use of the capture in the second 49; call. 50define void @test_lifetime_end() { 51; CHECK-LABEL: define {{[^@]+}}@test_lifetime_end() { 52; CHECK-NEXT: [[PTR1:%.*]] = alloca i8, align 1 53; CHECK-NEXT: [[PTR2:%.*]] = alloca i8, align 1 54; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 1, ptr [[PTR2]]) 55; CHECK-NEXT: call void @foo(ptr [[PTR1]]) 56; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 1, ptr [[PTR2]]) 57; CHECK-NEXT: call void @foo(ptr [[PTR1]]) 58; CHECK-NEXT: ret void 59; 60 %ptr1 = alloca i8 61 %ptr2 = alloca i8 62 call void @llvm.lifetime.start.p0(i64 1, ptr %ptr2) 63 call void @foo(ptr %ptr2) 64 call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false) 65 call void @llvm.lifetime.end.p0(i64 1, ptr %ptr2) 66 call void @foo(ptr %ptr1) 67 ret void 68} 69 70; Lifetime of %ptr2 does not end, because of size mismatch. 71define void @test_lifetime_not_end() { 72; CHECK-LABEL: define {{[^@]+}}@test_lifetime_not_end() { 73; CHECK-NEXT: [[PTR1:%.*]] = alloca i8, align 1 74; CHECK-NEXT: [[PTR2:%.*]] = alloca i8, align 1 75; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 1, ptr [[PTR2]]) 76; CHECK-NEXT: call void @foo(ptr [[PTR2]]) 77; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 1, i1 false) 78; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 0, ptr [[PTR2]]) 79; CHECK-NEXT: call void @foo(ptr [[PTR1]]) 80; CHECK-NEXT: ret void 81; 82 %ptr1 = alloca i8 83 %ptr2 = alloca i8 84 call void @llvm.lifetime.start.p0(i64 1, ptr %ptr2) 85 call void @foo(ptr %ptr2) 86 call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false) 87 call void @llvm.lifetime.end.p0(i64 0, ptr %ptr2) 88 call void @foo(ptr %ptr1) 89 ret void 90} 91 92; Lifetime of %ptr2 ends before any potential use of the capture because we 93; return from the function. 94define void @test_function_end() { 95; CHECK-LABEL: define {{[^@]+}}@test_function_end() { 96; CHECK-NEXT: [[PTR1:%.*]] = alloca i8, align 1 97; CHECK-NEXT: [[PTR2:%.*]] = alloca i8, align 1 98; CHECK-NEXT: call void @foo(ptr [[PTR1]]) 99; CHECK-NEXT: ret void 100; 101 %ptr1 = alloca i8 102 %ptr2 = alloca i8 103 call void @foo(ptr %ptr2) 104 call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false) 105 ret void 106} 107 108; A potential use of the capture occurs in a later block, can't be optimized. 109define void @test_terminator() { 110; CHECK-LABEL: define {{[^@]+}}@test_terminator() { 111; CHECK-NEXT: [[PTR1:%.*]] = alloca i8, align 1 112; CHECK-NEXT: [[PTR2:%.*]] = alloca i8, align 1 113; CHECK-NEXT: call void @foo(ptr [[PTR2]]) 114; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 1, i1 false) 115; CHECK-NEXT: br label [[NEXT:%.*]] 116; CHECK: next: 117; CHECK-NEXT: call void @foo(ptr [[PTR1]]) 118; CHECK-NEXT: ret void 119; 120 %ptr1 = alloca i8 121 %ptr2 = alloca i8 122 call void @foo(ptr %ptr2) 123 call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false) 124 br label %next 125 126next: 127 call void @foo(ptr %ptr1) 128 ret void 129} 130 131; This case can be optimized, but would require a scan across multiple blocks 132; and is currently not performed. 133define void @test_terminator2() { 134; CHECK-LABEL: define {{[^@]+}}@test_terminator2() { 135; CHECK-NEXT: [[PTR1:%.*]] = alloca i8, align 1 136; CHECK-NEXT: [[PTR2:%.*]] = alloca i8, align 1 137; CHECK-NEXT: call void @foo(ptr [[PTR2]]) 138; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 1, i1 false) 139; CHECK-NEXT: br label [[NEXT:%.*]] 140; CHECK: next: 141; CHECK-NEXT: ret void 142; 143 %ptr1 = alloca i8 144 %ptr2 = alloca i8 145 call void @foo(ptr %ptr2) 146 call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false) 147 br label %next 148 149next: 150 ret void 151} 152 153declare void @capture(ptr) 154 155; This case should not be optimized, because dest is captured before the call. 156define void @test_dest_captured_before_alloca() { 157; CHECK-LABEL: define {{[^@]+}}@test_dest_captured_before_alloca() { 158; CHECK-NEXT: [[PTR1:%.*]] = alloca i8, align 1 159; CHECK-NEXT: [[PTR2:%.*]] = alloca i8, align 1 160; CHECK-NEXT: call void @capture(ptr [[PTR1]]) 161; CHECK-NEXT: call void @foo(ptr [[PTR2]]) #[[ATTR2:[0-9]+]] 162; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 1, i1 false) 163; CHECK-NEXT: ret void 164; 165 %ptr1 = alloca i8 166 %ptr2 = alloca i8 167 call void @capture(ptr %ptr1) 168 call void @foo(ptr %ptr2) argmemonly 169 call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false) 170 ret void 171} 172 173 174@g = internal global i8 0 175 176; This case should not be optimized, because @g is captured before the call 177; (being a global) and @icmp_g might depend on its identity. 178define void @test_dest_captured_before_global() { 179; CHECK-LABEL: define {{[^@]+}}@test_dest_captured_before_global() { 180; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 181; CHECK-NEXT: call void @icmp_g(ptr [[PTR]]) 182; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr @g, ptr [[PTR]], i32 1, i1 false) 183; CHECK-NEXT: ret void 184; 185 %ptr = alloca i8 186 call void @icmp_g(ptr %ptr) 187 call void @llvm.memcpy.p0.p0.i32(ptr @g, ptr %ptr, i32 1, i1 false) 188 ret void 189} 190 191define void @icmp_g(ptr %p) { 192; CHECK-LABEL: define {{[^@]+}}@icmp_g 193; CHECK-SAME: (ptr [[P:%.*]]) { 194; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P]], @g 195; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]] 196; CHECK: if: 197; CHECK-NEXT: store i8 1, ptr [[P]], align 1 198; CHECK-NEXT: ret void 199; CHECK: else: 200; CHECK-NEXT: store i8 2, ptr [[P]], align 1 201; CHECK-NEXT: ret void 202; 203 %c = icmp eq ptr %p, @g 204 br i1 %c, label %if, label %else 205 206if: 207 store i8 1, ptr %p 208 ret void 209 210else: 211 store i8 2, ptr %p 212 ret void 213} 214