241 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt -S -passes=memcpyopt < %s -verify-memoryssa | FileCheck %s3 4define i8 @read_dest_between_call_and_memcpy() {5; CHECK-LABEL: @read_dest_between_call_and_memcpy(6; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 17; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 18; CHECK-NEXT: store i8 1, ptr [[DEST]], align 19; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr [[SRC]], i8 0, i64 16, i1 false)10; CHECK-NEXT: [[X:%.*]] = load i8, ptr [[DEST]], align 111; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr [[DEST]], i8 0, i64 16, i1 false)12; CHECK-NEXT: ret i8 [[X]]13;14 %dest = alloca [16 x i8]15 %src = alloca [16 x i8]16 store i8 1, ptr %dest17 call void @llvm.memset.p0.i64(ptr %src, i8 0, i64 16, i1 false)18 %x = load i8, ptr %dest19 call void @llvm.memcpy.p0.p0.i64(ptr %dest, ptr %src, i64 16, i1 false)20 ret i8 %x21}22 23define i8 @read_src_between_call_and_memcpy() {24; CHECK-LABEL: @read_src_between_call_and_memcpy(25; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 126; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 127; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr [[SRC]], i8 0, i64 16, i1 false)28; CHECK-NEXT: [[X:%.*]] = load i8, ptr [[SRC]], align 129; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr [[DEST]], i8 0, i64 16, i1 false)30; CHECK-NEXT: ret i8 [[X]]31;32 %dest = alloca [16 x i8]33 %src = alloca [16 x i8]34 call void @llvm.memset.p0.i64(ptr %src, i8 0, i64 16, i1 false)35 %x = load i8, ptr %src36 call void @llvm.memcpy.p0.p0.i64(ptr %dest, ptr %src, i64 16, i1 false)37 ret i8 %x38}39 40define void @write_dest_between_call_and_memcpy() {41; CHECK-LABEL: @write_dest_between_call_and_memcpy(42; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 143; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 144; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr [[SRC]], i8 0, i64 16, i1 false)45; CHECK-NEXT: store i8 1, ptr [[DEST]], align 146; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr [[DEST]], i8 0, i64 16, i1 false)47; CHECK-NEXT: ret void48;49 %dest = alloca [16 x i8]50 %src = alloca [16 x i8]51 call void @llvm.memset.p0.i64(ptr %src, i8 0, i64 16, i1 false)52 store i8 1, ptr %dest53 call void @llvm.memcpy.p0.p0.i64(ptr %dest, ptr %src, i64 16, i1 false)54 ret void55}56 57define void @write_src_between_call_and_memcpy() {58; CHECK-LABEL: @write_src_between_call_and_memcpy(59; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 160; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr [[SRC]], i8 0, i64 16, i1 false)61; CHECK-NEXT: store i8 1, ptr [[SRC]], align 162; CHECK-NEXT: ret void63;64 %dest = alloca [16 x i8]65 %src = alloca [16 x i8]66 call void @llvm.memset.p0.i64(ptr %src, i8 0, i64 16, i1 false)67 store i8 1, ptr %src68 call void @llvm.memcpy.p0.p0.i64(ptr %dest, ptr %src, i64 16, i1 false)69 ret void70}71 72define void @throw_between_call_and_mempy(ptr writable dereferenceable(16) %dest.i8) {73; CHECK-LABEL: @throw_between_call_and_mempy(74; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 175; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr [[SRC]], i8 0, i64 16, i1 false)76; CHECK-NEXT: call void @may_throw() #[[ATTR2:[0-9]+]]77; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr [[DEST_I8:%.*]], i8 0, i64 16, i1 false)78; CHECK-NEXT: ret void79;80 %src = alloca [16 x i8]81 call void @llvm.memset.p0.i64(ptr %src, i8 0, i64 16, i1 false)82 call void @may_throw() readnone83 call void @llvm.memcpy.p0.p0.i64(ptr %dest.i8, ptr %src, i64 16, i1 false)84 ret void85}86 87define void @dest_is_gep_nounwind_call() {88; CHECK-LABEL: @dest_is_gep_nounwind_call(89; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 190; CHECK-NEXT: [[SRC:%.*]] = alloca [8 x i8], align 191; CHECK-NEXT: [[DEST_I8:%.*]] = getelementptr [16 x i8], ptr [[DEST]], i64 0, i64 892; CHECK-NEXT: call void @accept_ptr(ptr [[DEST_I8]]) #[[ATTR3:[0-9]+]]93; CHECK-NEXT: ret void94;95 %dest = alloca [16 x i8]96 %src = alloca [8 x i8]97 %dest.i8 = getelementptr [16 x i8], ptr %dest, i64 0, i64 898 call void @accept_ptr(ptr %src) nounwind99 call void @llvm.memcpy.p0.p0.i64(ptr %dest.i8, ptr %src, i64 8, i1 false)100 ret void101}102 103define void @dest_is_gep_may_throw_call() {104; CHECK-LABEL: @dest_is_gep_may_throw_call(105; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1106; CHECK-NEXT: [[SRC:%.*]] = alloca [8 x i8], align 1107; CHECK-NEXT: [[DEST_I8:%.*]] = getelementptr [16 x i8], ptr [[DEST]], i64 0, i64 8108; CHECK-NEXT: call void @accept_ptr(ptr [[DEST_I8]])109; CHECK-NEXT: ret void110;111 %dest = alloca [16 x i8]112 %src = alloca [8 x i8]113 %dest.i8 = getelementptr [16 x i8], ptr %dest, i64 0, i64 8114 call void @accept_ptr(ptr %src)115 call void @llvm.memcpy.p0.p0.i64(ptr %dest.i8, ptr %src, i64 8, i1 false)116 ret void117}118 119define void @dest_is_gep_requires_movement() {120; CHECK-LABEL: @dest_is_gep_requires_movement(121; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1122; CHECK-NEXT: [[SRC:%.*]] = alloca [8 x i8], align 1123; CHECK-NEXT: [[DEST_I8:%.*]] = getelementptr [16 x i8], ptr [[DEST]], i64 0, i64 8124; CHECK-NEXT: call void @accept_ptr(ptr [[DEST_I8]]) #[[ATTR3]]125; CHECK-NEXT: ret void126;127 %dest = alloca [16 x i8]128 %src = alloca [8 x i8]129 call void @accept_ptr(ptr %src) nounwind130 %dest.i8 = getelementptr [16 x i8], ptr %dest, i64 0, i64 8131 call void @llvm.memcpy.p0.p0.i64(ptr %dest.i8, ptr %src, i64 8, i1 false)132 ret void133}134 135define void @capture_before_call_argmemonly() {136; CHECK-LABEL: @capture_before_call_argmemonly(137; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1138; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1139; CHECK-NEXT: call void @accept_ptr(ptr [[DEST]])140; CHECK-NEXT: call void @accept_ptr(ptr captures(none) [[DEST]]) #[[ATTR4:[0-9]+]]141; CHECK-NEXT: ret void142;143 %dest = alloca [16 x i8]144 %src = alloca [16 x i8]145 call void @accept_ptr(ptr %dest) ; capture146 call void @accept_ptr(ptr nocapture %src) argmemonly147 call void @llvm.memcpy.p0.p0.i64(ptr %dest, ptr %src, i64 16, i1 false)148 ret void149}150 151define void @capture_before_call_argmemonly_nounwind() {152; CHECK-LABEL: @capture_before_call_argmemonly_nounwind(153; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1154; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1155; CHECK-NEXT: call void @accept_ptr(ptr [[DEST]])156; CHECK-NEXT: call void @accept_ptr(ptr captures(none) [[DEST]]) #[[ATTR5:[0-9]+]]157; CHECK-NEXT: ret void158;159 %dest = alloca [16 x i8]160 %src = alloca [16 x i8]161 call void @accept_ptr(ptr %dest) ; capture162 ; NB: argmemonly currently implies willreturn.163 call void @accept_ptr(ptr nocapture %src) argmemonly nounwind164 call void @llvm.memcpy.p0.p0.i64(ptr %dest, ptr %src, i64 16, i1 false)165 ret void166}167 168define void @capture_before_call_argmemonly_nounwind_willreturn() {169; CHECK-LABEL: @capture_before_call_argmemonly_nounwind_willreturn(170; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1171; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1172; CHECK-NEXT: call void @accept_ptr(ptr [[DEST]])173; CHECK-NEXT: call void @accept_ptr(ptr captures(none) [[DEST]]) #[[ATTR6:[0-9]+]]174; CHECK-NEXT: ret void175;176 %dest = alloca [16 x i8]177 %src = alloca [16 x i8]178 call void @accept_ptr(ptr %dest) ; capture179 call void @accept_ptr(ptr nocapture %src) argmemonly nounwind willreturn180 call void @llvm.memcpy.p0.p0.i64(ptr %dest, ptr %src, i64 16, i1 false)181 ret void182}183 184; There is no path from the capture back to the memcpy.185; So we are allowed to perform the call slot optimization.186define void @capture_nopath_call(i1 %cond) {187; CHECK-LABEL: @capture_nopath_call(188; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1189; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1190; CHECK-NEXT: br i1 [[COND:%.*]], label [[CAPTURES:%.*]], label [[NOCAPTURES:%.*]]191; CHECK: captures:192; CHECK-NEXT: call void @accept_ptr(ptr [[DEST]])193; CHECK-NEXT: ret void194; CHECK: nocaptures:195; CHECK-NEXT: call void @accept_ptr(ptr [[DEST]]) #[[ATTR3]]196; CHECK-NEXT: ret void197;198 %dest = alloca [16 x i8]199 %src = alloca [16 x i8]200 br i1 %cond, label %captures, label %nocaptures201 202captures:203 call void @accept_ptr(ptr %dest) ; capture204 ret void205 206nocaptures:207 call void @accept_ptr(ptr %src) nounwind208 call void @llvm.memcpy.p0.p0.i64(ptr %dest, ptr %src, i64 16, i1 false)209 ret void210}211 212define void @source_alignment(ptr noalias writable dereferenceable(128) %dst) {213; CHECK-LABEL: @source_alignment(214; CHECK-NEXT: [[SRC:%.*]] = alloca [128 x i8], align 4215; CHECK-NEXT: call void @accept_ptr(ptr captures(none) [[DST:%.*]]) #[[ATTR3]]216; CHECK-NEXT: ret void217;218 %src = alloca [128 x i8], align 4219 call void @accept_ptr(ptr nocapture %src) nounwind220 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dst, ptr %src, i64 128, i1 false)221 ret void222}223 224define void @dest_not_writable(ptr noalias dereferenceable(128) %dst) {225; CHECK-LABEL: @dest_not_writable(226; CHECK-NEXT: [[SRC:%.*]] = alloca [128 x i8], align 4227; CHECK-NEXT: call void @accept_ptr(ptr captures(none) [[SRC]]) #[[ATTR3]]228; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DST:%.*]], ptr [[SRC]], i64 128, i1 false)229; CHECK-NEXT: ret void230;231 %src = alloca [128 x i8], align 4232 call void @accept_ptr(ptr nocapture %src) nounwind233 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dst, ptr %src, i64 128, i1 false)234 ret void235}236 237declare void @may_throw()238declare void @accept_ptr(ptr)239declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1)240declare void @llvm.memset.p0.i64(ptr, i8, i64, i1)241