1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -memcpyopt < %s -enable-memcpyopt-memoryssa=0 | FileCheck %s --check-prefixes=CHECK,NO_MSSA 3; RUN: opt -S -memcpyopt < %s -enable-memcpyopt-memoryssa=1 -verify-memoryssa | FileCheck %s --check-prefixes=CHECK,MSSA 4 5define i8 @read_dest_between_call_and_memcpy() { 6; CHECK-LABEL: @read_dest_between_call_and_memcpy( 7; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1 8; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1 9; CHECK-NEXT: [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8* 10; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8* 11; CHECK-NEXT: store i8 1, i8* [[DEST_I8]], align 1 12; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[SRC_I8]], i8 0, i64 16, i1 false) 13; CHECK-NEXT: [[X:%.*]] = load i8, i8* [[DEST_I8]], align 1 14; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[DEST_I8]], i8 0, i64 16, i1 false) 15; CHECK-NEXT: ret i8 [[X]] 16; 17 %dest = alloca [16 x i8] 18 %src = alloca [16 x i8] 19 %dest.i8 = bitcast [16 x i8]* %dest to i8* 20 %src.i8 = bitcast [16 x i8]* %src to i8* 21 store i8 1, i8* %dest.i8 22 call void @llvm.memset.p0i8.i64(i8* %src.i8, i8 0, i64 16, i1 false) 23 %x = load i8, i8* %dest.i8 24 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false) 25 ret i8 %x 26} 27 28define i8 @read_src_between_call_and_memcpy() { 29; NO_MSSA-LABEL: @read_src_between_call_and_memcpy( 30; NO_MSSA-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1 31; NO_MSSA-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1 32; NO_MSSA-NEXT: [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8* 33; NO_MSSA-NEXT: [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8* 34; NO_MSSA-NEXT: call void @llvm.memset.p0i8.i64(i8* [[SRC_I8]], i8 0, i64 16, i1 false) 35; NO_MSSA-NEXT: [[X:%.*]] = load i8, i8* [[SRC_I8]], align 1 36; NO_MSSA-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DEST_I8]], i8* [[SRC_I8]], i64 16, i1 false) 37; NO_MSSA-NEXT: ret i8 [[X]] 38; 39; MSSA-LABEL: @read_src_between_call_and_memcpy( 40; MSSA-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1 41; MSSA-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1 42; MSSA-NEXT: [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8* 43; MSSA-NEXT: [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8* 44; MSSA-NEXT: call void @llvm.memset.p0i8.i64(i8* [[SRC_I8]], i8 0, i64 16, i1 false) 45; MSSA-NEXT: [[X:%.*]] = load i8, i8* [[SRC_I8]], align 1 46; MSSA-NEXT: call void @llvm.memset.p0i8.i64(i8* [[DEST_I8]], i8 0, i64 16, i1 false) 47; MSSA-NEXT: ret i8 [[X]] 48; 49 %dest = alloca [16 x i8] 50 %src = alloca [16 x i8] 51 %dest.i8 = bitcast [16 x i8]* %dest to i8* 52 %src.i8 = bitcast [16 x i8]* %src to i8* 53 call void @llvm.memset.p0i8.i64(i8* %src.i8, i8 0, i64 16, i1 false) 54 %x = load i8, i8* %src.i8 55 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false) 56 ret i8 %x 57} 58 59define void @write_dest_between_call_and_memcpy() { 60; CHECK-LABEL: @write_dest_between_call_and_memcpy( 61; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1 62; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1 63; CHECK-NEXT: [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8* 64; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8* 65; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[SRC_I8]], i8 0, i64 16, i1 false) 66; CHECK-NEXT: store i8 1, i8* [[DEST_I8]], align 1 67; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[DEST_I8]], i8 0, i64 16, i1 false) 68; CHECK-NEXT: ret void 69; 70 %dest = alloca [16 x i8] 71 %src = alloca [16 x i8] 72 %dest.i8 = bitcast [16 x i8]* %dest to i8* 73 %src.i8 = bitcast [16 x i8]* %src to i8* 74 call void @llvm.memset.p0i8.i64(i8* %src.i8, i8 0, i64 16, i1 false) 75 store i8 1, i8* %dest.i8 76 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false) 77 ret void 78} 79 80define void @write_src_between_call_and_memcpy() { 81; CHECK-LABEL: @write_src_between_call_and_memcpy( 82; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1 83; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1 84; CHECK-NEXT: [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8* 85; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8* 86; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[SRC_I8]], i8 0, i64 16, i1 false) 87; CHECK-NEXT: store i8 1, i8* [[SRC_I8]], align 1 88; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DEST_I8]], i8* [[SRC_I8]], i64 16, i1 false) 89; CHECK-NEXT: ret void 90; 91 %dest = alloca [16 x i8] 92 %src = alloca [16 x i8] 93 %dest.i8 = bitcast [16 x i8]* %dest to i8* 94 %src.i8 = bitcast [16 x i8]* %src to i8* 95 call void @llvm.memset.p0i8.i64(i8* %src.i8, i8 0, i64 16, i1 false) 96 store i8 1, i8* %src.i8 97 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false) 98 ret void 99} 100 101define void @throw_between_call_and_mempy(i8* dereferenceable(16) %dest.i8) { 102; CHECK-LABEL: @throw_between_call_and_mempy( 103; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1 104; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8* 105; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[SRC_I8]], i8 0, i64 16, i1 false) 106; CHECK-NEXT: call void @may_throw() [[ATTR2:#.*]] 107; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[DEST_I8:%.*]], i8 0, i64 16, i1 false) 108; CHECK-NEXT: ret void 109; 110 %src = alloca [16 x i8] 111 %src.i8 = bitcast [16 x i8]* %src to i8* 112 call void @llvm.memset.p0i8.i64(i8* %src.i8, i8 0, i64 16, i1 false) 113 call void @may_throw() readnone 114 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false) 115 ret void 116} 117 118define void @dest_is_gep_nounwind_call() { 119; CHECK-LABEL: @dest_is_gep_nounwind_call( 120; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1 121; CHECK-NEXT: [[SRC:%.*]] = alloca [8 x i8], align 1 122; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [8 x i8]* [[SRC]] to i8* 123; CHECK-NEXT: [[DEST_I8:%.*]] = getelementptr [16 x i8], [16 x i8]* [[DEST]], i64 0, i64 8 124; CHECK-NEXT: [[DEST_I81:%.*]] = bitcast i8* [[DEST_I8]] to [8 x i8]* 125; CHECK-NEXT: [[DEST_I812:%.*]] = bitcast [8 x i8]* [[DEST_I81]] to i8* 126; CHECK-NEXT: call void @accept_ptr(i8* [[DEST_I812]]) [[ATTR3:#.*]] 127; CHECK-NEXT: ret void 128; 129 %dest = alloca [16 x i8] 130 %src = alloca [8 x i8] 131 %src.i8 = bitcast [8 x i8]* %src to i8* 132 %dest.i8 = getelementptr [16 x i8], [16 x i8]* %dest, i64 0, i64 8 133 call void @accept_ptr(i8* %src.i8) nounwind 134 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 8, i1 false) 135 ret void 136} 137 138define void @dest_is_gep_may_throw_call() { 139; CHECK-LABEL: @dest_is_gep_may_throw_call( 140; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1 141; CHECK-NEXT: [[SRC:%.*]] = alloca [8 x i8], align 1 142; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [8 x i8]* [[SRC]] to i8* 143; CHECK-NEXT: [[DEST_I8:%.*]] = getelementptr [16 x i8], [16 x i8]* [[DEST]], i64 0, i64 8 144; CHECK-NEXT: [[DEST_I81:%.*]] = bitcast i8* [[DEST_I8]] to [8 x i8]* 145; CHECK-NEXT: [[DEST_I812:%.*]] = bitcast [8 x i8]* [[DEST_I81]] to i8* 146; CHECK-NEXT: call void @accept_ptr(i8* [[DEST_I812]]) 147; CHECK-NEXT: ret void 148; 149 %dest = alloca [16 x i8] 150 %src = alloca [8 x i8] 151 %src.i8 = bitcast [8 x i8]* %src to i8* 152 %dest.i8 = getelementptr [16 x i8], [16 x i8]* %dest, i64 0, i64 8 153 call void @accept_ptr(i8* %src.i8) 154 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 8, i1 false) 155 ret void 156} 157 158define void @dest_is_gep_requires_movement() { 159; CHECK-LABEL: @dest_is_gep_requires_movement( 160; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1 161; CHECK-NEXT: [[SRC:%.*]] = alloca [8 x i8], align 1 162; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [8 x i8]* [[SRC]] to i8* 163; CHECK-NEXT: [[DEST_I8:%.*]] = getelementptr [16 x i8], [16 x i8]* [[DEST]], i64 0, i64 8 164; CHECK-NEXT: [[DEST_I81:%.*]] = bitcast i8* [[DEST_I8]] to [8 x i8]* 165; CHECK-NEXT: [[DEST_I812:%.*]] = bitcast [8 x i8]* [[DEST_I81]] to i8* 166; CHECK-NEXT: call void @accept_ptr(i8* [[DEST_I812]]) [[ATTR3]] 167; CHECK-NEXT: ret void 168; 169 %dest = alloca [16 x i8] 170 %src = alloca [8 x i8] 171 %src.i8 = bitcast [8 x i8]* %src to i8* 172 call void @accept_ptr(i8* %src.i8) nounwind 173 %dest.i8 = getelementptr [16 x i8], [16 x i8]* %dest, i64 0, i64 8 174 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 8, i1 false) 175 ret void 176} 177 178define void @capture_before_call_argmemonly() { 179; CHECK-LABEL: @capture_before_call_argmemonly( 180; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1 181; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1 182; CHECK-NEXT: [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8* 183; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8* 184; CHECK-NEXT: call void @accept_ptr(i8* [[DEST_I8]]) 185; CHECK-NEXT: [[DEST1:%.*]] = bitcast [16 x i8]* [[DEST]] to i8* 186; CHECK-NEXT: call void @accept_ptr(i8* [[DEST1]]) [[ATTR4:#.*]] 187; CHECK-NEXT: ret void 188; 189 %dest = alloca [16 x i8] 190 %src = alloca [16 x i8] 191 %dest.i8 = bitcast [16 x i8]* %dest to i8* 192 %src.i8 = bitcast [16 x i8]* %src to i8* 193 call void @accept_ptr(i8* %dest.i8) ; capture 194 call void @accept_ptr(i8* %src.i8) argmemonly 195 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false) 196 ret void 197} 198 199define void @capture_before_call_argmemonly_nounwind() { 200; CHECK-LABEL: @capture_before_call_argmemonly_nounwind( 201; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1 202; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1 203; CHECK-NEXT: [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8* 204; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8* 205; CHECK-NEXT: call void @accept_ptr(i8* [[DEST_I8]]) 206; CHECK-NEXT: [[DEST1:%.*]] = bitcast [16 x i8]* [[DEST]] to i8* 207; CHECK-NEXT: call void @accept_ptr(i8* [[DEST1]]) [[ATTR5:#.*]] 208; CHECK-NEXT: ret void 209; 210 %dest = alloca [16 x i8] 211 %src = alloca [16 x i8] 212 %dest.i8 = bitcast [16 x i8]* %dest to i8* 213 %src.i8 = bitcast [16 x i8]* %src to i8* 214 call void @accept_ptr(i8* %dest.i8) ; capture 215 ; NB: argmemonly currently implies willreturn. 216 call void @accept_ptr(i8* %src.i8) argmemonly nounwind 217 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false) 218 ret void 219} 220 221define void @capture_before_call_argmemonly_nounwind_willreturn() { 222; CHECK-LABEL: @capture_before_call_argmemonly_nounwind_willreturn( 223; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1 224; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1 225; CHECK-NEXT: [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8* 226; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8* 227; CHECK-NEXT: call void @accept_ptr(i8* [[DEST_I8]]) 228; CHECK-NEXT: [[DEST1:%.*]] = bitcast [16 x i8]* [[DEST]] to i8* 229; CHECK-NEXT: call void @accept_ptr(i8* [[DEST1]]) [[ATTR0:#.*]] 230; CHECK-NEXT: ret void 231; 232 %dest = alloca [16 x i8] 233 %src = alloca [16 x i8] 234 %dest.i8 = bitcast [16 x i8]* %dest to i8* 235 %src.i8 = bitcast [16 x i8]* %src to i8* 236 call void @accept_ptr(i8* %dest.i8) ; capture 237 call void @accept_ptr(i8* %src.i8) argmemonly nounwind willreturn 238 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false) 239 ret void 240} 241 242declare void @may_throw() 243declare void @accept_ptr(i8*) 244declare void @llvm.memcpy.p0i8.p0i8.i64(i8*, i8*, i64, i1) 245declare void @llvm.memset.p0i8.i64(i8*, i8, i64, i1) 246